xref: /aosp_15_r20/external/deqp/external/openglcts/modules/common/glcShaderLibrary.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2016 Google Inc.
6  * Copyright (c) 2016 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */ /*!
21  * \file
22  * \brief Compiler test case.
23  */ /*-------------------------------------------------------------------*/
24 
25 #include "glcShaderLibrary.hpp"
26 #include "glcShaderLibraryCase.hpp"
27 #include "gluShaderUtil.hpp"
28 #include "tcuResource.hpp"
29 
30 #include "deInt32.h"
31 
32 #include <fstream>
33 #include <sstream>
34 #include <string>
35 #include <vector>
36 
37 #include <stdarg.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 using std::ostringstream;
42 using std::string;
43 using std::vector;
44 
45 using namespace glu;
46 
47 #if 0
48 #define PARSE_DBG(X) printf X
49 #else
50 #define PARSE_DBG(X) DE_NULL_STATEMENT
51 #endif
52 
53 namespace deqp
54 {
55 namespace sl
56 {
57 
58 static const glu::GLSLVersion DEFAULT_GLSL_VERSION = glu::GLSL_VERSION_100_ES;
59 
isWhitespace(char c)60 DE_INLINE bool isWhitespace(char c)
61 {
62     return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n');
63 }
64 
isEOL(char c)65 DE_INLINE bool isEOL(char c)
66 {
67     return (c == '\r') || (c == '\n');
68 }
69 
isNumeric(char c)70 DE_INLINE bool isNumeric(char c)
71 {
72     return deInRange32(c, '0', '9');
73 }
74 
isAlpha(char c)75 DE_INLINE bool isAlpha(char c)
76 {
77     return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z');
78 }
79 
isCaseNameChar(char c)80 DE_INLINE bool isCaseNameChar(char c)
81 {
82     return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z') || deInRange32(c, '0', '9') || (c == '_') ||
83            (c == '-') || (c == '.');
84 }
85 
86 // \todo [2011-02-11 pyry] Should not depend on Context or TestContext!
87 class ShaderParser
88 {
89 public:
90     ShaderParser(tcu::TestContext &testCtx, RenderContext &renderCtx);
91     ~ShaderParser(void);
92 
93     vector<tcu::TestNode *> parse(const char *input);
94 
95 private:
96     enum Token
97     {
98         TOKEN_INVALID = 0,
99         TOKEN_EOF,
100         TOKEN_STRING,
101         TOKEN_SHADER_SOURCE,
102 
103         TOKEN_INT_LITERAL,
104         TOKEN_FLOAT_LITERAL,
105 
106         // identifiers
107         TOKEN_IDENTIFIER,
108         TOKEN_TRUE,
109         TOKEN_FALSE,
110         TOKEN_DESC,
111         TOKEN_EXPECT,
112         TOKEN_GROUP,
113         TOKEN_CASE,
114         TOKEN_END,
115         TOKEN_VALUES,
116         TOKEN_BOTH,
117         TOKEN_VERTEX,
118         TOKEN_FRAGMENT,
119         TOKEN_UNIFORM,
120         TOKEN_INPUT,
121         TOKEN_OUTPUT,
122         TOKEN_FLOAT,
123         TOKEN_FLOAT_VEC2,
124         TOKEN_FLOAT_VEC3,
125         TOKEN_FLOAT_VEC4,
126         TOKEN_FLOAT_MAT2,
127         TOKEN_FLOAT_MAT2X3,
128         TOKEN_FLOAT_MAT2X4,
129         TOKEN_FLOAT_MAT3X2,
130         TOKEN_FLOAT_MAT3,
131         TOKEN_FLOAT_MAT3X4,
132         TOKEN_FLOAT_MAT4X2,
133         TOKEN_FLOAT_MAT4X3,
134         TOKEN_FLOAT_MAT4,
135         TOKEN_INT,
136         TOKEN_INT_VEC2,
137         TOKEN_INT_VEC3,
138         TOKEN_INT_VEC4,
139         TOKEN_UINT,
140         TOKEN_UINT_VEC2,
141         TOKEN_UINT_VEC3,
142         TOKEN_UINT_VEC4,
143         TOKEN_BOOL,
144         TOKEN_BOOL_VEC2,
145         TOKEN_BOOL_VEC3,
146         TOKEN_BOOL_VEC4,
147         TOKEN_VERSION,
148 
149         // symbols
150         TOKEN_ASSIGN,
151         TOKEN_PLUS,
152         TOKEN_MINUS,
153         TOKEN_COMMA,
154         TOKEN_VERTICAL_BAR,
155         TOKEN_SEMI_COLON,
156         TOKEN_LEFT_PAREN,
157         TOKEN_RIGHT_PAREN,
158         TOKEN_LEFT_BRACKET,
159         TOKEN_RIGHT_BRACKET,
160         TOKEN_LEFT_BRACE,
161         TOKEN_RIGHT_BRACE,
162 
163         TOKEN_LAST
164     };
165 
166     void parseError(const std::string &errorStr);
167     float parseFloatLiteral(const char *str);
168     long long int parseIntLiteral(const char *str);
169     string parseStringLiteral(const char *str);
170     string parseShaderSource(const char *str);
171     void advanceToken(void);
172     void advanceToken(Token assumed);
173     void assumeToken(Token token);
174     DataType mapDataTypeToken(Token token);
175     const char *getTokenName(Token token);
176 
177     void parseValueElement(DataType dataType, ShaderCase::Value &result);
178     void parseValue(ShaderCase::ValueBlock &valueBlock);
179     void parseValueBlock(ShaderCase::ValueBlock &valueBlock);
180     void parseShaderCase(vector<tcu::TestNode *> &shaderNodeList);
181     void parseShaderGroup(vector<tcu::TestNode *> &shaderNodeList);
182 
183     // Member variables.
184     tcu::TestContext &m_testCtx;
185     RenderContext &m_renderCtx;
186     std::string m_input;
187     const char *m_curPtr;
188     Token m_curToken;
189     std::string m_curTokenStr;
190 };
191 
ShaderParser(tcu::TestContext & testCtx,RenderContext & renderCtx)192 ShaderParser::ShaderParser(tcu::TestContext &testCtx, RenderContext &renderCtx)
193     : m_testCtx(testCtx)
194     , m_renderCtx(renderCtx)
195     , m_curPtr(DE_NULL)
196     , m_curToken(TOKEN_LAST)
197 {
198 }
199 
~ShaderParser(void)200 ShaderParser::~ShaderParser(void)
201 {
202     // nada
203 }
204 
parseError(const std::string & errorStr)205 void ShaderParser::parseError(const std::string &errorStr)
206 {
207     string atStr = string(m_curPtr, 80);
208     throw tcu::InternalError((string("Parser error: ") + errorStr + " near '" + atStr + " ...'").c_str(), "", __FILE__,
209                              __LINE__);
210 }
211 
parseFloatLiteral(const char * str)212 float ShaderParser::parseFloatLiteral(const char *str)
213 {
214     return (float)atof(str);
215 }
216 
parseIntLiteral(const char * str)217 long long int ShaderParser::parseIntLiteral(const char *str)
218 {
219     return strtoll(str, NULL, 0);
220 }
221 
parseStringLiteral(const char * str)222 string ShaderParser::parseStringLiteral(const char *str)
223 {
224     const char *p = str;
225     char endChar  = *p++;
226     ostringstream o;
227 
228     while (*p != endChar && *p)
229     {
230         if (*p == '\\')
231         {
232             switch (p[1])
233             {
234             case 0:
235                 DE_ASSERT(false);
236                 break;
237             case 'n':
238                 o << '\n';
239                 break;
240             case 't':
241                 o << '\t';
242                 break;
243             default:
244                 o << p[1];
245                 break;
246             }
247 
248             p += 2;
249         }
250         else
251             o << *p++;
252     }
253 
254     return o.str();
255 }
256 
removeExtraIndentation(const string & source)257 static string removeExtraIndentation(const string &source)
258 {
259     // Detect indentation from first line.
260     int numIndentChars = 0;
261     for (int ndx = 0; ndx < (int)source.length() && isWhitespace(source[ndx]); ndx++)
262         numIndentChars += source[ndx] == '\t' ? 4 : 1;
263 
264     // Process all lines and remove preceding indentation.
265     ostringstream processed;
266     {
267         bool atLineStart       = true;
268         int indentCharsOmitted = 0;
269 
270         for (int pos = 0; pos < (int)source.length(); pos++)
271         {
272             char c = source[pos];
273 
274             if (atLineStart && indentCharsOmitted < numIndentChars && (c == ' ' || c == '\t'))
275             {
276                 indentCharsOmitted += c == '\t' ? 4 : 1;
277             }
278             else if (isEOL(c))
279             {
280                 if (source[pos] == '\r' && source[pos + 1] == '\n')
281                 {
282                     pos += 1;
283                     processed << '\n';
284                 }
285                 else
286                     processed << c;
287 
288                 atLineStart        = true;
289                 indentCharsOmitted = 0;
290             }
291             else
292             {
293                 processed << c;
294                 atLineStart = false;
295             }
296         }
297     }
298 
299     return processed.str();
300 }
301 
parseShaderSource(const char * str)302 string ShaderParser::parseShaderSource(const char *str)
303 {
304     const char *p = str + 2;
305     ostringstream o;
306 
307     // Eat first empty line from beginning.
308     while (*p == ' ')
309         p++;
310     while (isEOL(*p))
311         p++;
312 
313     while ((p[0] != '"') || (p[1] != '"'))
314     {
315         if (*p == '\\')
316         {
317             switch (p[1])
318             {
319             case 0:
320                 DE_ASSERT(false);
321                 break;
322             case 'n':
323                 o << '\n';
324                 break;
325             case 't':
326                 o << '\t';
327                 break;
328             default:
329                 o << p[1];
330                 break;
331             }
332 
333             p += 2;
334         }
335         else
336             o << *p++;
337     }
338 
339     return removeExtraIndentation(o.str());
340 }
341 
advanceToken(void)342 void ShaderParser::advanceToken(void)
343 {
344     // Skip old token.
345     m_curPtr += m_curTokenStr.length();
346 
347     // Reset token (for safety).
348     m_curToken    = TOKEN_INVALID;
349     m_curTokenStr = "";
350 
351     // Eat whitespace & comments while they last.
352     for (;;)
353     {
354         while (isWhitespace(*m_curPtr))
355             m_curPtr++;
356 
357         // Check for EOL comment.
358         if (*m_curPtr == '#')
359         {
360             while (*m_curPtr && !isEOL(*m_curPtr))
361                 m_curPtr++;
362         }
363         else
364             break;
365     }
366 
367     if (!*m_curPtr)
368     {
369         m_curToken    = TOKEN_EOF;
370         m_curTokenStr = "<EOF>";
371     }
372     else if (isAlpha(*m_curPtr))
373     {
374         struct Named
375         {
376             const char *str;
377             Token token;
378         };
379 
380         static const Named s_named[] = {{"true", TOKEN_TRUE},
381                                         {"false", TOKEN_FALSE},
382                                         {"desc", TOKEN_DESC},
383                                         {"expect", TOKEN_EXPECT},
384                                         {"group", TOKEN_GROUP},
385                                         {"case", TOKEN_CASE},
386                                         {"end", TOKEN_END},
387                                         {"values", TOKEN_VALUES},
388                                         {"both", TOKEN_BOTH},
389                                         {"vertex", TOKEN_VERTEX},
390                                         {"fragment", TOKEN_FRAGMENT},
391                                         {"uniform", TOKEN_UNIFORM},
392                                         {"input", TOKEN_INPUT},
393                                         {"output", TOKEN_OUTPUT},
394                                         {"float", TOKEN_FLOAT},
395                                         {"vec2", TOKEN_FLOAT_VEC2},
396                                         {"vec3", TOKEN_FLOAT_VEC3},
397                                         {"vec4", TOKEN_FLOAT_VEC4},
398                                         {"mat2", TOKEN_FLOAT_MAT2},
399                                         {"mat2x3", TOKEN_FLOAT_MAT2X3},
400                                         {"mat2x4", TOKEN_FLOAT_MAT2X4},
401                                         {"mat3x2", TOKEN_FLOAT_MAT3X2},
402                                         {"mat3", TOKEN_FLOAT_MAT3},
403                                         {"mat3x4", TOKEN_FLOAT_MAT3X4},
404                                         {"mat4x2", TOKEN_FLOAT_MAT4X2},
405                                         {"mat4x3", TOKEN_FLOAT_MAT4X3},
406                                         {"mat4", TOKEN_FLOAT_MAT4},
407                                         {"int", TOKEN_INT},
408                                         {"ivec2", TOKEN_INT_VEC2},
409                                         {"ivec3", TOKEN_INT_VEC3},
410                                         {"ivec4", TOKEN_INT_VEC4},
411                                         {"uint", TOKEN_UINT},
412                                         {"uvec2", TOKEN_UINT_VEC2},
413                                         {"uvec3", TOKEN_UINT_VEC3},
414                                         {"uvec4", TOKEN_UINT_VEC4},
415                                         {"bool", TOKEN_BOOL},
416                                         {"bvec2", TOKEN_BOOL_VEC2},
417                                         {"bvec3", TOKEN_BOOL_VEC3},
418                                         {"bvec4", TOKEN_BOOL_VEC4},
419                                         {"version", TOKEN_VERSION}};
420 
421         const char *end = m_curPtr + 1;
422         while (isCaseNameChar(*end))
423             end++;
424         m_curTokenStr = string(m_curPtr, end - m_curPtr);
425 
426         m_curToken = TOKEN_IDENTIFIER;
427 
428         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_named); ndx++)
429         {
430             if (m_curTokenStr == s_named[ndx].str)
431             {
432                 m_curToken = s_named[ndx].token;
433                 break;
434             }
435         }
436     }
437     else if (isNumeric(*m_curPtr))
438     {
439         /* \todo [2010-03-31 petri] Hex? */
440         const char *p = m_curPtr;
441         while (isNumeric(*p))
442             p++;
443         if (*p == '.')
444         {
445             p++;
446             while (isNumeric(*p))
447                 p++;
448 
449             if (*p == 'e' || *p == 'E')
450             {
451                 p++;
452                 if (*p == '+' || *p == '-')
453                     p++;
454                 DE_ASSERT(isNumeric(*p));
455                 while (isNumeric(*p))
456                     p++;
457             }
458 
459             m_curToken    = TOKEN_FLOAT_LITERAL;
460             m_curTokenStr = string(m_curPtr, p - m_curPtr);
461         }
462         else
463         {
464             m_curToken    = TOKEN_INT_LITERAL;
465             m_curTokenStr = string(m_curPtr, p - m_curPtr);
466         }
467     }
468     else if (*m_curPtr == '"' && m_curPtr[1] == '"')
469     {
470         const char *p = m_curPtr + 2;
471 
472         while ((p[0] != '"') || (p[1] != '"'))
473         {
474             DE_ASSERT(*p);
475             if (*p == '\\')
476             {
477                 DE_ASSERT(p[1] != 0);
478                 p += 2;
479             }
480             else
481                 p++;
482         }
483         p += 2;
484 
485         m_curToken    = TOKEN_SHADER_SOURCE;
486         m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr));
487     }
488     else if (*m_curPtr == '"' || *m_curPtr == '\'')
489     {
490         char endChar  = *m_curPtr;
491         const char *p = m_curPtr + 1;
492 
493         while (*p != endChar)
494         {
495             DE_ASSERT(*p);
496             if (*p == '\\')
497             {
498                 DE_ASSERT(p[1] != 0);
499                 p += 2;
500             }
501             else
502                 p++;
503         }
504         p++;
505 
506         m_curToken    = TOKEN_STRING;
507         m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr));
508     }
509     else
510     {
511         struct SimpleToken
512         {
513             const char *str;
514             Token token;
515         };
516 
517         static const SimpleToken s_simple[] = {
518             {"=", TOKEN_ASSIGN},       {"+", TOKEN_PLUS},          {"-", TOKEN_MINUS},      {",", TOKEN_COMMA},
519             {"|", TOKEN_VERTICAL_BAR}, {";", TOKEN_SEMI_COLON},    {"(", TOKEN_LEFT_PAREN}, {")", TOKEN_RIGHT_PAREN},
520             {"[", TOKEN_LEFT_BRACKET}, {"]", TOKEN_RIGHT_BRACKET}, {"{", TOKEN_LEFT_BRACE}, {"}", TOKEN_RIGHT_BRACE}};
521 
522         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_simple); ndx++)
523         {
524             if (strncmp(s_simple[ndx].str, m_curPtr, strlen(s_simple[ndx].str)) == 0)
525             {
526                 m_curToken    = s_simple[ndx].token;
527                 m_curTokenStr = s_simple[ndx].str;
528                 return;
529             }
530         }
531 
532         // Otherwise invalid token.
533         m_curToken    = TOKEN_INVALID;
534         m_curTokenStr = *m_curPtr;
535     }
536 }
537 
advanceToken(Token assumed)538 void ShaderParser::advanceToken(Token assumed)
539 {
540     assumeToken(assumed);
541     advanceToken();
542 }
543 
assumeToken(Token token)544 void ShaderParser::assumeToken(Token token)
545 {
546     if (m_curToken != token)
547         parseError(
548             (string("unexpected token '") + m_curTokenStr + "', expecting '" + getTokenName(token) + "'").c_str());
549     DE_TEST_ASSERT(m_curToken == token);
550 }
551 
mapDataTypeToken(Token token)552 DataType ShaderParser::mapDataTypeToken(Token token)
553 {
554     switch (token)
555     {
556     case TOKEN_FLOAT:
557         return TYPE_FLOAT;
558     case TOKEN_FLOAT_VEC2:
559         return TYPE_FLOAT_VEC2;
560     case TOKEN_FLOAT_VEC3:
561         return TYPE_FLOAT_VEC3;
562     case TOKEN_FLOAT_VEC4:
563         return TYPE_FLOAT_VEC4;
564     case TOKEN_FLOAT_MAT2:
565         return TYPE_FLOAT_MAT2;
566     case TOKEN_FLOAT_MAT2X3:
567         return TYPE_FLOAT_MAT2X3;
568     case TOKEN_FLOAT_MAT2X4:
569         return TYPE_FLOAT_MAT2X4;
570     case TOKEN_FLOAT_MAT3X2:
571         return TYPE_FLOAT_MAT3X2;
572     case TOKEN_FLOAT_MAT3:
573         return TYPE_FLOAT_MAT3;
574     case TOKEN_FLOAT_MAT3X4:
575         return TYPE_FLOAT_MAT3X4;
576     case TOKEN_FLOAT_MAT4X2:
577         return TYPE_FLOAT_MAT4X2;
578     case TOKEN_FLOAT_MAT4X3:
579         return TYPE_FLOAT_MAT4X3;
580     case TOKEN_FLOAT_MAT4:
581         return TYPE_FLOAT_MAT4;
582     case TOKEN_INT:
583         return TYPE_INT;
584     case TOKEN_INT_VEC2:
585         return TYPE_INT_VEC2;
586     case TOKEN_INT_VEC3:
587         return TYPE_INT_VEC3;
588     case TOKEN_INT_VEC4:
589         return TYPE_INT_VEC4;
590     case TOKEN_UINT:
591         return TYPE_UINT;
592     case TOKEN_UINT_VEC2:
593         return TYPE_UINT_VEC2;
594     case TOKEN_UINT_VEC3:
595         return TYPE_UINT_VEC3;
596     case TOKEN_UINT_VEC4:
597         return TYPE_UINT_VEC4;
598     case TOKEN_BOOL:
599         return TYPE_BOOL;
600     case TOKEN_BOOL_VEC2:
601         return TYPE_BOOL_VEC2;
602     case TOKEN_BOOL_VEC3:
603         return TYPE_BOOL_VEC3;
604     case TOKEN_BOOL_VEC4:
605         return TYPE_BOOL_VEC4;
606     default:
607         return TYPE_INVALID;
608     }
609 }
610 
getTokenName(Token token)611 const char *ShaderParser::getTokenName(Token token)
612 {
613     switch (token)
614     {
615     case TOKEN_INVALID:
616         return "<invalid>";
617     case TOKEN_EOF:
618         return "<eof>";
619     case TOKEN_STRING:
620         return "<string>";
621     case TOKEN_SHADER_SOURCE:
622         return "source";
623 
624     case TOKEN_INT_LITERAL:
625         return "<int>";
626     case TOKEN_FLOAT_LITERAL:
627         return "<float>";
628 
629     // identifiers
630     case TOKEN_IDENTIFIER:
631         return "<identifier>";
632     case TOKEN_TRUE:
633         return "true";
634     case TOKEN_FALSE:
635         return "false";
636     case TOKEN_DESC:
637         return "desc";
638     case TOKEN_EXPECT:
639         return "expect";
640     case TOKEN_GROUP:
641         return "group";
642     case TOKEN_CASE:
643         return "case";
644     case TOKEN_END:
645         return "end";
646     case TOKEN_VALUES:
647         return "values";
648     case TOKEN_BOTH:
649         return "both";
650     case TOKEN_VERTEX:
651         return "vertex";
652     case TOKEN_FRAGMENT:
653         return "fragment";
654     case TOKEN_UNIFORM:
655         return "uniform";
656     case TOKEN_INPUT:
657         return "input";
658     case TOKEN_OUTPUT:
659         return "output";
660     case TOKEN_FLOAT:
661         return "float";
662     case TOKEN_FLOAT_VEC2:
663         return "vec2";
664     case TOKEN_FLOAT_VEC3:
665         return "vec3";
666     case TOKEN_FLOAT_VEC4:
667         return "vec4";
668     case TOKEN_FLOAT_MAT2:
669         return "mat2";
670     case TOKEN_FLOAT_MAT2X3:
671         return "mat2x3";
672     case TOKEN_FLOAT_MAT2X4:
673         return "mat2x4";
674     case TOKEN_FLOAT_MAT3X2:
675         return "mat3x2";
676     case TOKEN_FLOAT_MAT3:
677         return "mat3";
678     case TOKEN_FLOAT_MAT3X4:
679         return "mat3x4";
680     case TOKEN_FLOAT_MAT4X2:
681         return "mat4x2";
682     case TOKEN_FLOAT_MAT4X3:
683         return "mat4x3";
684     case TOKEN_FLOAT_MAT4:
685         return "mat4";
686     case TOKEN_INT:
687         return "int";
688     case TOKEN_INT_VEC2:
689         return "ivec2";
690     case TOKEN_INT_VEC3:
691         return "ivec3";
692     case TOKEN_INT_VEC4:
693         return "ivec4";
694     case TOKEN_UINT:
695         return "uint";
696     case TOKEN_UINT_VEC2:
697         return "uvec2";
698     case TOKEN_UINT_VEC3:
699         return "uvec3";
700     case TOKEN_UINT_VEC4:
701         return "uvec4";
702     case TOKEN_BOOL:
703         return "bool";
704     case TOKEN_BOOL_VEC2:
705         return "bvec2";
706     case TOKEN_BOOL_VEC3:
707         return "bvec3";
708     case TOKEN_BOOL_VEC4:
709         return "bvec4";
710 
711     case TOKEN_ASSIGN:
712         return "=";
713     case TOKEN_PLUS:
714         return "+";
715     case TOKEN_MINUS:
716         return "-";
717     case TOKEN_COMMA:
718         return ",";
719     case TOKEN_VERTICAL_BAR:
720         return "|";
721     case TOKEN_SEMI_COLON:
722         return ";";
723     case TOKEN_LEFT_PAREN:
724         return "(";
725     case TOKEN_RIGHT_PAREN:
726         return ")";
727     case TOKEN_LEFT_BRACKET:
728         return "[";
729     case TOKEN_RIGHT_BRACKET:
730         return "]";
731     case TOKEN_LEFT_BRACE:
732         return "{";
733     case TOKEN_RIGHT_BRACE:
734         return "}";
735 
736     default:
737         return "<unknown>";
738     }
739 }
740 
parseValueElement(DataType expectedDataType,ShaderCase::Value & result)741 void ShaderParser::parseValueElement(DataType expectedDataType, ShaderCase::Value &result)
742 {
743     DataType scalarType = getDataTypeScalarType(expectedDataType);
744     int scalarSize      = getDataTypeScalarSize(expectedDataType);
745 
746     /* \todo [2010-04-19 petri] Support arrays. */
747     ShaderCase::Value::Element elems[16];
748 
749     if (scalarSize > 1)
750     {
751         DE_ASSERT(mapDataTypeToken(m_curToken) == expectedDataType);
752         advanceToken(); // data type (float, vec2, etc.)
753         advanceToken(TOKEN_LEFT_PAREN);
754     }
755 
756     for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
757     {
758         if (scalarType == TYPE_FLOAT)
759         {
760             float signMult = 1.0f;
761             if (m_curToken == TOKEN_MINUS)
762             {
763                 signMult = -1.0f;
764                 advanceToken();
765             }
766 
767             assumeToken(TOKEN_FLOAT_LITERAL);
768             elems[scalarNdx].float32 = signMult * parseFloatLiteral(m_curTokenStr.c_str());
769             advanceToken(TOKEN_FLOAT_LITERAL);
770         }
771         else if (scalarType == TYPE_INT || scalarType == TYPE_UINT)
772         {
773             int signMult = 1;
774             if (m_curToken == TOKEN_MINUS)
775             {
776                 signMult = -1;
777                 advanceToken();
778             }
779 
780             assumeToken(TOKEN_INT_LITERAL);
781             elems[scalarNdx].int32 = (int32_t)(signMult * parseIntLiteral(m_curTokenStr.c_str()));
782             advanceToken(TOKEN_INT_LITERAL);
783         }
784         else
785         {
786             DE_ASSERT(scalarType == TYPE_BOOL);
787             elems[scalarNdx].bool32 = (m_curToken == TOKEN_TRUE);
788             if (m_curToken != TOKEN_TRUE && m_curToken != TOKEN_FALSE)
789                 parseError(string("unexpected token, expecting bool: " + m_curTokenStr));
790             advanceToken(); // true/false
791         }
792 
793         if (scalarNdx != (scalarSize - 1))
794             advanceToken(TOKEN_COMMA);
795     }
796 
797     if (scalarSize > 1)
798         advanceToken(TOKEN_RIGHT_PAREN);
799 
800     // Store results.
801     for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
802         result.elements.push_back(elems[scalarNdx]);
803 }
804 
parseValue(ShaderCase::ValueBlock & valueBlock)805 void ShaderParser::parseValue(ShaderCase::ValueBlock &valueBlock)
806 {
807     PARSE_DBG(("      parseValue()\n"));
808 
809     // Parsed results.
810     ShaderCase::Value result;
811 
812     // Parse storage.
813     if (m_curToken == TOKEN_UNIFORM)
814         result.storageType = ShaderCase::Value::STORAGE_UNIFORM;
815     else if (m_curToken == TOKEN_INPUT)
816         result.storageType = ShaderCase::Value::STORAGE_INPUT;
817     else if (m_curToken == TOKEN_OUTPUT)
818         result.storageType = ShaderCase::Value::STORAGE_OUTPUT;
819     else
820         parseError(string("unexpected token encountered when parsing value classifier"));
821     advanceToken();
822 
823     // Parse data type.
824     result.dataType = mapDataTypeToken(m_curToken);
825     if (result.dataType == TYPE_INVALID)
826         parseError(string("unexpected token when parsing value data type: " + m_curTokenStr));
827     advanceToken();
828 
829     // Parse value name.
830     if (m_curToken == TOKEN_IDENTIFIER || m_curToken == TOKEN_STRING)
831     {
832         if (m_curToken == TOKEN_IDENTIFIER)
833             result.valueName = m_curTokenStr;
834         else
835             result.valueName = parseStringLiteral(m_curTokenStr.c_str());
836     }
837     else
838         parseError(string("unexpected token when parsing value name: " + m_curTokenStr));
839     advanceToken();
840 
841     // Parse assignment operator.
842     advanceToken(TOKEN_ASSIGN);
843 
844     // Parse actual value.
845     if (m_curToken == TOKEN_LEFT_BRACKET) // value list
846     {
847         advanceToken(TOKEN_LEFT_BRACKET);
848         result.arrayLength = 0;
849 
850         for (;;)
851         {
852             parseValueElement(result.dataType, result);
853             result.arrayLength++;
854 
855             if (m_curToken == TOKEN_RIGHT_BRACKET)
856                 break;
857             else if (m_curToken == TOKEN_VERTICAL_BAR)
858             {
859                 advanceToken();
860                 continue;
861             }
862             else
863                 parseError(string("unexpected token in value element array: " + m_curTokenStr));
864         }
865 
866         advanceToken(TOKEN_RIGHT_BRACKET);
867     }
868     else // arrays, single elements
869     {
870         parseValueElement(result.dataType, result);
871         result.arrayLength = 1;
872     }
873 
874     advanceToken(TOKEN_SEMI_COLON); // end of declaration
875 
876     valueBlock.values.push_back(result);
877 }
878 
parseValueBlock(ShaderCase::ValueBlock & valueBlock)879 void ShaderParser::parseValueBlock(ShaderCase::ValueBlock &valueBlock)
880 {
881     PARSE_DBG(("    parseValueBlock()\n"));
882     advanceToken(TOKEN_VALUES);
883     advanceToken(TOKEN_LEFT_BRACE);
884 
885     for (;;)
886     {
887         if (m_curToken == TOKEN_UNIFORM || m_curToken == TOKEN_INPUT || m_curToken == TOKEN_OUTPUT)
888             parseValue(valueBlock);
889         else if (m_curToken == TOKEN_RIGHT_BRACE)
890             break;
891         else
892             parseError(string("unexpected token when parsing a value block: " + m_curTokenStr));
893     }
894 
895     advanceToken(TOKEN_RIGHT_BRACE);
896 
897     // Compute combined array length of value block.
898     int arrayLength = 1;
899     for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++)
900     {
901         const ShaderCase::Value &val = valueBlock.values[valueNdx];
902         if (val.arrayLength > 1)
903         {
904             DE_ASSERT(arrayLength == 1 || arrayLength == val.arrayLength);
905             arrayLength = val.arrayLength;
906         }
907     }
908     valueBlock.arrayLength = arrayLength;
909 }
910 
parseShaderCase(vector<tcu::TestNode * > & shaderNodeList)911 void ShaderParser::parseShaderCase(vector<tcu::TestNode *> &shaderNodeList)
912 {
913     // Parse 'case'.
914     PARSE_DBG(("  parseShaderCase()\n"));
915     advanceToken(TOKEN_CASE);
916 
917     // Parse case name.
918     string caseName = m_curTokenStr;
919     advanceToken(); // \note [pyry] All token types are allowed here.
920 
921     // Setup case.
922     vector<ShaderCase::ValueBlock> valueBlockList;
923 
924     GLSLVersion version                   = DEFAULT_GLSL_VERSION;
925     ShaderCase::ExpectResult expectResult = ShaderCase::EXPECT_PASS;
926     string description;
927     string bothSource;
928     string vertexSource;
929     string fragmentSource;
930 
931     for (;;)
932     {
933         if (m_curToken == TOKEN_END)
934             break;
935         else if (m_curToken == TOKEN_DESC)
936         {
937             advanceToken();
938             assumeToken(TOKEN_STRING);
939 
940             description = parseStringLiteral(m_curTokenStr.c_str());
941             advanceToken();
942         }
943         else if (m_curToken == TOKEN_EXPECT)
944         {
945             advanceToken();
946             assumeToken(TOKEN_IDENTIFIER);
947 
948             if (m_curTokenStr == "pass")
949                 expectResult = ShaderCase::EXPECT_PASS;
950             else if (m_curTokenStr == "compile_fail")
951                 expectResult = ShaderCase::EXPECT_COMPILE_FAIL;
952             else if (m_curTokenStr == "link_fail")
953                 expectResult = ShaderCase::EXPECT_LINK_FAIL;
954             else
955                 parseError(string("invalid expected result value: " + m_curTokenStr));
956 
957             advanceToken();
958         }
959         else if (m_curToken == TOKEN_VALUES)
960         {
961             ShaderCase::ValueBlock block;
962             parseValueBlock(block);
963             valueBlockList.push_back(block);
964         }
965         else if (m_curToken == TOKEN_BOTH || m_curToken == TOKEN_VERTEX || m_curToken == TOKEN_FRAGMENT)
966         {
967             Token token = m_curToken;
968             advanceToken();
969             assumeToken(TOKEN_SHADER_SOURCE);
970             string source = parseShaderSource(m_curTokenStr.c_str());
971             advanceToken();
972             switch (token)
973             {
974             case TOKEN_BOTH:
975                 bothSource = source;
976                 break;
977             case TOKEN_VERTEX:
978                 vertexSource = source;
979                 break;
980             case TOKEN_FRAGMENT:
981                 fragmentSource = source;
982                 break;
983             default:
984                 DE_ASSERT(false);
985             }
986         }
987         else if (m_curToken == TOKEN_VERSION)
988         {
989             advanceToken();
990 
991             int versionNum      = 0;
992             std::string postfix = "";
993 
994             assumeToken(TOKEN_INT_LITERAL);
995             versionNum = (int)parseIntLiteral(m_curTokenStr.c_str());
996             advanceToken();
997 
998             if (m_curToken == TOKEN_IDENTIFIER)
999             {
1000                 postfix = m_curTokenStr;
1001                 advanceToken();
1002             }
1003 
1004             if (versionNum == 100 && postfix == "es")
1005                 version = glu::GLSL_VERSION_100_ES;
1006             else if (versionNum == 300 && postfix == "es")
1007                 version = glu::GLSL_VERSION_300_ES;
1008             else if (versionNum == 310 && postfix == "es")
1009                 version = glu::GLSL_VERSION_310_ES;
1010             else if (versionNum == 130)
1011                 version = glu::GLSL_VERSION_130;
1012             else if (versionNum == 140)
1013                 version = glu::GLSL_VERSION_140;
1014             else if (versionNum == 150)
1015                 version = glu::GLSL_VERSION_150;
1016             else if (versionNum == 330)
1017                 version = glu::GLSL_VERSION_330;
1018             else if (versionNum == 400)
1019                 version = glu::GLSL_VERSION_400;
1020             else if (versionNum == 410)
1021                 version = glu::GLSL_VERSION_410;
1022             else if (versionNum == 420)
1023                 version = glu::GLSL_VERSION_420;
1024             else if (versionNum == 430)
1025                 version = glu::GLSL_VERSION_430;
1026             else if (versionNum == 440)
1027                 version = glu::GLSL_VERSION_440;
1028             else if (versionNum == 450)
1029                 version = glu::GLSL_VERSION_450;
1030             else
1031                 parseError("Unknown GLSL version");
1032         }
1033         else
1034             parseError(string("unexpected token while parsing shader case: " + m_curTokenStr));
1035     }
1036 
1037     advanceToken(TOKEN_END); // case end
1038 
1039     if (bothSource.length() > 0)
1040     {
1041         DE_ASSERT(vertexSource.length() == 0);
1042         DE_ASSERT(fragmentSource.length() == 0);
1043 
1044         string vertName = caseName + "_vertex";
1045         string fragName = caseName + "_fragment";
1046         shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, vertName.c_str(), description.c_str(),
1047                                                 expectResult, valueBlockList, version, bothSource.c_str(), DE_NULL));
1048         shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, fragName.c_str(), description.c_str(),
1049                                                 expectResult, valueBlockList, version, DE_NULL, bothSource.c_str()));
1050     }
1051     else
1052     {
1053         shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, caseName.c_str(), description.c_str(),
1054                                                 expectResult, valueBlockList, version, vertexSource.c_str(),
1055                                                 fragmentSource.c_str()));
1056     }
1057 }
1058 
parseShaderGroup(vector<tcu::TestNode * > & shaderNodeList)1059 void ShaderParser::parseShaderGroup(vector<tcu::TestNode *> &shaderNodeList)
1060 {
1061     // Parse 'case'.
1062     PARSE_DBG(("  parseShaderGroup()\n"));
1063     advanceToken(TOKEN_GROUP);
1064 
1065     // Parse case name.
1066     string name = m_curTokenStr;
1067     advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
1068 
1069     // Parse description.
1070     assumeToken(TOKEN_STRING);
1071     string description = parseStringLiteral(m_curTokenStr.c_str());
1072     advanceToken(TOKEN_STRING);
1073 
1074     std::vector<tcu::TestNode *> children;
1075 
1076     // Parse group children.
1077     for (;;)
1078     {
1079         if (m_curToken == TOKEN_END)
1080             break;
1081         else if (m_curToken == TOKEN_GROUP)
1082             parseShaderGroup(children);
1083         else if (m_curToken == TOKEN_CASE)
1084             parseShaderCase(children);
1085         else
1086             parseError(string("unexpected token while parsing shader group: " + m_curTokenStr));
1087     }
1088 
1089     advanceToken(TOKEN_END); // group end
1090 
1091     // Create group node.
1092     tcu::TestCaseGroup *groupNode = new tcu::TestCaseGroup(m_testCtx, name.c_str(), description.c_str(), children);
1093     shaderNodeList.push_back(groupNode);
1094 }
1095 
parse(const char * input)1096 vector<tcu::TestNode *> ShaderParser::parse(const char *input)
1097 {
1098     // Initialize parser.
1099     m_input       = input;
1100     m_curPtr      = m_input.c_str();
1101     m_curToken    = TOKEN_INVALID;
1102     m_curTokenStr = "";
1103     advanceToken();
1104 
1105     vector<tcu::TestNode *> nodeList;
1106 
1107     // Parse all cases.
1108     PARSE_DBG(("parse()\n"));
1109     for (;;)
1110     {
1111         if (m_curToken == TOKEN_CASE)
1112             parseShaderCase(nodeList);
1113         else if (m_curToken == TOKEN_GROUP)
1114             parseShaderGroup(nodeList);
1115         else if (m_curToken == TOKEN_EOF)
1116             break;
1117         else
1118             parseError(string("invalid token encountered at main level: '") + m_curTokenStr + "'");
1119     }
1120 
1121     assumeToken(TOKEN_EOF);
1122     //  printf("  parsed %d test cases.\n", caseList.size());
1123     return nodeList;
1124 }
1125 
1126 } // namespace sl
1127 
ShaderLibrary(tcu::TestContext & testCtx,RenderContext & renderCtx)1128 ShaderLibrary::ShaderLibrary(tcu::TestContext &testCtx, RenderContext &renderCtx)
1129     : m_testCtx(testCtx)
1130     , m_renderCtx(renderCtx)
1131 {
1132 }
1133 
~ShaderLibrary(void)1134 ShaderLibrary::~ShaderLibrary(void)
1135 {
1136 }
1137 
loadShaderFile(const char * fileName)1138 vector<tcu::TestNode *> ShaderLibrary::loadShaderFile(const char *fileName)
1139 {
1140     tcu::Resource *resource = m_testCtx.getArchive().getResource(fileName);
1141     std::vector<char> buf;
1142 
1143     /*  printf("  loading '%s'\n", fileName);*/
1144 
1145     try
1146     {
1147         int size = resource->getSize();
1148         buf.resize(size + 1);
1149         resource->read((uint8_t *)&buf[0], size);
1150         buf[size] = '\0';
1151     }
1152     catch (const std::exception &)
1153     {
1154         delete resource;
1155         throw;
1156     }
1157 
1158     delete resource;
1159 
1160     sl::ShaderParser parser(m_testCtx, m_renderCtx);
1161     vector<tcu::TestNode *> nodes = parser.parse(&buf[0]);
1162 
1163     return nodes;
1164 }
1165 
1166 // ShaderLibraryGroup
1167 
ShaderLibraryGroup(Context & context,const char * name,const char * description,const char * filename)1168 ShaderLibraryGroup::ShaderLibraryGroup(Context &context, const char *name, const char *description,
1169                                        const char *filename)
1170     : TestCaseGroup(context, name, description)
1171     , m_filename(filename)
1172 {
1173 }
1174 
~ShaderLibraryGroup(void)1175 ShaderLibraryGroup::~ShaderLibraryGroup(void)
1176 {
1177 }
1178 
init(void)1179 void ShaderLibraryGroup::init(void)
1180 {
1181     deqp::ShaderLibrary shaderLibrary(m_testCtx, m_context.getRenderContext());
1182     std::vector<tcu::TestNode *> children = shaderLibrary.loadShaderFile(m_filename.c_str());
1183 
1184     for (int i = 0; i < (int)children.size(); i++)
1185         addChild(children[i]);
1186 }
1187 
1188 } // namespace deqp
1189