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