summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibrary.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibrary.js1114
1 files changed, 1114 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibrary.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibrary.js
new file mode 100644
index 0000000000..27f86e055c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibrary.js
@@ -0,0 +1,1114 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('modules.shared.glsShaderLibrary');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('modules.shared.glsShaderLibraryCase');
+
+goog.scope(function() {
+
+var glsShaderLibrary = modules.shared.glsShaderLibrary;
+var tcuTestCase = framework.common.tcuTestCase;
+var glsShaderLibraryCase = modules.shared.glsShaderLibraryCase;
+var gluShaderUtil = framework.opengl.gluShaderUtil;
+
+ glsShaderLibrary.generateTestCases = function() {
+ /** @type {glsShaderLibrary.Parser} */ var parser = new glsShaderLibrary.Parser();
+ try {
+ /** @type {Object} */ var state = tcuTestCase.runner;
+ var tree = parser.parse(state.testFile);
+ var rootTest = tcuTestCase.newTest(state.testName, 'Top level');
+ rootTest.setChildren(tree);
+ state.setRoot(rootTest);
+ }
+ catch (err) {
+ bufferedLogToConsole(err);
+ testFailed('Failed to parse shader test case file');
+ return false;
+ }
+ return true;
+ };
+
+ glsShaderLibrary.processTestFile = function() {
+ if (glsShaderLibrary.generateTestCases()) {
+ tcuTestCase.runner.runCallback(glsShaderLibraryCase.runTestCases);
+ } else {
+ tcuTestCase.runner.terminate();
+ }
+ };
+
+ glsShaderLibrary.isWhitespace = function(value) {
+ return /^[ \t\r\n]+$/.test(value);
+ };
+ glsShaderLibrary.isEOL = function(value) {
+ return /^[\r\n]+$/.test(value);
+ };
+ glsShaderLibrary.isAlpha = function(value) {
+ return /^[a-zA-Z]$/.test(value);
+ };
+ glsShaderLibrary.isNumeric = function(value) {
+ return /^[0-9]$/.test(value);
+ };
+ glsShaderLibrary.isCaseNameChar = function(value) {
+ return /^[a-zA-Z0-9_\-\.]$/.test(value);
+ };
+
+ /**
+ * Removes however many indents there are on the first line from all lines.
+ * @param {string} str
+ * @return {string} output
+ */
+ glsShaderLibrary.removeExtraIndentation = function(str) {
+ return glsShaderLibrary.removeExtraIndentationArray(
+ str.split(/\r\n|\r|\n/)
+ ).join('\n');
+ };
+
+ /**
+ * Returns an array of strings without indentation.
+ * @param {Array<string>} arr
+ * @return {Array<string>} output
+ */
+ glsShaderLibrary.removeExtraIndentationArray = function(arr) {
+ /** @type {Array<string>} */ var output = [];
+
+ if (arr.length) {
+
+ /** @type {number} */ var numIndentChars = 0;
+ for (var i = 0; i < arr[0].length && glsShaderLibrary.isWhitespace(arr[0].charAt(i)); ++i) {
+ numIndentChars += arr[0].charAt(i) === '\t' ? 4 : 1;
+ }
+
+ for (var i = 0; i < arr.length; ++i) {
+ /** @type {number} */ var removed = 0;
+ /** @type {number} */ var j;
+ // Some tests are indented inconsistently, so we have to check for non-whitespace characters here.
+ for (j = 0; removed < numIndentChars && j < arr[i].length && glsShaderLibrary.isWhitespace(arr[i].charAt(j)); ++j) {
+ removed += (arr[i].charAt(j) === '\t' ? 4 : 1);
+ }
+
+ output.push(arr[i].substr(j, arr[i].length - j));
+ }
+
+ }
+
+ return output;
+ };
+
+ glsShaderLibrary.de_assert = function(condition) {
+ if (!condition) {
+ throw Error();
+ }
+ };
+
+ /**
+ * @param {string} str
+ * @param {string} endstr end of string character
+ * @param {boolean=} trimFront trim leading whitespace
+ * @return {string} str
+ * @private
+ */
+ glsShaderLibrary.parseStringLiteralHelper = function(str, endstr, trimFront) {
+ trimFront = trimFront || false;
+
+ /** @type {number} */ var index_end = 0;
+ // isolate the string
+ do {
+ index_end = str.indexOf(endstr, index_end + 1);
+ } while (index_end >= 0 && str.charAt(index_end - 1) === '\\');
+
+ if (index_end <= 0) {
+ index_end = str.length;
+ }
+
+ // strip quotes, replace \n and \t with nl and tabs respectively
+ str = str.substr(endstr.length, index_end - endstr.length);
+ if (trimFront)
+ str = str.replace(/^\s*\n/, '');
+ var result = '';
+ var i = 0;
+ while (str[i] != undefined) {
+ if (str[i] == '\\') {
+ switch (str[i + 1]) {
+ case undefined:
+ break;
+ case 'n':
+ result += '\n';
+ break;
+ case 't':
+ result += '\t';
+ break;
+ default:
+ result += str[i + 1];
+ break;
+ }
+ i += 2;
+ } else {
+ result += str[i];
+ i++;
+ }
+ }
+ return result;
+
+ };
+
+ /**
+ * glsShaderLibrary.Parser class
+ * @constructor
+ */
+ glsShaderLibrary.Parser = function() {
+
+ /* data members */
+
+ /**
+ * The Token constants
+ * @enum {number}
+ */
+ var Token = {
+ TOKEN_INVALID: 0,
+ TOKEN_EOF: 1,
+ TOKEN_STRING: 2,
+ TOKEN_SHADER_SOURCE: 3,
+
+ TOKEN_INT_LITERAL: 4,
+ TOKEN_FLOAT_LITERAL: 5,
+
+ // identifiers
+ TOKEN_IDENTIFIER: 6,
+ TOKEN_TRUE: 7,
+ TOKEN_FALSE: 8,
+ TOKEN_DESC: 9,
+ TOKEN_EXPECT: 10,
+ TOKEN_GROUP: 11,
+ TOKEN_CASE: 12,
+ TOKEN_END: 13,
+ TOKEN_VALUES: 14,
+ TOKEN_BOTH: 15,
+ TOKEN_VERTEX: 26,
+ TOKEN_FRAGMENT: 17,
+ TOKEN_UNIFORM: 18,
+ TOKEN_INPUT: 19,
+ TOKEN_OUTPUT: 20,
+ TOKEN_FLOAT: 21,
+ TOKEN_FLOAT_VEC2: 22,
+ TOKEN_FLOAT_VEC3: 23,
+ TOKEN_FLOAT_VEC4: 24,
+ TOKEN_FLOAT_MAT2: 25,
+ TOKEN_FLOAT_MAT2X3: 26,
+ TOKEN_FLOAT_MAT2X4: 27,
+ TOKEN_FLOAT_MAT3X2: 28,
+ TOKEN_FLOAT_MAT3: 29,
+ TOKEN_FLOAT_MAT3X4: 30,
+ TOKEN_FLOAT_MAT4X2: 31,
+ TOKEN_FLOAT_MAT4X3: 32,
+ TOKEN_FLOAT_MAT4: 33,
+ TOKEN_INT: 34,
+ TOKEN_INT_VEC2: 35,
+ TOKEN_INT_VEC3: 36,
+ TOKEN_INT_VEC4: 37,
+ TOKEN_UINT: 38,
+ TOKEN_UINT_VEC2: 39,
+ TOKEN_UINT_VEC3: 40,
+ TOKEN_UINT_VEC4: 41,
+ TOKEN_BOOL: 42,
+ TOKEN_BOOL_VEC2: 43,
+ TOKEN_BOOL_VEC3: 44,
+ TOKEN_BOOL_VEC4: 45,
+ TOKEN_VERSION: 46,
+
+ // symbols
+ TOKEN_ASSIGN: 47,
+ TOKEN_PLUS: 48,
+ TOKEN_MINUS: 49,
+ TOKEN_COMMA: 50,
+ TOKEN_VERTICAL_BAR: 51,
+ TOKEN_SEMI_COLON: 52,
+ TOKEN_LEFT_PAREN: 53,
+ TOKEN_RIGHT_PAREN: 54,
+ TOKEN_LEFT_BRACKET: 55,
+ TOKEN_RIGHT_BRACKET: 56,
+ TOKEN_LEFT_BRACE: 57,
+ TOKEN_RIGHT_BRACE: 58,
+
+ TOKEN_LAST: 59
+ };
+
+ /** @type {string} */ var m_input = '';
+ /** @type {number} */ var m_curPtr = 0;
+ /** @type {number} */ var m_curToken;// = Token.TOKEN_INVALID;
+ /** @type {string} */ var m_curTokenStr = '';
+
+ /* function members */
+ this.parse = function(input) {
+
+ // initialise parser
+ m_input = input;
+ m_curPtr = 0;
+ m_curToken = Token.TOKEN_INVALID;
+ m_curTokenStr = '';
+ advanceToken();
+
+ /** @type {Array<tcuTestCase.DeqpTest>} */ var nodeList = [];
+
+ for (;;) {
+
+ if (m_curToken === Token.TOKEN_CASE) {
+ parseShaderCase(nodeList);
+ } else if (m_curToken === Token.TOKEN_GROUP) {
+ parseShaderGroup(nodeList);
+ } else if (m_curToken === Token.TOKEN_EOF) {
+ break;
+ } else {
+ // throw Error("invalid token encountered at main level: '" + m_curTokenStr + "'");
+ testFailed("invalid token encountered at main level: '" + m_curTokenStr + "'");
+ tcuTestCase.runner.terminate();
+ }
+
+ }
+
+ return nodeList;
+
+ };
+
+ /**
+ * ensures that the token exists
+ * otherwise it returns the corresponding token's name depending on enum number value
+ * @param {number} id
+ * @return {string} name
+ */
+ var resolveTokenName = function(id) {
+ for (var name in Token) {
+ if (Token[name] === id) return name;
+ }
+ return 'TOKEN_UNKNOWN';
+ };
+
+ /**
+ * Throws an error which contains the passed string
+ * @param {string} errorStr that contains an error to notify
+ * @return {string} error
+ */
+ var parseError = function(errorStr) {
+ // abort
+ throw 'glsShaderLibrary.Parser error: ' + errorStr + ' near ' + m_input.substr(m_curPtr, m_curPtr + 80);
+ };
+
+ /**
+ * Converts string into float
+ * @param {string} str
+ * @return {number}
+ */
+ var parseFloatLiteral = function(str) {
+ return parseFloat(str);
+ };
+
+ /**
+ * Converts string into integer
+ * @param {string} str
+ * @return {number}
+ */
+ var parseIntLiteral = function(str) {
+ return parseInt(str, 10);
+ };
+ var parseStringLiteral = function(str) {
+ /**
+ * @type {string}
+ * find delimitor
+ */ var endchar = str.substr(0, 1);
+ return glsShaderLibrary.parseStringLiteralHelper(str, endchar);
+ };
+ var parseShaderSource = function(str) {
+ // similar to parse literal, delimitors are two double quotes ("")
+ return glsShaderLibrary.removeExtraIndentation(
+ glsShaderLibrary.parseStringLiteralHelper(str, '""', true)
+ );
+ };
+
+ var advanceTokenWorker = function() {
+
+ // Skip old token
+ m_curPtr += m_curTokenStr.length;
+
+ // Reset token (for safety).
+ m_curToken = Token.TOKEN_INVALID;
+ m_curTokenStr = '';
+
+ // Eat whitespace & comments while they last.
+ for (;;) {
+
+ while (glsShaderLibrary.isWhitespace(m_input.charAt(m_curPtr))) ++m_curPtr;
+
+ // check for EOL comment
+ if (m_input.charAt(m_curPtr) === '#') {
+ // if m_input is to be an array of lines then this probably wont work very well
+ while (
+ m_curPtr < m_input.length &&
+ !glsShaderLibrary.isEOL(m_input.charAt(m_curPtr))
+ ) ++m_curPtr;
+ } else {
+ break;
+ }
+
+ }
+
+ if (m_curPtr >= m_input.length) {
+
+ m_curToken = Token.TOKEN_EOF;
+ m_curTokenStr = '<EOF>';
+
+ } else if (glsShaderLibrary.isAlpha(m_input.charAt(m_curPtr))) {
+
+ /** @type {number} */ var end = m_curPtr + 1;
+ while (glsShaderLibrary.isCaseNameChar(m_input.charAt(end))) ++end;
+
+ m_curTokenStr = m_input.substr(m_curPtr, end - m_curPtr);
+
+ m_curToken = (function() {
+ // consider reimplementing with a binary search
+ switch (m_curTokenStr) {
+ case 'true': return Token.TOKEN_TRUE;
+ case 'false': return Token.TOKEN_FALSE;
+ case 'desc': return Token.TOKEN_DESC;
+ case 'expect': return Token.TOKEN_EXPECT;
+ case 'group': return Token.TOKEN_GROUP;
+ case 'case': return Token.TOKEN_CASE;
+ case 'end': return Token.TOKEN_END;
+ case 'values': return Token.TOKEN_VALUES;
+ case 'both': return Token.TOKEN_BOTH;
+ case 'vertex': return Token.TOKEN_VERTEX;
+ case 'fragment': return Token.TOKEN_FRAGMENT;
+ case 'uniform': return Token.TOKEN_UNIFORM;
+ case 'input': return Token.TOKEN_INPUT;
+ case 'output': return Token.TOKEN_OUTPUT;
+ case 'float': return Token.TOKEN_FLOAT;
+ case 'vec2': return Token.TOKEN_FLOAT_VEC2;
+ case 'vec3': return Token.TOKEN_FLOAT_VEC3;
+ case 'vec4': return Token.TOKEN_FLOAT_VEC4;
+ case 'mat2': return Token.TOKEN_FLOAT_MAT2;
+ case 'mat2x3': return Token.TOKEN_FLOAT_MAT2X3;
+ case 'mat2x4': return Token.TOKEN_FLOAT_MAT2X4;
+ case 'mat3x2': return Token.TOKEN_FLOAT_MAT3X2;
+ case 'mat3': return Token.TOKEN_FLOAT_MAT3;
+ case 'mat3x4': return Token.TOKEN_FLOAT_MAT3X4;
+ case 'mat4x2': return Token.TOKEN_FLOAT_MAT4X2;
+ case 'mat4x3': return Token.TOKEN_FLOAT_MAT4X3;
+ case 'mat4': return Token.TOKEN_FLOAT_MAT4;
+ case 'int': return Token.TOKEN_INT;
+ case 'ivec2': return Token.TOKEN_INT_VEC2;
+ case 'ivec3': return Token.TOKEN_INT_VEC3;
+ case 'ivec4': return Token.TOKEN_INT_VEC4;
+ case 'uint': return Token.TOKEN_UINT;
+ case 'uvec2': return Token.TOKEN_UINT_VEC2;
+ case 'uvec3': return Token.TOKEN_UINT_VEC3;
+ case 'uvec4': return Token.TOKEN_UINT_VEC4;
+ case 'bool': return Token.TOKEN_BOOL;
+ case 'bvec2': return Token.TOKEN_BOOL_VEC2;
+ case 'bvec3': return Token.TOKEN_BOOL_VEC3;
+ case 'bvec4': return Token.TOKEN_BOOL_VEC4;
+ case 'version': return Token.TOKEN_VERSION;
+ default: return Token.TOKEN_IDENTIFIER;
+ }
+ }());
+
+ } else if (glsShaderLibrary.isNumeric(m_input.charAt(m_curPtr))) {
+
+ /** @type {number} */ var p = m_curPtr;
+ while (glsShaderLibrary.isNumeric(m_input.charAt(p))) ++p;
+
+ if (m_input.charAt(p) === '.') { // float
+
+ ++p;
+ while (glsShaderLibrary.isNumeric(m_input.charAt(p))) ++p;
+
+ if (m_input.charAt(p) === 'e' || m_input.charAt(p) === 'E') {
+
+ ++p;
+ if (m_input.charAt(p) === '+' || m_input.charAt(p) === '-') ++p;
+
+ glsShaderLibrary.de_assert(p < m_input.length && glsShaderLibrary.isNumeric(m_input.charAt(p)));
+ while (glsShaderLibrary.isNumeric(m_input.charAt(p))) ++p;
+
+ }
+
+ m_curToken = Token.TOKEN_FLOAT_LITERAL;
+ m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
+
+ } else {
+
+ m_curToken = Token.TOKEN_INT_LITERAL;
+ m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
+
+ }
+
+ } else if (m_input.charAt(m_curPtr) === '"' && m_input.charAt(m_curPtr + 1) === '"') { // shader source
+
+ var p = m_curPtr + 2;
+
+ while (m_input.charAt(p) != '"' || m_input.charAt(p + 1) != '"') {
+ glsShaderLibrary.de_assert(p < m_input.length);
+ if (m_input.charAt(p) === '\\') {
+ glsShaderLibrary.de_assert(p + 1 < m_input.length);
+ p += 2;
+ } else {
+ ++p;
+ }
+ }
+ p += 2;
+
+ m_curToken = Token.TOKEN_SHADER_SOURCE;
+ m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
+
+ } else if (m_input.charAt(m_curPtr) === '"' || m_input.charAt(m_curPtr) === "'") {
+
+ /** @type {string} */ var delimitor = m_input.charAt(m_curPtr);
+ var p = m_curPtr + 1;
+
+ while (m_input.charAt(p) != delimitor) {
+
+ glsShaderLibrary.de_assert(p < m_input.length);
+ if (m_input.charAt(p) === '\\') {
+ glsShaderLibrary.de_assert(p + 1 < m_input.length);
+ p += 2;
+ } else {
+ ++p;
+ }
+
+ }
+ ++p;
+
+ m_curToken = Token.TOKEN_STRING;
+ m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
+
+ } else {
+
+ m_curTokenStr = m_input.charAt(m_curPtr);
+ m_curToken = (function() {
+ // consider reimplementing with a binary search
+ switch (m_curTokenStr) {
+ case '=': return Token.TOKEN_ASSIGN;
+ case '+': return Token.TOKEN_PLUS;
+ case '-': return Token.TOKEN_MINUS;
+ case ',': return Token.TOKEN_COMMA;
+ case '|': return Token.TOKEN_VERTICAL_BAR;
+ case ';': return Token.TOKEN_SEMI_COLON;
+ case '(': return Token.TOKEN_LEFT_PAREN;
+ case ')': return Token.TOKEN_RIGHT_PAREN;
+ case '[': return Token.TOKEN_LEFT_BRACKET;
+ case ']': return Token.TOKEN_RIGHT_BRACKET;
+ case '{': return Token.TOKEN_LEFT_BRACE;
+ case '}': return Token.TOKEN_RIGHT_BRACE;
+
+ default: return Token.TOKEN_INVALID;
+ }
+ }());
+
+ }
+
+ };
+
+ /**
+ * @return {Object.<number, string, string>}
+ */
+ var advanceTokenTester = function(input, current_index) {
+ m_input = input;
+ m_curPtr = current_index;
+ m_curTokenStr = '';
+ advanceTokenWorker();
+ return {
+ /** @type {number} */ idType: m_curToken,
+ /** @type {string} */ name: resolveTokenName(m_curToken),
+ /** @type {string} */ value: m_curTokenStr
+ };
+ };
+
+ /**
+ * @param {Token=} tokenAssumed
+ */
+ var advanceToken = function(tokenAssumed) {
+ if (typeof(tokenAssumed) !== 'undefined') {
+ assumeToken(tokenAssumed);
+ }
+ advanceTokenWorker();
+ };
+ var assumeToken = function(token) {
+
+ if (m_curToken != token) {
+ // parse error
+ /** @type {string} */ var msg = "unexpected token '" + m_curTokenStr + "', expecting '" + getTokenName(token) + "'";
+ throw Error('Parse Error. ' + msg + ' near ' + m_curPtr + ' ...');
+ }
+ };
+ var mapDataTypeToken = function(token) {
+ switch (token) {
+ case Token.TOKEN_FLOAT: return gluShaderUtil.DataType.FLOAT;
+ case Token.TOKEN_FLOAT_VEC2: return gluShaderUtil.DataType.FLOAT_VEC2;
+ case Token.TOKEN_FLOAT_VEC3: return gluShaderUtil.DataType.FLOAT_VEC3;
+ case Token.TOKEN_FLOAT_VEC4: return gluShaderUtil.DataType.FLOAT_VEC4;
+ case Token.TOKEN_FLOAT_MAT2: return gluShaderUtil.DataType.FLOAT_MAT2;
+ case Token.TOKEN_FLOAT_MAT2X3: return gluShaderUtil.DataType.FLOAT_MAT2X3;
+ case Token.TOKEN_FLOAT_MAT2X4: return gluShaderUtil.DataType.FLOAT_MAT2X4;
+ case Token.TOKEN_FLOAT_MAT3X2: return gluShaderUtil.DataType.FLOAT_MAT3X2;
+ case Token.TOKEN_FLOAT_MAT3: return gluShaderUtil.DataType.FLOAT_MAT3;
+ case Token.TOKEN_FLOAT_MAT3X4: return gluShaderUtil.DataType.FLOAT_MAT3X4;
+ case Token.TOKEN_FLOAT_MAT4X2: return gluShaderUtil.DataType.FLOAT_MAT4X2;
+ case Token.TOKEN_FLOAT_MAT4X3: return gluShaderUtil.DataType.FLOAT_MAT4X3;
+ case Token.TOKEN_FLOAT_MAT4: return gluShaderUtil.DataType.FLOAT_MAT4;
+ case Token.TOKEN_INT: return gluShaderUtil.DataType.INT;
+ case Token.TOKEN_INT_VEC2: return gluShaderUtil.DataType.INT_VEC2;
+ case Token.TOKEN_INT_VEC3: return gluShaderUtil.DataType.INT_VEC3;
+ case Token.TOKEN_INT_VEC4: return gluShaderUtil.DataType.INT_VEC4;
+ case Token.TOKEN_UINT: return gluShaderUtil.DataType.UINT;
+ case Token.TOKEN_UINT_VEC2: return gluShaderUtil.DataType.UINT_VEC2;
+ case Token.TOKEN_UINT_VEC3: return gluShaderUtil.DataType.UINT_VEC3;
+ case Token.TOKEN_UINT_VEC4: return gluShaderUtil.DataType.UINT_VEC4;
+ case Token.TOKEN_BOOL: return gluShaderUtil.DataType.BOOL;
+ case Token.TOKEN_BOOL_VEC2: return gluShaderUtil.DataType.BOOL_VEC2;
+ case Token.TOKEN_BOOL_VEC3: return gluShaderUtil.DataType.BOOL_VEC3;
+ case Token.TOKEN_BOOL_VEC4: return gluShaderUtil.DataType.BOOL_VEC4;
+ default: return gluShaderUtil.DataType.INVALID;
+ }
+ };
+
+ /**
+ * Returns the corresponding token's name depending on enum number value
+ * @param {number} token
+ * @return {string}
+ */
+ var getTokenName = function(token) {
+ switch (token) {
+ case Token.TOKEN_INVALID: return '<invalid>';
+ case Token.TOKEN_EOF: return '<eof>';
+ case Token.TOKEN_STRING: return '<string>';
+ case Token.TOKEN_SHADER_SOURCE: return 'source';
+
+ case Token.TOKEN_INT_LITERAL: return '<int>';
+ case Token.TOKEN_FLOAT_LITERAL: return '<float>';
+
+ // identifiers
+ case Token.TOKEN_IDENTIFIER: return '<identifier>';
+ case Token.TOKEN_TRUE: return 'true';
+ case Token.TOKEN_FALSE: return 'false';
+ case Token.TOKEN_DESC: return 'desc';
+ case Token.TOKEN_EXPECT: return 'expect';
+ case Token.TOKEN_GROUP: return 'group';
+ case Token.TOKEN_CASE: return 'case';
+ case Token.TOKEN_END: return 'end';
+ case Token.TOKEN_VALUES: return 'values';
+ case Token.TOKEN_BOTH: return 'both';
+ case Token.TOKEN_VERTEX: return 'vertex';
+ case Token.TOKEN_FRAGMENT: return 'fragment';
+ case Token.TOKEN_UNIFORM: return 'uniform';
+ case Token.TOKEN_INPUT: return 'input';
+ case Token.TOKEN_OUTPUT: return 'output';
+ case Token.TOKEN_FLOAT: return 'float';
+ case Token.TOKEN_FLOAT_VEC2: return 'vec2';
+ case Token.TOKEN_FLOAT_VEC3: return 'vec3';
+ case Token.TOKEN_FLOAT_VEC4: return 'vec4';
+ case Token.TOKEN_FLOAT_MAT2: return 'mat2';
+ case Token.TOKEN_FLOAT_MAT2X3: return 'mat2x3';
+ case Token.TOKEN_FLOAT_MAT2X4: return 'mat2x4';
+ case Token.TOKEN_FLOAT_MAT3X2: return 'mat3x2';
+ case Token.TOKEN_FLOAT_MAT3: return 'mat3';
+ case Token.TOKEN_FLOAT_MAT3X4: return 'mat3x4';
+ case Token.TOKEN_FLOAT_MAT4X2: return 'mat4x2';
+ case Token.TOKEN_FLOAT_MAT4X3: return 'mat4x3';
+ case Token.TOKEN_FLOAT_MAT4: return 'mat4';
+ case Token.TOKEN_INT: return 'int';
+ case Token.TOKEN_INT_VEC2: return 'ivec2';
+ case Token.TOKEN_INT_VEC3: return 'ivec3';
+ case Token.TOKEN_INT_VEC4: return 'ivec4';
+ case Token.TOKEN_UINT: return 'uint';
+ case Token.TOKEN_UINT_VEC2: return 'uvec2';
+ case Token.TOKEN_UINT_VEC3: return 'uvec3';
+ case Token.TOKEN_UINT_VEC4: return 'uvec4';
+ case Token.TOKEN_BOOL: return 'bool';
+ case Token.TOKEN_BOOL_VEC2: return 'bvec2';
+ case Token.TOKEN_BOOL_VEC3: return 'bvec3';
+ case Token.TOKEN_BOOL_VEC4: return 'bvec4';
+
+ case Token.TOKEN_ASSIGN: return '=';
+ case Token.TOKEN_PLUS: return '+';
+ case Token.TOKEN_MINUS: return '-';
+ case Token.TOKEN_COMMA: return ',';
+ case Token.TOKEN_VERTICAL_BAR: return '|';
+ case Token.TOKEN_SEMI_COLON: return ';';
+ case Token.TOKEN_LEFT_PAREN: return '(';
+ case Token.TOKEN_RIGHT_PAREN: return ')';
+ case Token.TOKEN_LEFT_BRACKET: return '[';
+ case Token.TOKEN_RIGHT_BRACKET: return ']';
+ case Token.TOKEN_LEFT_BRACE: return ' {';
+ case Token.TOKEN_RIGHT_BRACE: return '}';
+
+ default: return '<unknown>';
+ }
+ };
+
+ /**
+ * @param {?gluShaderUtil.DataType} expectedDataType
+ * @param {Object} result
+ */
+ var parseValueElement = function(expectedDataType, result) {
+ /** @type {?string} */ var scalarType = null;
+ /** @type {number} */ var scalarSize = 0;
+ if (expectedDataType) {
+ scalarType = gluShaderUtil.getDataTypeScalarType(expectedDataType);
+ scalarSize = gluShaderUtil.getDataTypeScalarSize(expectedDataType);
+ }
+
+ /** @type {Array<number>} */ var elems = [];
+
+ if (scalarSize > 1) {
+ glsShaderLibrary.de_assert(mapDataTypeToken(m_curToken) === expectedDataType);
+ advanceToken(); // data type(float, vec2, etc.)
+ advanceToken(Token.TOKEN_LEFT_PAREN);
+ }
+
+ for (var i = 0; i < scalarSize; ++i) {
+ if (scalarType === 'float') {
+
+ /** @type {number} */ var signMult = 1.0;
+ if (m_curToken === Token.TOKEN_MINUS) {
+ signMult = -1.0;
+ advanceToken();
+ }
+
+ assumeToken(Token.TOKEN_FLOAT_LITERAL);
+ elems.push(signMult * parseFloatLiteral(m_curTokenStr));
+ advanceToken(Token.TOKEN_FLOAT_LITERAL);
+
+ } else if (scalarType === 'int' || scalarType === 'uint') {
+
+ var signMult = 1;
+ if (m_curToken === Token.TOKEN_MINUS) {
+ signMult = -1;
+ advanceToken();
+ }
+
+ assumeToken(Token.TOKEN_INT_LITERAL);
+ elems.push(signMult * parseIntLiteral(m_curTokenStr));
+ advanceToken(Token.TOKEN_INT_LITERAL);
+
+ } else {
+
+ glsShaderLibrary.de_assert(scalarType === 'bool');
+ elems.push(m_curToken === Token.TOKEN_TRUE);
+ if (m_curToken != Token.TOKEN_TRUE && m_curToken != Token.TOKEN_FALSE) {
+ throw Error('unexpected token, expecting bool: ' + m_curTokenStr);
+ }
+ advanceToken(); // true/false
+
+ }
+
+ if (i != (scalarSize - 1)) {
+ advanceToken(Token.TOKEN_COMMA);
+ }
+ }
+
+ if (scalarSize > 1) {
+ advanceToken(Token.TOKEN_RIGHT_PAREN);
+ }
+
+ for (var i = 0; i < elems.length; i++)
+ result.elements.push(elems[i]);
+
+ };
+
+ /**
+ * @param {Object.<Array, number>} valueBlock
+ */
+ var parseValue = function(valueBlock) {
+
+ /**
+ * @type {Object}
+ */
+ var result = {
+ /** @type {?gluShaderUtil.DataType} */ dataType: null,
+ /** @type {?glsShaderLibraryCase.shaderCase} */ storageType: null,
+ /** @type {?string} */ valueName: null,
+ /** @type {Array} */ elements: []
+ };
+
+ // parse storage
+ switch (m_curToken) {
+ case Token.TOKEN_UNIFORM:
+ result.storageType = glsShaderLibraryCase.shaderCase.STORAGE_UNIFORM;
+ break;
+ case Token.TOKEN_INPUT:
+ result.storageType = glsShaderLibraryCase.shaderCase.STORAGE_INPUT;
+ break;
+ case Token.TOKEN_OUTPUT:
+ result.storageType = glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT;
+ break;
+ default:
+ throw Error('unexpected token encountered when parsing value classifier');
+ break;
+ }
+ advanceToken();
+
+ // parse data type
+ result.dataType = mapDataTypeToken(m_curToken);
+ if (result.dataType === gluShaderUtil.DataType.INVALID) {
+ throw Error('unexpected token when parsing value data type: ' + m_curTokenStr);
+ }
+ advanceToken();
+
+ // parse value name
+ if (m_curToken === Token.TOKEN_IDENTIFIER) {
+ result.valueName = m_curTokenStr;
+ } else if (m_curToken === Token.TOKEN_STRING) {
+ result.valueName = parseStringLiteral(m_curTokenStr);
+ } else {
+ throw Error('unexpected token when parsing value name: ' + m_curTokenStr);
+ }
+ advanceToken();
+
+ // parse assignment operator.
+ advanceToken(Token.TOKEN_ASSIGN);
+
+ // parse actual value
+ if (m_curToken === Token.TOKEN_LEFT_BRACKET) { // value list
+ advanceToken(Token.TOKEN_LEFT_BRACKET);
+ result.arrayLength = 0;
+
+ for (;;) {
+ parseValueElement(result.dataType, result);
+ result.arrayLength += 1;
+
+ if (m_curToken === Token.TOKEN_RIGHT_BRACKET) {
+ break;
+ } else if (m_curToken === Token.TOKEN_VERTICAL_BAR) { // pipe?
+ advanceToken();
+ continue;
+ } else {
+ throw Error('unexpected token in value element array: ' + m_curTokenStr);
+ }
+ }
+
+ advanceToken(Token.TOKEN_RIGHT_BRACKET);
+
+ } else { // arrays, single elements
+ parseValueElement(result.dataType, result);
+ result.arrayLength = 1;
+ }
+
+ advanceToken(Token.TOKEN_SEMI_COLON);
+
+ valueBlock.values.push(result);
+
+ };
+
+ /**
+ * @param {Object.<Array, number>} valueBlock
+ */
+ var parseValueBlock = function(valueBlock) {
+
+ advanceToken(Token.TOKEN_VALUES);
+ advanceToken(Token.TOKEN_LEFT_BRACE);
+
+ for (;;) {
+ if (
+ m_curToken === Token.TOKEN_UNIFORM ||
+ m_curToken === Token.TOKEN_INPUT ||
+ m_curToken === Token.TOKEN_OUTPUT
+ ) {
+ parseValue(valueBlock);
+ } else if (m_curToken === Token.TOKEN_RIGHT_BRACE) {
+ break;
+ } else {
+ throw Error('unexpected( token when parsing a value block: ' + m_curTokenStr);
+ }
+ }
+
+ advanceToken(Token.TOKEN_RIGHT_BRACE);
+
+ /** @type {number} */ var arrayLength = 1;
+ // compute combined array length of value block.
+ for (var i = 0; i < valueBlock.values.length; ++i) {
+ if (valueBlock.values[i].arrayLength > 1) {
+ glsShaderLibrary.de_assert(arrayLength === 1 || arrayLength === valueBlock.values[i].arrayLength);
+ arrayLength = valueBlock.values[i].arrayLength;
+ }
+ }
+
+ valueBlock.arrayLength = arrayLength;
+
+ };
+
+ /**
+ * @param {Array<tcuTestCase.DeqpTest>} shaderNodeList
+ */
+ var parseShaderCase = function(shaderNodeList) {
+
+ // parse case
+ advanceToken(Token.TOKEN_CASE);
+
+ /**
+ * @type {string}
+ * parse case name
+ */
+ var caseName = m_curTokenStr;
+ advanceToken(); // \note [pyry] All token types are allowed here.
+
+ /**
+ * @type {Array<Object>}
+ * setup case
+ */
+ var valueBlockList = [];
+
+ /** TODO: Should the default version be defined elsewhere? */
+ /** @type {string} */ var version = '100';
+ /** @type {number} */ var expectResult = glsShaderLibraryCase.expectResult.EXPECT_PASS;
+ /** @type {string} */ var description;
+ /** @type {string} */ var bothSource = '';
+ /** @type {string} */ var vertexSource = '';
+ /** @type {string} */ var fragmentSource = '';
+
+ for (;;) {
+
+ if (m_curToken === Token.TOKEN_END) {
+
+ break;
+
+ } else if (m_curToken === Token.TOKEN_DESC) {
+
+ advanceToken();
+ assumeToken(Token.TOKEN_STRING);
+
+ description = parseStringLiteral(m_curTokenStr);
+ advanceToken();
+
+ } else if (m_curToken === Token.TOKEN_EXPECT) {
+
+ advanceToken();
+ assumeToken(Token.TOKEN_IDENTIFIER);
+
+ expectResult = (function(token) {
+ switch (token) {
+ case 'pass': return glsShaderLibraryCase.expectResult.EXPECT_PASS;
+ case 'compile_fail': return glsShaderLibraryCase.expectResult.EXPECT_COMPILE_FAIL;
+ case 'link_fail': return glsShaderLibraryCase.expectResult.EXPECT_LINK_FAIL;
+ case 'compile_or_link_fail': return glsShaderLibraryCase.expectResult.EXPECT_COMPILE_LINK_FAIL;
+ case 'build_successful': return glsShaderLibraryCase.expectResult.EXPECT_BUILD_SUCCESSFUL;
+ default:
+ throw Error('invalid expected result value: ' + m_curTokenStr);
+ }
+ }(m_curTokenStr));
+
+ advanceToken();
+
+ } else if (m_curToken === Token.TOKEN_VALUES) {
+
+ /** @type {Object.<Array, number>} */ var block = glsShaderLibraryCase.genValueBlock();
+ parseValueBlock(block);
+ valueBlockList.push(block);
+
+ } else if (
+ m_curToken === Token.TOKEN_BOTH ||
+ m_curToken === Token.TOKEN_VERTEX ||
+ m_curToken === Token.TOKEN_FRAGMENT
+ ) {
+
+ /** @type {number} */ var token = m_curToken;
+ advanceToken();
+ assumeToken(Token.TOKEN_SHADER_SOURCE);
+ /** @type {string} */ var source = parseShaderSource(m_curTokenStr);
+
+ advanceToken();
+ switch (token) {
+ case Token.TOKEN_BOTH: bothSource = source; break;
+ case Token.TOKEN_VERTEX: vertexSource = source; break;
+ case Token.TOKEN_FRAGMENT: fragmentSource = source; break;
+ default: glsShaderLibrary.de_assert(false); break;
+ }
+
+ } else if (m_curToken === Token.TOKEN_VERSION) {
+
+ advanceToken();
+
+ /** @type {number} */ var versionNum = 0;
+ /** @type {string} */ var postfix = '';
+
+ assumeToken(Token.TOKEN_INT_LITERAL);
+ versionNum = parseIntLiteral(m_curTokenStr);
+ advanceToken();
+
+ if (m_curToken === Token.TOKEN_IDENTIFIER) {
+ postfix = m_curTokenStr;
+ advanceToken();
+ }
+
+ // TODO: need to fix these constants, we dont have glu
+ if (versionNum === 100 && postfix === 'es') version = '100';
+ else if (versionNum === 300 && postfix === 'es') version = '300 es';
+ else if (versionNum === 310 && postfix === 'es') version = '310 es';
+ else if (versionNum === 130) version = '130';
+ else if (versionNum === 140) version = '140';
+ else if (versionNum === 150) version = '150';
+ else if (versionNum === 330) version = '330';
+ else if (versionNum === 400) version = '400';
+ else if (versionNum === 410) version = '410';
+ else if (versionNum === 420) version = '420';
+ else if (versionNum === 430) version = '430';
+ else if (versionNum === 440) version = '440';
+ else if (versionNum === 450) version = '450';
+ else {
+ throw Error('Unknown GLSL version');
+ }
+
+ } else {
+ throw Error('unexpected token while parsing shader case: ' + m_curTokenStr);
+ }
+
+ }
+
+ advanceToken(Token.TOKEN_END); // case end
+
+ /**
+ * no ShaderCase yet?
+ * @param {?string} vert
+ * @param {?string} frag
+ * @param {glsShaderLibraryCase.caseType} type
+ * @return {Object}
+ */
+ var getShaderSpec = function(vert, frag, type) {
+ return {
+ /** @type {glsShaderLibraryCase.expectResult} */ expectResult: expectResult,
+ /** @type {glsShaderLibraryCase.caseType} */ caseType: type,
+ /** @type {Array<Object>} */ valueBlockList: valueBlockList,
+ /** @type {string} */ targetVersion: version,
+ /** @type {?string} */ vertexSource: vert,
+ /** @type {?string} */ fragmentSource: frag
+ };
+ };
+ getShaderSpec.bind(this);
+
+ if (bothSource.length) {
+
+ glsShaderLibrary.de_assert(!vertexSource);
+ glsShaderLibrary.de_assert(!fragmentSource);
+
+ shaderNodeList.push(tcuTestCase.newTest(caseName + '_vertex', description, getShaderSpec(bothSource, null,
+ glsShaderLibraryCase.caseType.CASETYPE_VERTEX_ONLY)));
+ shaderNodeList.push(tcuTestCase.newTest(caseName + '_fragment', description, getShaderSpec(null, bothSource,
+ glsShaderLibraryCase.caseType.CASETYPE_FRAGMENT_ONLY)));
+
+ } else {
+ glsShaderLibrary.de_assert(vertexSource);
+ glsShaderLibrary.de_assert(fragmentSource);
+
+ shaderNodeList.push(tcuTestCase.newTest(caseName, description, getShaderSpec(vertexSource, fragmentSource,
+ glsShaderLibraryCase.caseType.CASETYPE_COMPLETE)));
+ }
+ };
+
+ /**
+ * @param {Array<tcuTestCase.DeqpTest>} shaderNodeList
+ */
+ var parseShaderGroup = function(shaderNodeList) {
+
+ // parse 'case'
+ advanceToken(Token.TOKEN_GROUP);
+
+ /** @type {string}
+ * parse case name
+ */ var name = m_curTokenStr;
+ advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
+
+ // Parse description.
+ assumeToken(Token.TOKEN_STRING);
+ /** @type {string} */ var description = parseStringLiteral(m_curTokenStr);
+ advanceToken(Token.TOKEN_STRING);
+
+ /** @type {Array<tcuTestCase.DeqpTest>} */ var children = [];
+
+ for (;;) {
+
+ if (m_curToken === Token.TOKEN_END) {
+ break;
+ } else if (m_curToken === Token.TOKEN_GROUP) {
+ parseShaderGroup(children);
+ } else if (m_curToken === Token.TOKEN_CASE) {
+ parseShaderCase(children);
+ } else {
+ testFailed('unexpected token while parsing shader group: ' + m_curTokenStr);
+ tcuTestCase.runner.terminate();
+ }
+
+ }
+
+ advanceToken(Token.TOKEN_END); // group end
+
+ /** @type {tcuTestCase.DeqpTest} */ var groupNode = tcuTestCase.newTest(name, description, null);
+ groupNode.setChildren(children);
+
+ shaderNodeList.push(groupNode);
+
+ };
+
+ // uncomment to expose private functions
+ (function(obj) {
+ obj.priv = {
+ m_curPtr: m_curPtr,
+
+ parseError: parseError,
+ parseFloatLiteral: parseFloatLiteral,
+ parseIntLiteral: parseIntLiteral,
+ parseStringLiteral: parseStringLiteral,
+ parseShaderSource: parseShaderSource,
+ advanceTokenTester: advanceTokenTester,
+ assumeToken: assumeToken,
+ mapDataTypeToken: mapDataTypeToken,
+ getTokenName: getTokenName,
+
+ Token: Token,
+
+ parseValueElement: parseValueElement,
+ parseValue: parseValue,
+ parseValueBlock: parseValueBlock,
+ parseShaderCase: parseShaderCase,
+ parseShaderGroup: parseShaderGroup,
+
+ none: false
+ };
+ }(this));
+ //*/
+ };
+
+/**
+ * Parse the test file and execute the test cases
+ * @param {string} testName Name of the test file (without extension)
+ * @param {string} filter Optional filter. Common substring of the names of the tests that should be glsShaderLibrary.run.
+ */
+glsShaderLibrary.run = function(testName, filter) {
+ WebGLTestUtils.loadTextFileAsync(testName + '.test', function(success, content) {
+ if (success) {
+ tcuTestCase.runner.testFile = content;
+ tcuTestCase.runner.testName = testName;
+ tcuTestCase.runner.runCallback(glsShaderLibrary.processTestFile);
+ } else {
+ testFailed('Failed to load test file: ' + testName);
+ tcuTestCase.runner.terminate();
+ }
+ });
+};
+
+});