Bug 1918529 - fix some subpixel misalignment issues with gfx.webrender.svg-filter...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / modules / shared / glsShaderLibrary.js
blob27f86e055c934022200a4f4d7af97aa926e9f96d
1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 'use strict';
22 goog.provide('modules.shared.glsShaderLibrary');
23 goog.require('framework.common.tcuTestCase');
24 goog.require('framework.opengl.gluShaderUtil');
25 goog.require('modules.shared.glsShaderLibraryCase');
27 goog.scope(function() {
29 var glsShaderLibrary = modules.shared.glsShaderLibrary;
30 var tcuTestCase = framework.common.tcuTestCase;
31 var glsShaderLibraryCase = modules.shared.glsShaderLibraryCase;
32 var gluShaderUtil = framework.opengl.gluShaderUtil;
34 glsShaderLibrary.generateTestCases = function() {
35 /** @type {glsShaderLibrary.Parser} */ var parser = new glsShaderLibrary.Parser();
36 try {
37 /** @type {Object} */ var state = tcuTestCase.runner;
38 var tree = parser.parse(state.testFile);
39 var rootTest = tcuTestCase.newTest(state.testName, 'Top level');
40 rootTest.setChildren(tree);
41 state.setRoot(rootTest);
43 catch (err) {
44 bufferedLogToConsole(err);
45 testFailed('Failed to parse shader test case file');
46 return false;
48 return true;
51 glsShaderLibrary.processTestFile = function() {
52 if (glsShaderLibrary.generateTestCases()) {
53 tcuTestCase.runner.runCallback(glsShaderLibraryCase.runTestCases);
54 } else {
55 tcuTestCase.runner.terminate();
59 glsShaderLibrary.isWhitespace = function(value) {
60 return /^[ \t\r\n]+$/.test(value);
62 glsShaderLibrary.isEOL = function(value) {
63 return /^[\r\n]+$/.test(value);
65 glsShaderLibrary.isAlpha = function(value) {
66 return /^[a-zA-Z]$/.test(value);
68 glsShaderLibrary.isNumeric = function(value) {
69 return /^[0-9]$/.test(value);
71 glsShaderLibrary.isCaseNameChar = function(value) {
72 return /^[a-zA-Z0-9_\-\.]$/.test(value);
75 /**
76 * Removes however many indents there are on the first line from all lines.
77 * @param {string} str
78 * @return {string} output
80 glsShaderLibrary.removeExtraIndentation = function(str) {
81 return glsShaderLibrary.removeExtraIndentationArray(
82 str.split(/\r\n|\r|\n/)
83 ).join('\n');
86 /**
87 * Returns an array of strings without indentation.
88 * @param {Array<string>} arr
89 * @return {Array<string>} output
91 glsShaderLibrary.removeExtraIndentationArray = function(arr) {
92 /** @type {Array<string>} */ var output = [];
94 if (arr.length) {
96 /** @type {number} */ var numIndentChars = 0;
97 for (var i = 0; i < arr[0].length && glsShaderLibrary.isWhitespace(arr[0].charAt(i)); ++i) {
98 numIndentChars += arr[0].charAt(i) === '\t' ? 4 : 1;
101 for (var i = 0; i < arr.length; ++i) {
102 /** @type {number} */ var removed = 0;
103 /** @type {number} */ var j;
104 // Some tests are indented inconsistently, so we have to check for non-whitespace characters here.
105 for (j = 0; removed < numIndentChars && j < arr[i].length && glsShaderLibrary.isWhitespace(arr[i].charAt(j)); ++j) {
106 removed += (arr[i].charAt(j) === '\t' ? 4 : 1);
109 output.push(arr[i].substr(j, arr[i].length - j));
114 return output;
117 glsShaderLibrary.de_assert = function(condition) {
118 if (!condition) {
119 throw Error();
124 * @param {string} str
125 * @param {string} endstr end of string character
126 * @param {boolean=} trimFront trim leading whitespace
127 * @return {string} str
128 * @private
130 glsShaderLibrary.parseStringLiteralHelper = function(str, endstr, trimFront) {
131 trimFront = trimFront || false;
133 /** @type {number} */ var index_end = 0;
134 // isolate the string
135 do {
136 index_end = str.indexOf(endstr, index_end + 1);
137 } while (index_end >= 0 && str.charAt(index_end - 1) === '\\');
139 if (index_end <= 0) {
140 index_end = str.length;
143 // strip quotes, replace \n and \t with nl and tabs respectively
144 str = str.substr(endstr.length, index_end - endstr.length);
145 if (trimFront)
146 str = str.replace(/^\s*\n/, '');
147 var result = '';
148 var i = 0;
149 while (str[i] != undefined) {
150 if (str[i] == '\\') {
151 switch (str[i + 1]) {
152 case undefined:
153 break;
154 case 'n':
155 result += '\n';
156 break;
157 case 't':
158 result += '\t';
159 break;
160 default:
161 result += str[i + 1];
162 break;
164 i += 2;
165 } else {
166 result += str[i];
167 i++;
170 return result;
175 * glsShaderLibrary.Parser class
176 * @constructor
178 glsShaderLibrary.Parser = function() {
180 /* data members */
183 * The Token constants
184 * @enum {number}
186 var Token = {
187 TOKEN_INVALID: 0,
188 TOKEN_EOF: 1,
189 TOKEN_STRING: 2,
190 TOKEN_SHADER_SOURCE: 3,
192 TOKEN_INT_LITERAL: 4,
193 TOKEN_FLOAT_LITERAL: 5,
195 // identifiers
196 TOKEN_IDENTIFIER: 6,
197 TOKEN_TRUE: 7,
198 TOKEN_FALSE: 8,
199 TOKEN_DESC: 9,
200 TOKEN_EXPECT: 10,
201 TOKEN_GROUP: 11,
202 TOKEN_CASE: 12,
203 TOKEN_END: 13,
204 TOKEN_VALUES: 14,
205 TOKEN_BOTH: 15,
206 TOKEN_VERTEX: 26,
207 TOKEN_FRAGMENT: 17,
208 TOKEN_UNIFORM: 18,
209 TOKEN_INPUT: 19,
210 TOKEN_OUTPUT: 20,
211 TOKEN_FLOAT: 21,
212 TOKEN_FLOAT_VEC2: 22,
213 TOKEN_FLOAT_VEC3: 23,
214 TOKEN_FLOAT_VEC4: 24,
215 TOKEN_FLOAT_MAT2: 25,
216 TOKEN_FLOAT_MAT2X3: 26,
217 TOKEN_FLOAT_MAT2X4: 27,
218 TOKEN_FLOAT_MAT3X2: 28,
219 TOKEN_FLOAT_MAT3: 29,
220 TOKEN_FLOAT_MAT3X4: 30,
221 TOKEN_FLOAT_MAT4X2: 31,
222 TOKEN_FLOAT_MAT4X3: 32,
223 TOKEN_FLOAT_MAT4: 33,
224 TOKEN_INT: 34,
225 TOKEN_INT_VEC2: 35,
226 TOKEN_INT_VEC3: 36,
227 TOKEN_INT_VEC4: 37,
228 TOKEN_UINT: 38,
229 TOKEN_UINT_VEC2: 39,
230 TOKEN_UINT_VEC3: 40,
231 TOKEN_UINT_VEC4: 41,
232 TOKEN_BOOL: 42,
233 TOKEN_BOOL_VEC2: 43,
234 TOKEN_BOOL_VEC3: 44,
235 TOKEN_BOOL_VEC4: 45,
236 TOKEN_VERSION: 46,
238 // symbols
239 TOKEN_ASSIGN: 47,
240 TOKEN_PLUS: 48,
241 TOKEN_MINUS: 49,
242 TOKEN_COMMA: 50,
243 TOKEN_VERTICAL_BAR: 51,
244 TOKEN_SEMI_COLON: 52,
245 TOKEN_LEFT_PAREN: 53,
246 TOKEN_RIGHT_PAREN: 54,
247 TOKEN_LEFT_BRACKET: 55,
248 TOKEN_RIGHT_BRACKET: 56,
249 TOKEN_LEFT_BRACE: 57,
250 TOKEN_RIGHT_BRACE: 58,
252 TOKEN_LAST: 59
255 /** @type {string} */ var m_input = '';
256 /** @type {number} */ var m_curPtr = 0;
257 /** @type {number} */ var m_curToken;// = Token.TOKEN_INVALID;
258 /** @type {string} */ var m_curTokenStr = '';
260 /* function members */
261 this.parse = function(input) {
263 // initialise parser
264 m_input = input;
265 m_curPtr = 0;
266 m_curToken = Token.TOKEN_INVALID;
267 m_curTokenStr = '';
268 advanceToken();
270 /** @type {Array<tcuTestCase.DeqpTest>} */ var nodeList = [];
272 for (;;) {
274 if (m_curToken === Token.TOKEN_CASE) {
275 parseShaderCase(nodeList);
276 } else if (m_curToken === Token.TOKEN_GROUP) {
277 parseShaderGroup(nodeList);
278 } else if (m_curToken === Token.TOKEN_EOF) {
279 break;
280 } else {
281 // throw Error("invalid token encountered at main level: '" + m_curTokenStr + "'");
282 testFailed("invalid token encountered at main level: '" + m_curTokenStr + "'");
283 tcuTestCase.runner.terminate();
288 return nodeList;
293 * ensures that the token exists
294 * otherwise it returns the corresponding token's name depending on enum number value
295 * @param {number} id
296 * @return {string} name
298 var resolveTokenName = function(id) {
299 for (var name in Token) {
300 if (Token[name] === id) return name;
302 return 'TOKEN_UNKNOWN';
306 * Throws an error which contains the passed string
307 * @param {string} errorStr that contains an error to notify
308 * @return {string} error
310 var parseError = function(errorStr) {
311 // abort
312 throw 'glsShaderLibrary.Parser error: ' + errorStr + ' near ' + m_input.substr(m_curPtr, m_curPtr + 80);
316 * Converts string into float
317 * @param {string} str
318 * @return {number}
320 var parseFloatLiteral = function(str) {
321 return parseFloat(str);
325 * Converts string into integer
326 * @param {string} str
327 * @return {number}
329 var parseIntLiteral = function(str) {
330 return parseInt(str, 10);
332 var parseStringLiteral = function(str) {
334 * @type {string}
335 * find delimitor
336 */ var endchar = str.substr(0, 1);
337 return glsShaderLibrary.parseStringLiteralHelper(str, endchar);
339 var parseShaderSource = function(str) {
340 // similar to parse literal, delimitors are two double quotes ("")
341 return glsShaderLibrary.removeExtraIndentation(
342 glsShaderLibrary.parseStringLiteralHelper(str, '""', true)
346 var advanceTokenWorker = function() {
348 // Skip old token
349 m_curPtr += m_curTokenStr.length;
351 // Reset token (for safety).
352 m_curToken = Token.TOKEN_INVALID;
353 m_curTokenStr = '';
355 // Eat whitespace & comments while they last.
356 for (;;) {
358 while (glsShaderLibrary.isWhitespace(m_input.charAt(m_curPtr))) ++m_curPtr;
360 // check for EOL comment
361 if (m_input.charAt(m_curPtr) === '#') {
362 // if m_input is to be an array of lines then this probably wont work very well
363 while (
364 m_curPtr < m_input.length &&
365 !glsShaderLibrary.isEOL(m_input.charAt(m_curPtr))
366 ) ++m_curPtr;
367 } else {
368 break;
373 if (m_curPtr >= m_input.length) {
375 m_curToken = Token.TOKEN_EOF;
376 m_curTokenStr = '<EOF>';
378 } else if (glsShaderLibrary.isAlpha(m_input.charAt(m_curPtr))) {
380 /** @type {number} */ var end = m_curPtr + 1;
381 while (glsShaderLibrary.isCaseNameChar(m_input.charAt(end))) ++end;
383 m_curTokenStr = m_input.substr(m_curPtr, end - m_curPtr);
385 m_curToken = (function() {
386 // consider reimplementing with a binary search
387 switch (m_curTokenStr) {
388 case 'true': return Token.TOKEN_TRUE;
389 case 'false': return Token.TOKEN_FALSE;
390 case 'desc': return Token.TOKEN_DESC;
391 case 'expect': return Token.TOKEN_EXPECT;
392 case 'group': return Token.TOKEN_GROUP;
393 case 'case': return Token.TOKEN_CASE;
394 case 'end': return Token.TOKEN_END;
395 case 'values': return Token.TOKEN_VALUES;
396 case 'both': return Token.TOKEN_BOTH;
397 case 'vertex': return Token.TOKEN_VERTEX;
398 case 'fragment': return Token.TOKEN_FRAGMENT;
399 case 'uniform': return Token.TOKEN_UNIFORM;
400 case 'input': return Token.TOKEN_INPUT;
401 case 'output': return Token.TOKEN_OUTPUT;
402 case 'float': return Token.TOKEN_FLOAT;
403 case 'vec2': return Token.TOKEN_FLOAT_VEC2;
404 case 'vec3': return Token.TOKEN_FLOAT_VEC3;
405 case 'vec4': return Token.TOKEN_FLOAT_VEC4;
406 case 'mat2': return Token.TOKEN_FLOAT_MAT2;
407 case 'mat2x3': return Token.TOKEN_FLOAT_MAT2X3;
408 case 'mat2x4': return Token.TOKEN_FLOAT_MAT2X4;
409 case 'mat3x2': return Token.TOKEN_FLOAT_MAT3X2;
410 case 'mat3': return Token.TOKEN_FLOAT_MAT3;
411 case 'mat3x4': return Token.TOKEN_FLOAT_MAT3X4;
412 case 'mat4x2': return Token.TOKEN_FLOAT_MAT4X2;
413 case 'mat4x3': return Token.TOKEN_FLOAT_MAT4X3;
414 case 'mat4': return Token.TOKEN_FLOAT_MAT4;
415 case 'int': return Token.TOKEN_INT;
416 case 'ivec2': return Token.TOKEN_INT_VEC2;
417 case 'ivec3': return Token.TOKEN_INT_VEC3;
418 case 'ivec4': return Token.TOKEN_INT_VEC4;
419 case 'uint': return Token.TOKEN_UINT;
420 case 'uvec2': return Token.TOKEN_UINT_VEC2;
421 case 'uvec3': return Token.TOKEN_UINT_VEC3;
422 case 'uvec4': return Token.TOKEN_UINT_VEC4;
423 case 'bool': return Token.TOKEN_BOOL;
424 case 'bvec2': return Token.TOKEN_BOOL_VEC2;
425 case 'bvec3': return Token.TOKEN_BOOL_VEC3;
426 case 'bvec4': return Token.TOKEN_BOOL_VEC4;
427 case 'version': return Token.TOKEN_VERSION;
428 default: return Token.TOKEN_IDENTIFIER;
430 }());
432 } else if (glsShaderLibrary.isNumeric(m_input.charAt(m_curPtr))) {
434 /** @type {number} */ var p = m_curPtr;
435 while (glsShaderLibrary.isNumeric(m_input.charAt(p))) ++p;
437 if (m_input.charAt(p) === '.') { // float
439 ++p;
440 while (glsShaderLibrary.isNumeric(m_input.charAt(p))) ++p;
442 if (m_input.charAt(p) === 'e' || m_input.charAt(p) === 'E') {
444 ++p;
445 if (m_input.charAt(p) === '+' || m_input.charAt(p) === '-') ++p;
447 glsShaderLibrary.de_assert(p < m_input.length && glsShaderLibrary.isNumeric(m_input.charAt(p)));
448 while (glsShaderLibrary.isNumeric(m_input.charAt(p))) ++p;
452 m_curToken = Token.TOKEN_FLOAT_LITERAL;
453 m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
455 } else {
457 m_curToken = Token.TOKEN_INT_LITERAL;
458 m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
462 } else if (m_input.charAt(m_curPtr) === '"' && m_input.charAt(m_curPtr + 1) === '"') { // shader source
464 var p = m_curPtr + 2;
466 while (m_input.charAt(p) != '"' || m_input.charAt(p + 1) != '"') {
467 glsShaderLibrary.de_assert(p < m_input.length);
468 if (m_input.charAt(p) === '\\') {
469 glsShaderLibrary.de_assert(p + 1 < m_input.length);
470 p += 2;
471 } else {
472 ++p;
475 p += 2;
477 m_curToken = Token.TOKEN_SHADER_SOURCE;
478 m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
480 } else if (m_input.charAt(m_curPtr) === '"' || m_input.charAt(m_curPtr) === "'") {
482 /** @type {string} */ var delimitor = m_input.charAt(m_curPtr);
483 var p = m_curPtr + 1;
485 while (m_input.charAt(p) != delimitor) {
487 glsShaderLibrary.de_assert(p < m_input.length);
488 if (m_input.charAt(p) === '\\') {
489 glsShaderLibrary.de_assert(p + 1 < m_input.length);
490 p += 2;
491 } else {
492 ++p;
496 ++p;
498 m_curToken = Token.TOKEN_STRING;
499 m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
501 } else {
503 m_curTokenStr = m_input.charAt(m_curPtr);
504 m_curToken = (function() {
505 // consider reimplementing with a binary search
506 switch (m_curTokenStr) {
507 case '=': return Token.TOKEN_ASSIGN;
508 case '+': return Token.TOKEN_PLUS;
509 case '-': return Token.TOKEN_MINUS;
510 case ',': return Token.TOKEN_COMMA;
511 case '|': return Token.TOKEN_VERTICAL_BAR;
512 case ';': return Token.TOKEN_SEMI_COLON;
513 case '(': return Token.TOKEN_LEFT_PAREN;
514 case ')': return Token.TOKEN_RIGHT_PAREN;
515 case '[': return Token.TOKEN_LEFT_BRACKET;
516 case ']': return Token.TOKEN_RIGHT_BRACKET;
517 case '{': return Token.TOKEN_LEFT_BRACE;
518 case '}': return Token.TOKEN_RIGHT_BRACE;
520 default: return Token.TOKEN_INVALID;
522 }());
529 * @return {Object.<number, string, string>}
531 var advanceTokenTester = function(input, current_index) {
532 m_input = input;
533 m_curPtr = current_index;
534 m_curTokenStr = '';
535 advanceTokenWorker();
536 return {
537 /** @type {number} */ idType: m_curToken,
538 /** @type {string} */ name: resolveTokenName(m_curToken),
539 /** @type {string} */ value: m_curTokenStr
544 * @param {Token=} tokenAssumed
546 var advanceToken = function(tokenAssumed) {
547 if (typeof(tokenAssumed) !== 'undefined') {
548 assumeToken(tokenAssumed);
550 advanceTokenWorker();
552 var assumeToken = function(token) {
554 if (m_curToken != token) {
555 // parse error
556 /** @type {string} */ var msg = "unexpected token '" + m_curTokenStr + "', expecting '" + getTokenName(token) + "'";
557 throw Error('Parse Error. ' + msg + ' near ' + m_curPtr + ' ...');
560 var mapDataTypeToken = function(token) {
561 switch (token) {
562 case Token.TOKEN_FLOAT: return gluShaderUtil.DataType.FLOAT;
563 case Token.TOKEN_FLOAT_VEC2: return gluShaderUtil.DataType.FLOAT_VEC2;
564 case Token.TOKEN_FLOAT_VEC3: return gluShaderUtil.DataType.FLOAT_VEC3;
565 case Token.TOKEN_FLOAT_VEC4: return gluShaderUtil.DataType.FLOAT_VEC4;
566 case Token.TOKEN_FLOAT_MAT2: return gluShaderUtil.DataType.FLOAT_MAT2;
567 case Token.TOKEN_FLOAT_MAT2X3: return gluShaderUtil.DataType.FLOAT_MAT2X3;
568 case Token.TOKEN_FLOAT_MAT2X4: return gluShaderUtil.DataType.FLOAT_MAT2X4;
569 case Token.TOKEN_FLOAT_MAT3X2: return gluShaderUtil.DataType.FLOAT_MAT3X2;
570 case Token.TOKEN_FLOAT_MAT3: return gluShaderUtil.DataType.FLOAT_MAT3;
571 case Token.TOKEN_FLOAT_MAT3X4: return gluShaderUtil.DataType.FLOAT_MAT3X4;
572 case Token.TOKEN_FLOAT_MAT4X2: return gluShaderUtil.DataType.FLOAT_MAT4X2;
573 case Token.TOKEN_FLOAT_MAT4X3: return gluShaderUtil.DataType.FLOAT_MAT4X3;
574 case Token.TOKEN_FLOAT_MAT4: return gluShaderUtil.DataType.FLOAT_MAT4;
575 case Token.TOKEN_INT: return gluShaderUtil.DataType.INT;
576 case Token.TOKEN_INT_VEC2: return gluShaderUtil.DataType.INT_VEC2;
577 case Token.TOKEN_INT_VEC3: return gluShaderUtil.DataType.INT_VEC3;
578 case Token.TOKEN_INT_VEC4: return gluShaderUtil.DataType.INT_VEC4;
579 case Token.TOKEN_UINT: return gluShaderUtil.DataType.UINT;
580 case Token.TOKEN_UINT_VEC2: return gluShaderUtil.DataType.UINT_VEC2;
581 case Token.TOKEN_UINT_VEC3: return gluShaderUtil.DataType.UINT_VEC3;
582 case Token.TOKEN_UINT_VEC4: return gluShaderUtil.DataType.UINT_VEC4;
583 case Token.TOKEN_BOOL: return gluShaderUtil.DataType.BOOL;
584 case Token.TOKEN_BOOL_VEC2: return gluShaderUtil.DataType.BOOL_VEC2;
585 case Token.TOKEN_BOOL_VEC3: return gluShaderUtil.DataType.BOOL_VEC3;
586 case Token.TOKEN_BOOL_VEC4: return gluShaderUtil.DataType.BOOL_VEC4;
587 default: return gluShaderUtil.DataType.INVALID;
592 * Returns the corresponding token's name depending on enum number value
593 * @param {number} token
594 * @return {string}
596 var getTokenName = function(token) {
597 switch (token) {
598 case Token.TOKEN_INVALID: return '<invalid>';
599 case Token.TOKEN_EOF: return '<eof>';
600 case Token.TOKEN_STRING: return '<string>';
601 case Token.TOKEN_SHADER_SOURCE: return 'source';
603 case Token.TOKEN_INT_LITERAL: return '<int>';
604 case Token.TOKEN_FLOAT_LITERAL: return '<float>';
606 // identifiers
607 case Token.TOKEN_IDENTIFIER: return '<identifier>';
608 case Token.TOKEN_TRUE: return 'true';
609 case Token.TOKEN_FALSE: return 'false';
610 case Token.TOKEN_DESC: return 'desc';
611 case Token.TOKEN_EXPECT: return 'expect';
612 case Token.TOKEN_GROUP: return 'group';
613 case Token.TOKEN_CASE: return 'case';
614 case Token.TOKEN_END: return 'end';
615 case Token.TOKEN_VALUES: return 'values';
616 case Token.TOKEN_BOTH: return 'both';
617 case Token.TOKEN_VERTEX: return 'vertex';
618 case Token.TOKEN_FRAGMENT: return 'fragment';
619 case Token.TOKEN_UNIFORM: return 'uniform';
620 case Token.TOKEN_INPUT: return 'input';
621 case Token.TOKEN_OUTPUT: return 'output';
622 case Token.TOKEN_FLOAT: return 'float';
623 case Token.TOKEN_FLOAT_VEC2: return 'vec2';
624 case Token.TOKEN_FLOAT_VEC3: return 'vec3';
625 case Token.TOKEN_FLOAT_VEC4: return 'vec4';
626 case Token.TOKEN_FLOAT_MAT2: return 'mat2';
627 case Token.TOKEN_FLOAT_MAT2X3: return 'mat2x3';
628 case Token.TOKEN_FLOAT_MAT2X4: return 'mat2x4';
629 case Token.TOKEN_FLOAT_MAT3X2: return 'mat3x2';
630 case Token.TOKEN_FLOAT_MAT3: return 'mat3';
631 case Token.TOKEN_FLOAT_MAT3X4: return 'mat3x4';
632 case Token.TOKEN_FLOAT_MAT4X2: return 'mat4x2';
633 case Token.TOKEN_FLOAT_MAT4X3: return 'mat4x3';
634 case Token.TOKEN_FLOAT_MAT4: return 'mat4';
635 case Token.TOKEN_INT: return 'int';
636 case Token.TOKEN_INT_VEC2: return 'ivec2';
637 case Token.TOKEN_INT_VEC3: return 'ivec3';
638 case Token.TOKEN_INT_VEC4: return 'ivec4';
639 case Token.TOKEN_UINT: return 'uint';
640 case Token.TOKEN_UINT_VEC2: return 'uvec2';
641 case Token.TOKEN_UINT_VEC3: return 'uvec3';
642 case Token.TOKEN_UINT_VEC4: return 'uvec4';
643 case Token.TOKEN_BOOL: return 'bool';
644 case Token.TOKEN_BOOL_VEC2: return 'bvec2';
645 case Token.TOKEN_BOOL_VEC3: return 'bvec3';
646 case Token.TOKEN_BOOL_VEC4: return 'bvec4';
648 case Token.TOKEN_ASSIGN: return '=';
649 case Token.TOKEN_PLUS: return '+';
650 case Token.TOKEN_MINUS: return '-';
651 case Token.TOKEN_COMMA: return ',';
652 case Token.TOKEN_VERTICAL_BAR: return '|';
653 case Token.TOKEN_SEMI_COLON: return ';';
654 case Token.TOKEN_LEFT_PAREN: return '(';
655 case Token.TOKEN_RIGHT_PAREN: return ')';
656 case Token.TOKEN_LEFT_BRACKET: return '[';
657 case Token.TOKEN_RIGHT_BRACKET: return ']';
658 case Token.TOKEN_LEFT_BRACE: return ' {';
659 case Token.TOKEN_RIGHT_BRACE: return '}';
661 default: return '<unknown>';
666 * @param {?gluShaderUtil.DataType} expectedDataType
667 * @param {Object} result
669 var parseValueElement = function(expectedDataType, result) {
670 /** @type {?string} */ var scalarType = null;
671 /** @type {number} */ var scalarSize = 0;
672 if (expectedDataType) {
673 scalarType = gluShaderUtil.getDataTypeScalarType(expectedDataType);
674 scalarSize = gluShaderUtil.getDataTypeScalarSize(expectedDataType);
677 /** @type {Array<number>} */ var elems = [];
679 if (scalarSize > 1) {
680 glsShaderLibrary.de_assert(mapDataTypeToken(m_curToken) === expectedDataType);
681 advanceToken(); // data type(float, vec2, etc.)
682 advanceToken(Token.TOKEN_LEFT_PAREN);
685 for (var i = 0; i < scalarSize; ++i) {
686 if (scalarType === 'float') {
688 /** @type {number} */ var signMult = 1.0;
689 if (m_curToken === Token.TOKEN_MINUS) {
690 signMult = -1.0;
691 advanceToken();
694 assumeToken(Token.TOKEN_FLOAT_LITERAL);
695 elems.push(signMult * parseFloatLiteral(m_curTokenStr));
696 advanceToken(Token.TOKEN_FLOAT_LITERAL);
698 } else if (scalarType === 'int' || scalarType === 'uint') {
700 var signMult = 1;
701 if (m_curToken === Token.TOKEN_MINUS) {
702 signMult = -1;
703 advanceToken();
706 assumeToken(Token.TOKEN_INT_LITERAL);
707 elems.push(signMult * parseIntLiteral(m_curTokenStr));
708 advanceToken(Token.TOKEN_INT_LITERAL);
710 } else {
712 glsShaderLibrary.de_assert(scalarType === 'bool');
713 elems.push(m_curToken === Token.TOKEN_TRUE);
714 if (m_curToken != Token.TOKEN_TRUE && m_curToken != Token.TOKEN_FALSE) {
715 throw Error('unexpected token, expecting bool: ' + m_curTokenStr);
717 advanceToken(); // true/false
721 if (i != (scalarSize - 1)) {
722 advanceToken(Token.TOKEN_COMMA);
726 if (scalarSize > 1) {
727 advanceToken(Token.TOKEN_RIGHT_PAREN);
730 for (var i = 0; i < elems.length; i++)
731 result.elements.push(elems[i]);
736 * @param {Object.<Array, number>} valueBlock
738 var parseValue = function(valueBlock) {
741 * @type {Object}
743 var result = {
744 /** @type {?gluShaderUtil.DataType} */ dataType: null,
745 /** @type {?glsShaderLibraryCase.shaderCase} */ storageType: null,
746 /** @type {?string} */ valueName: null,
747 /** @type {Array} */ elements: []
750 // parse storage
751 switch (m_curToken) {
752 case Token.TOKEN_UNIFORM:
753 result.storageType = glsShaderLibraryCase.shaderCase.STORAGE_UNIFORM;
754 break;
755 case Token.TOKEN_INPUT:
756 result.storageType = glsShaderLibraryCase.shaderCase.STORAGE_INPUT;
757 break;
758 case Token.TOKEN_OUTPUT:
759 result.storageType = glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT;
760 break;
761 default:
762 throw Error('unexpected token encountered when parsing value classifier');
763 break;
765 advanceToken();
767 // parse data type
768 result.dataType = mapDataTypeToken(m_curToken);
769 if (result.dataType === gluShaderUtil.DataType.INVALID) {
770 throw Error('unexpected token when parsing value data type: ' + m_curTokenStr);
772 advanceToken();
774 // parse value name
775 if (m_curToken === Token.TOKEN_IDENTIFIER) {
776 result.valueName = m_curTokenStr;
777 } else if (m_curToken === Token.TOKEN_STRING) {
778 result.valueName = parseStringLiteral(m_curTokenStr);
779 } else {
780 throw Error('unexpected token when parsing value name: ' + m_curTokenStr);
782 advanceToken();
784 // parse assignment operator.
785 advanceToken(Token.TOKEN_ASSIGN);
787 // parse actual value
788 if (m_curToken === Token.TOKEN_LEFT_BRACKET) { // value list
789 advanceToken(Token.TOKEN_LEFT_BRACKET);
790 result.arrayLength = 0;
792 for (;;) {
793 parseValueElement(result.dataType, result);
794 result.arrayLength += 1;
796 if (m_curToken === Token.TOKEN_RIGHT_BRACKET) {
797 break;
798 } else if (m_curToken === Token.TOKEN_VERTICAL_BAR) { // pipe?
799 advanceToken();
800 continue;
801 } else {
802 throw Error('unexpected token in value element array: ' + m_curTokenStr);
806 advanceToken(Token.TOKEN_RIGHT_BRACKET);
808 } else { // arrays, single elements
809 parseValueElement(result.dataType, result);
810 result.arrayLength = 1;
813 advanceToken(Token.TOKEN_SEMI_COLON);
815 valueBlock.values.push(result);
820 * @param {Object.<Array, number>} valueBlock
822 var parseValueBlock = function(valueBlock) {
824 advanceToken(Token.TOKEN_VALUES);
825 advanceToken(Token.TOKEN_LEFT_BRACE);
827 for (;;) {
828 if (
829 m_curToken === Token.TOKEN_UNIFORM ||
830 m_curToken === Token.TOKEN_INPUT ||
831 m_curToken === Token.TOKEN_OUTPUT
833 parseValue(valueBlock);
834 } else if (m_curToken === Token.TOKEN_RIGHT_BRACE) {
835 break;
836 } else {
837 throw Error('unexpected( token when parsing a value block: ' + m_curTokenStr);
841 advanceToken(Token.TOKEN_RIGHT_BRACE);
843 /** @type {number} */ var arrayLength = 1;
844 // compute combined array length of value block.
845 for (var i = 0; i < valueBlock.values.length; ++i) {
846 if (valueBlock.values[i].arrayLength > 1) {
847 glsShaderLibrary.de_assert(arrayLength === 1 || arrayLength === valueBlock.values[i].arrayLength);
848 arrayLength = valueBlock.values[i].arrayLength;
852 valueBlock.arrayLength = arrayLength;
857 * @param {Array<tcuTestCase.DeqpTest>} shaderNodeList
859 var parseShaderCase = function(shaderNodeList) {
861 // parse case
862 advanceToken(Token.TOKEN_CASE);
865 * @type {string}
866 * parse case name
868 var caseName = m_curTokenStr;
869 advanceToken(); // \note [pyry] All token types are allowed here.
872 * @type {Array<Object>}
873 * setup case
875 var valueBlockList = [];
877 /** TODO: Should the default version be defined elsewhere? */
878 /** @type {string} */ var version = '100';
879 /** @type {number} */ var expectResult = glsShaderLibraryCase.expectResult.EXPECT_PASS;
880 /** @type {string} */ var description;
881 /** @type {string} */ var bothSource = '';
882 /** @type {string} */ var vertexSource = '';
883 /** @type {string} */ var fragmentSource = '';
885 for (;;) {
887 if (m_curToken === Token.TOKEN_END) {
889 break;
891 } else if (m_curToken === Token.TOKEN_DESC) {
893 advanceToken();
894 assumeToken(Token.TOKEN_STRING);
896 description = parseStringLiteral(m_curTokenStr);
897 advanceToken();
899 } else if (m_curToken === Token.TOKEN_EXPECT) {
901 advanceToken();
902 assumeToken(Token.TOKEN_IDENTIFIER);
904 expectResult = (function(token) {
905 switch (token) {
906 case 'pass': return glsShaderLibraryCase.expectResult.EXPECT_PASS;
907 case 'compile_fail': return glsShaderLibraryCase.expectResult.EXPECT_COMPILE_FAIL;
908 case 'link_fail': return glsShaderLibraryCase.expectResult.EXPECT_LINK_FAIL;
909 case 'compile_or_link_fail': return glsShaderLibraryCase.expectResult.EXPECT_COMPILE_LINK_FAIL;
910 case 'build_successful': return glsShaderLibraryCase.expectResult.EXPECT_BUILD_SUCCESSFUL;
911 default:
912 throw Error('invalid expected result value: ' + m_curTokenStr);
914 }(m_curTokenStr));
916 advanceToken();
918 } else if (m_curToken === Token.TOKEN_VALUES) {
920 /** @type {Object.<Array, number>} */ var block = glsShaderLibraryCase.genValueBlock();
921 parseValueBlock(block);
922 valueBlockList.push(block);
924 } else if (
925 m_curToken === Token.TOKEN_BOTH ||
926 m_curToken === Token.TOKEN_VERTEX ||
927 m_curToken === Token.TOKEN_FRAGMENT
930 /** @type {number} */ var token = m_curToken;
931 advanceToken();
932 assumeToken(Token.TOKEN_SHADER_SOURCE);
933 /** @type {string} */ var source = parseShaderSource(m_curTokenStr);
935 advanceToken();
936 switch (token) {
937 case Token.TOKEN_BOTH: bothSource = source; break;
938 case Token.TOKEN_VERTEX: vertexSource = source; break;
939 case Token.TOKEN_FRAGMENT: fragmentSource = source; break;
940 default: glsShaderLibrary.de_assert(false); break;
943 } else if (m_curToken === Token.TOKEN_VERSION) {
945 advanceToken();
947 /** @type {number} */ var versionNum = 0;
948 /** @type {string} */ var postfix = '';
950 assumeToken(Token.TOKEN_INT_LITERAL);
951 versionNum = parseIntLiteral(m_curTokenStr);
952 advanceToken();
954 if (m_curToken === Token.TOKEN_IDENTIFIER) {
955 postfix = m_curTokenStr;
956 advanceToken();
959 // TODO: need to fix these constants, we dont have glu
960 if (versionNum === 100 && postfix === 'es') version = '100';
961 else if (versionNum === 300 && postfix === 'es') version = '300 es';
962 else if (versionNum === 310 && postfix === 'es') version = '310 es';
963 else if (versionNum === 130) version = '130';
964 else if (versionNum === 140) version = '140';
965 else if (versionNum === 150) version = '150';
966 else if (versionNum === 330) version = '330';
967 else if (versionNum === 400) version = '400';
968 else if (versionNum === 410) version = '410';
969 else if (versionNum === 420) version = '420';
970 else if (versionNum === 430) version = '430';
971 else if (versionNum === 440) version = '440';
972 else if (versionNum === 450) version = '450';
973 else {
974 throw Error('Unknown GLSL version');
977 } else {
978 throw Error('unexpected token while parsing shader case: ' + m_curTokenStr);
983 advanceToken(Token.TOKEN_END); // case end
986 * no ShaderCase yet?
987 * @param {?string} vert
988 * @param {?string} frag
989 * @param {glsShaderLibraryCase.caseType} type
990 * @return {Object}
992 var getShaderSpec = function(vert, frag, type) {
993 return {
994 /** @type {glsShaderLibraryCase.expectResult} */ expectResult: expectResult,
995 /** @type {glsShaderLibraryCase.caseType} */ caseType: type,
996 /** @type {Array<Object>} */ valueBlockList: valueBlockList,
997 /** @type {string} */ targetVersion: version,
998 /** @type {?string} */ vertexSource: vert,
999 /** @type {?string} */ fragmentSource: frag
1002 getShaderSpec.bind(this);
1004 if (bothSource.length) {
1006 glsShaderLibrary.de_assert(!vertexSource);
1007 glsShaderLibrary.de_assert(!fragmentSource);
1009 shaderNodeList.push(tcuTestCase.newTest(caseName + '_vertex', description, getShaderSpec(bothSource, null,
1010 glsShaderLibraryCase.caseType.CASETYPE_VERTEX_ONLY)));
1011 shaderNodeList.push(tcuTestCase.newTest(caseName + '_fragment', description, getShaderSpec(null, bothSource,
1012 glsShaderLibraryCase.caseType.CASETYPE_FRAGMENT_ONLY)));
1014 } else {
1015 glsShaderLibrary.de_assert(vertexSource);
1016 glsShaderLibrary.de_assert(fragmentSource);
1018 shaderNodeList.push(tcuTestCase.newTest(caseName, description, getShaderSpec(vertexSource, fragmentSource,
1019 glsShaderLibraryCase.caseType.CASETYPE_COMPLETE)));
1024 * @param {Array<tcuTestCase.DeqpTest>} shaderNodeList
1026 var parseShaderGroup = function(shaderNodeList) {
1028 // parse 'case'
1029 advanceToken(Token.TOKEN_GROUP);
1031 /** @type {string}
1032 * parse case name
1033 */ var name = m_curTokenStr;
1034 advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
1036 // Parse description.
1037 assumeToken(Token.TOKEN_STRING);
1038 /** @type {string} */ var description = parseStringLiteral(m_curTokenStr);
1039 advanceToken(Token.TOKEN_STRING);
1041 /** @type {Array<tcuTestCase.DeqpTest>} */ var children = [];
1043 for (;;) {
1045 if (m_curToken === Token.TOKEN_END) {
1046 break;
1047 } else if (m_curToken === Token.TOKEN_GROUP) {
1048 parseShaderGroup(children);
1049 } else if (m_curToken === Token.TOKEN_CASE) {
1050 parseShaderCase(children);
1051 } else {
1052 testFailed('unexpected token while parsing shader group: ' + m_curTokenStr);
1053 tcuTestCase.runner.terminate();
1058 advanceToken(Token.TOKEN_END); // group end
1060 /** @type {tcuTestCase.DeqpTest} */ var groupNode = tcuTestCase.newTest(name, description, null);
1061 groupNode.setChildren(children);
1063 shaderNodeList.push(groupNode);
1067 // uncomment to expose private functions
1068 (function(obj) {
1069 obj.priv = {
1070 m_curPtr: m_curPtr,
1072 parseError: parseError,
1073 parseFloatLiteral: parseFloatLiteral,
1074 parseIntLiteral: parseIntLiteral,
1075 parseStringLiteral: parseStringLiteral,
1076 parseShaderSource: parseShaderSource,
1077 advanceTokenTester: advanceTokenTester,
1078 assumeToken: assumeToken,
1079 mapDataTypeToken: mapDataTypeToken,
1080 getTokenName: getTokenName,
1082 Token: Token,
1084 parseValueElement: parseValueElement,
1085 parseValue: parseValue,
1086 parseValueBlock: parseValueBlock,
1087 parseShaderCase: parseShaderCase,
1088 parseShaderGroup: parseShaderGroup,
1090 none: false
1092 }(this));
1093 //*/
1097 * Parse the test file and execute the test cases
1098 * @param {string} testName Name of the test file (without extension)
1099 * @param {string} filter Optional filter. Common substring of the names of the tests that should be glsShaderLibrary.run.
1101 glsShaderLibrary.run = function(testName, filter) {
1102 WebGLTestUtils.loadTextFileAsync(testName + '.test', function(success, content) {
1103 if (success) {
1104 tcuTestCase.runner.testFile = content;
1105 tcuTestCase.runner.testName = testName;
1106 tcuTestCase.runner.runCallback(glsShaderLibrary.processTestFile);
1107 } else {
1108 testFailed('Failed to load test file: ' + testName);
1109 tcuTestCase.runner.terminate();