glsShaderLibraryCase.js (51318B)
1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES Utilities 3 * ------------------------------------------------ 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 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 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 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. 18 * 19 */ 20 21 'use strict'; 22 goog.provide('modules.shared.glsShaderLibraryCase'); 23 goog.require('framework.common.tcuTestCase'); 24 goog.require('framework.opengl.gluDrawUtil'); 25 goog.require('framework.opengl.gluShaderProgram'); 26 goog.require('framework.opengl.gluShaderUtil'); 27 28 goog.scope(function() { 29 30 var glsShaderLibraryCase = modules.shared.glsShaderLibraryCase; 31 var tcuTestCase = framework.common.tcuTestCase; 32 var gluShaderProgram = framework.opengl.gluShaderProgram; 33 var gluShaderUtil = framework.opengl.gluShaderUtil; 34 var gluDrawUtil = framework.opengl.gluDrawUtil; 35 36 /** @const @type {number} */ glsShaderLibraryCase.VIEWPORT_WIDTH = 128; 37 /** @const @type {number} */ glsShaderLibraryCase.VIEWPORT_HEIGHT = 128; 38 39 /** 40 * Shader compilation expected result enum 41 * @enum {number} 42 */ 43 glsShaderLibraryCase.expectResult = { 44 EXPECT_PASS: 0, 45 EXPECT_COMPILE_FAIL: 1, 46 EXPECT_LINK_FAIL: 2, 47 EXPECT_COMPILE_LINK_FAIL: 3, 48 EXPECT_VALIDATION_FAIL: 4, 49 EXPECT_BUILD_SUCCESSFUL: 5 50 }; 51 52 /** 53 * Test case type 54 * @enum {number} 55 */ 56 glsShaderLibraryCase.caseType = { 57 CASETYPE_COMPLETE: 0, //!< Has all shaders specified separately. 58 CASETYPE_VERTEX_ONLY: 1, //!< "Both" case, vertex shader sub case. 59 CASETYPE_FRAGMENT_ONLY: 2 //!< "Both" case, fragment shader sub case. 60 }; 61 62 /** 63 * glsShaderLibraryCase.BeforeDrawValidator target type enum 64 * @enum {number} 65 */ 66 glsShaderLibraryCase.targetType = { 67 PROGRAM: 0, 68 PIPELINE: 1 69 }; 70 71 /** 72 * Shader case type enum 73 * @enum {number} 74 */ 75 glsShaderLibraryCase.shaderCase = { 76 STORAGE_INPUT: 0, 77 STORAGE_OUTPUT: 1, 78 STORAGE_UNIFORM: 2 79 }; 80 81 /** 82 * Checks if shader uses in/out qualifiers depending on the version 83 * @param {string} version 84 * @return {boolean} version 85 */ 86 glsShaderLibraryCase.usesShaderInoutQualifiers = function(version) { 87 switch (version) { 88 case '100': 89 case '130': 90 case '140': 91 case '150': 92 return false; 93 94 default: 95 return true; 96 } 97 }; 98 99 /** 100 * Checks if version supports fragment highp precision 101 * @param {string} version 102 * @return {boolean} version ,True when is different from version 100 103 */ 104 glsShaderLibraryCase.supportsFragmentHighp = function(version) { 105 return version !== '100'; 106 }; 107 108 /** 109 * This functions builds a matching vertex shader for a 'both' case, when 110 * the fragment shader is being tested. 111 * We need to build attributes and varyings for each 'input'. 112 * @param { {values:Array}} valueBlock 113 * @return {string} res 114 */ 115 glsShaderLibraryCase.genVertexShader = function(valueBlock) { 116 /** @type {string} */ var res = ''; 117 /** @type {Object} */ var state = tcuTestCase.runner; 118 /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion); 119 /** @type {string} */ var vtxIn = usesInout ? 'in' : 'attribute'; 120 /** @type {string} */ var vtxOut = usesInout ? 'out' : 'varying'; 121 122 res += '#version ' + state.currentTest.spec.targetVersion + '\n'; 123 res += 'precision highp float;\n'; 124 res += 'precision highp int;\n'; 125 res += '\n'; 126 res += vtxIn + ' highp vec4 dEQP_Position;\n'; 127 128 for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { 129 var val = valueBlock.values[ndx]; 130 if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) { 131 /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType); 132 res += vtxIn + ' ' + floatType + ' a_' + val.valueName + ';\n'; 133 134 if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') 135 res += vtxOut + ' ' + floatType + ' ' + val.valueName + ';\n'; 136 else 137 res += vtxOut + ' ' + floatType + ' v_' + val.valueName + ';\n'; 138 } 139 } 140 res += '\n'; 141 142 // Main function. 143 // - gl_Position = dEQP_Position; 144 // - for each input: write attribute directly to varying 145 res += 'void main()\n'; 146 res += ' {\n'; 147 res += '\tgl_Position = dEQP_Position;\n'; 148 for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { 149 var val = valueBlock.values[ndx]; 150 if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) { 151 /** @type {string} */ var name = val.valueName; 152 if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') 153 res += '\t' + name + ' = a_' + name + ';\n'; 154 else 155 res += '\tv_' + name + ' = a_' + name + ';\n'; 156 } 157 } 158 159 res += '}\n'; 160 return res; 161 }; 162 163 /** 164 * @param { {values:Array}} valueBlock 165 * @param {boolean} useFloatTypes 166 * @return {string} stream 167 */ 168 glsShaderLibraryCase.genCompareFunctions = function(valueBlock, useFloatTypes) { 169 var cmpTypeFound = {}; 170 /** @type {string} */ var stream = ''; 171 172 for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { 173 /** @type {Array} */ var val = valueBlock.values[ndx]; 174 if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) 175 cmpTypeFound[gluShaderUtil.getDataTypeName(val.dataType)] = true; 176 177 } 178 if (useFloatTypes) { 179 if (cmpTypeFound['bool']) stream += 'bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n'; 180 if (cmpTypeFound['bvec2']) stream += 'bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n'; 181 if (cmpTypeFound['bvec3']) stream += 'bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n'; 182 if (cmpTypeFound['bvec4']) stream += 'bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n'; 183 if (cmpTypeFound['int']) stream += 'bool isOk (float a, int b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1)); }\n'; 184 if (cmpTypeFound['ivec2']) stream += 'bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n'; 185 if (cmpTypeFound['ivec3']) stream += 'bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n'; 186 if (cmpTypeFound['ivec4']) stream += 'bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n'; 187 if (cmpTypeFound['uint']) stream += 'bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1u)); }\n'; 188 if (cmpTypeFound['uvec2']) stream += 'bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n'; 189 if (cmpTypeFound['uvec3']) stream += 'bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n'; 190 if (cmpTypeFound['uvec4']) stream += 'bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n'; 191 } else { 192 if (cmpTypeFound['bool']) stream += 'bool isOk (bool a, bool b) { return (a == b); }\n'; 193 if (cmpTypeFound['bvec2']) stream += 'bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n'; 194 if (cmpTypeFound['bvec3']) stream += 'bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n'; 195 if (cmpTypeFound['bvec4']) stream += 'bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n'; 196 if (cmpTypeFound['int']) stream += 'bool isOk (int a, int b) { return (a == b); }\n'; 197 if (cmpTypeFound['ivec2']) stream += 'bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n'; 198 if (cmpTypeFound['ivec3']) stream += 'bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n'; 199 if (cmpTypeFound['ivec4']) stream += 'bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n'; 200 if (cmpTypeFound['uint']) stream += 'bool isOk (uint a, uint b) { return (a == b); }\n'; 201 if (cmpTypeFound['uvec2']) stream += 'bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n'; 202 if (cmpTypeFound['uvec3']) stream += 'bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n'; 203 if (cmpTypeFound['uvec4']) stream += 'bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n'; 204 } 205 206 if (cmpTypeFound['float']) 207 stream += 'bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n'; 208 if (cmpTypeFound['vec2']) 209 stream += 'bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n'; 210 if (cmpTypeFound['vec3']) 211 stream += 'bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n'; 212 if (cmpTypeFound['vec4']) 213 stream += 'bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n'; 214 215 if (cmpTypeFound['mat2']) 216 stream += 'bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec2(eps))); }\n'; 217 if (cmpTypeFound['mat2x3']) 218 stream += 'bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec3(eps))); }\n'; 219 if (cmpTypeFound['mat2x4']) 220 stream += 'bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec4(eps))); }\n'; 221 if (cmpTypeFound['mat3x2']) 222 stream += 'bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n'; 223 if (cmpTypeFound['mat3']) 224 stream += 'bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n'; 225 if (cmpTypeFound['mat3x4']) 226 stream += 'bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n'; 227 if (cmpTypeFound['mat4x2']) 228 stream += 'bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n'; 229 if (cmpTypeFound['mat4x3']) 230 stream += 'bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n'; 231 if (cmpTypeFound['mat4']) 232 stream += 'bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n'; 233 234 return stream; 235 }; 236 237 /** 238 * @param {string} dstVec4Var 239 * @param { {values:Array}} valueBlock 240 * @param {string} nonFloatNamePrefix 241 * @param {?string=} checkVarName 242 * @return {string} output 243 */ 244 glsShaderLibraryCase.genCompareOp = function(dstVec4Var, valueBlock, nonFloatNamePrefix, checkVarName) { 245 246 /** @type {boolean} */ var isFirstOutput = true; 247 /** @type {string} */ var output = ''; 248 249 for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { 250 /** @type {Array} */ var val = valueBlock.values[ndx]; 251 /** @type {string} */ var valueName = val.valueName; 252 253 if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) { 254 // Check if we're only interested in one variable (then skip if not the right one). 255 if (checkVarName && (valueName !== checkVarName)) 256 continue; 257 258 // Prefix. 259 if (isFirstOutput) { 260 output += 'bool RES = '; 261 isFirstOutput = false; 262 } else 263 output += 'RES = RES && '; 264 265 // Generate actual comparison. 266 if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') 267 output += 'isOk(' + valueName + ', ref_' + valueName + ', 0.05);\n'; 268 else 269 output += 'isOk(' + nonFloatNamePrefix + valueName + ', ref_' + valueName + ');\n'; 270 } 271 // \note Uniforms are already declared in shader. 272 } 273 274 if (isFirstOutput) 275 output += dstVec4Var + ' = vec4(1.0);\n'; // \todo [petri] Should we give warning if not expect-failure case? 276 else 277 output += dstVec4Var + ' = vec4(RES, RES, RES, 1.0);\n'; 278 279 return output; 280 }; 281 282 /** 283 * @param { {values:Array}} valueBlock 284 * @return {string} shader 285 */ 286 glsShaderLibraryCase.genFragmentShader = function(valueBlock) { 287 /** @type {string} */ var shader = ''; 288 /** @type {Object} */ var state = tcuTestCase.runner; 289 /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion); 290 /** @type {string} */ var vtxIn = usesInout ? 'in' : 'attribute'; 291 /** @type {string} */ var vtxOut = usesInout ? 'out' : 'varying'; 292 /** @type {boolean} */ var customColorOut = usesInout; 293 /** @type {string} */ var fragIn = usesInout ? 'in' : 'varying'; 294 /** @type {string} */ var prec = glsShaderLibraryCase.supportsFragmentHighp(state.currentTest.spec.targetVersion) ? 'highp' : 'mediump'; 295 296 shader += '#version ' + state.currentTest.spec.targetVersion + '\n'; 297 298 shader += 'precision ' + prec + ' float;\n'; 299 shader += 'precision ' + prec + ' int;\n'; 300 shader += '\n'; 301 302 if (customColorOut) { 303 shader += 'layout(location = 0) out mediump vec4 dEQP_FragColor;\n'; 304 shader += '\n'; 305 } 306 307 shader += glsShaderLibraryCase.genCompareFunctions(valueBlock, true); 308 shader += '\n'; 309 310 // Declarations (varying, reference for each output). 311 for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { 312 /** @type {Array} */ var val = valueBlock.values[ndx]; 313 /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType); 314 /** @type {string} */ var refType = gluShaderUtil.getDataTypeName(val.dataType); 315 316 if (val.storageType == glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) { 317 if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') 318 shader += fragIn + ' ' + floatType + ' ' + val.valueName + ';\n'; 319 else 320 shader += fragIn + ' ' + floatType + ' v_' + val.valueName + ';\n'; 321 322 shader += 'uniform ' + refType + ' ref_' + val.valueName + ';\n'; 323 } 324 } 325 326 shader += '\n'; 327 shader += 'void main()\n'; 328 shader += ' {\n'; 329 330 shader += '\t'; 331 shader += glsShaderLibraryCase.genCompareOp(customColorOut ? 'dEQP_FragColor' : 'gl_FragColor', valueBlock, 'v_', null); 332 333 shader += '}\n'; 334 return shader; 335 }; 336 337 glsShaderLibraryCase.caseRequirement = (function() { 338 339 /** 340 * @constructor 341 */ 342 var CaseRequirement = function() { 343 344 /** 345 * @param {number} shaderType 346 * @return {boolean} 347 */ 348 this.isAffected = function(shaderType) { 349 for (var i = 0; i < this.shaderTypes.length; i++) 350 if (this.shaderTypes[i] === shaderType) 351 return true; 352 return false; 353 }; 354 355 this.checkRequirements = function(gl) { 356 if (this.type === requirementType.EXTENSION) { 357 var extns = gl.getSupportedExtensions(); 358 for (var i = 0; i < extns.length; i++) 359 for (var j = 0; j < this.requirements.length; j++) 360 if (extns[i] === this.requirements[j]) { 361 this.supportedExtension = this.requirements[j]; 362 return true; 363 } 364 if (this.requirements.length === 1) 365 throw Error('Test requires extension of ' + this.requirements[0]); 366 else 367 throw Error('Test requires any extension of ' + this.requirements); 368 } else if (this.type === requirementType.IMPLEMENTATION_LIMIT) { 369 var value = gl.getParameter(this.enumName); 370 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Failed to read parameter ' + this.enumName, false, true); 371 372 if (!(value > this.referenceValue)) 373 throw Error('Test requires ' + this.enumName + ' (' + value + ') > ' + this.referenceValue); 374 } 375 }; 376 377 this.getSupportedExtension = function() { 378 return this.supportedExtension; 379 }; 380 381 }; 382 383 var createAnyExtensionRequirement = function(requirements, shaderTypes) { 384 var cr = new CaseRequirement(); 385 cr.type = requirementType.EXTENSION; 386 cr.requirements = requirements; 387 cr.shaderTypes = shaderTypes; 388 return cr; 389 }; 390 391 var createLimitRequirement = function(enumName, ref) { 392 var cr = new CaseRequirement(); 393 cr.type = requirementType.IMPLEMENTATION_LIMIT; 394 cr.enumName = enumName; 395 cr.referenceValue = ref; 396 }; 397 398 /** 399 * @enum {number} 400 */ 401 var requirementType = { 402 EXTENSION: 0, 403 IMPLEMENTATION_LIMIT: 1 404 }; 405 406 return { 407 createAnyExtensionRequirement: createAnyExtensionRequirement, 408 createLimitRequirement: createLimitRequirement, 409 requirementType: requirementType 410 }; 411 412 }()); 413 414 /** Specialize a shader only for the vertex test case. 415 * @param {string} baseCode 416 * @param {number} shaderType 417 * @param {Array<Object>} requirements 418 * @return {string} resultBuf 419 */ 420 glsShaderLibraryCase.injectExtensionRequirements = function(baseCode, shaderType, requirements) { 421 /** 422 * @param {Array<Object>} requirements 423 * @param {number} shaderType 424 * @return {string} buf 425 */ 426 var generateExtensionStatements = function(requirements, shaderType) { 427 /** @type {string} */ var buf = ''; 428 429 if (requirements) 430 for (var ndx = 0; ndx < requirements.length; ndx++) 431 if (requirements[ndx].type === glsShaderLibraryCase.caseRequirement.requirementType.EXTENSION && 432 requirements[ndx].isAffected(shaderType)) 433 buf += '#extension ' + requirements[ndx].getSupportedExtension() + ' : require\n'; 434 435 return buf; 436 }; 437 438 /** @type {string} */ var extensions = generateExtensionStatements(requirements, shaderType); 439 440 if (extensions.length === 0) 441 return baseCode; 442 443 /** @type {Array<string>} */ var splitLines = baseCode.split('\n'); 444 /** @type {boolean} */ var firstNonPreprocessorLine = true; 445 /** @type {string} */ var resultBuf = ''; 446 447 for (var i = 0; i < splitLines.length; i++) { 448 /** @const @type {boolean} */ var isPreprocessorDirective = (splitLines[i].match(/^\s*#/) !== null); 449 450 if (!isPreprocessorDirective && firstNonPreprocessorLine) { 451 firstNonPreprocessorLine = false; 452 resultBuf += extensions; 453 } 454 455 resultBuf += splitLines[i] + '\n'; 456 } 457 458 return resultBuf; 459 }; 460 461 /** Specialize a shader for the vertex shader test case. 462 * @param {string} src 463 * @param { {values:Array}} valueBlock 464 * @return {string} withExt 465 */ 466 glsShaderLibraryCase.specializeVertexShader = function(src, valueBlock) { 467 /** @type {string} */ var decl = ''; 468 /** @type {string} */ var setup = ''; 469 /** @type {string} */ var output = ''; 470 /** @type {Object} */ var state = tcuTestCase.runner; 471 /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion); 472 /** @type {string} */ var vtxIn = usesInout ? 'in' : 'attribute'; 473 /** @type {string} */ var vtxOut = usesInout ? 'out' : 'varying'; 474 475 // Output (write out position). 476 output += 'gl_Position = dEQP_Position;\n'; 477 478 // Declarations (position + attribute for each input, varying for each output). 479 decl += vtxIn + ' highp vec4 dEQP_Position;\n'; 480 for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { 481 /** @type {Array} */ var val = valueBlock.values[ndx]; 482 /** @type {string} */ var valueName = val.valueName; 483 /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType); 484 /** @type {string} */ var dataTypeName = gluShaderUtil.getDataTypeName(val.dataType); 485 486 if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) { 487 if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') { 488 decl += vtxIn + ' ' + floatType + ' ' + valueName + ';\n'; 489 } else { 490 decl += vtxIn + ' ' + floatType + ' a_' + valueName + ';\n'; 491 setup += dataTypeName + ' ' + valueName + ' = ' + dataTypeName + '(a_' + valueName + ');\n'; 492 } 493 } else if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) { 494 if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') 495 decl += vtxOut + ' ' + floatType + ' ' + valueName + ';\n'; 496 else { 497 decl += vtxOut + ' ' + floatType + ' v_' + valueName + ';\n'; 498 decl += dataTypeName + ' ' + valueName + ';\n'; 499 500 output += 'v_' + valueName + ' = ' + floatType + '(' + valueName + ');\n'; 501 } 502 } 503 } 504 505 /** @type {string} */ 506 var baseSrc = src 507 .replace(/\$\{DECLARATIONS\}/g, decl) 508 .replace(/\$\{DECLARATIONS:single-line\}/g, decl.replace(/\n/g, ' ')) 509 .replace(/\$\{SETUP\}/g, setup) 510 .replace(/\$\{OUTPUT\}/g, output) 511 .replace(/\$\{POSITION_FRAG_COLOR\}/g, 'gl_Position'); 512 513 /** @type {string} */ 514 var withExt = glsShaderLibraryCase.injectExtensionRequirements(baseSrc, gluShaderProgram.shaderType.VERTEX, state.currentTest.spec.requirements); 515 516 return withExt; 517 }; 518 519 /** Specialize a shader only for the vertex test case. 520 * @param {string} src 521 * @param { {values:Array}} valueBlock 522 * @return {string} withExt 523 */ 524 glsShaderLibraryCase.specializeVertexOnly = function(src, valueBlock) { 525 /** @type {string} */ var decl = ''; 526 /** @type {string} */ var setup = ''; 527 /** @type {string} */ var output = ''; 528 /** @type {Object} */ var state = tcuTestCase.runner; 529 /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion); 530 /** @type {string} */ var vtxIn = usesInout ? 'in' : 'attribute'; 531 532 // Output (write out position). 533 output += 'gl_Position = dEQP_Position;\n'; 534 535 // Declarations (position + attribute for each input, varying for each output). 536 decl += vtxIn + ' highp vec4 dEQP_Position;\n'; 537 538 for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { 539 /** @type {Array} */ var val = valueBlock.values[ndx]; 540 /** @type {string} */ var valueName = val.valueName; 541 /** @type {string} */ var type = gluShaderUtil.getDataTypeName(val.dataType); 542 543 if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) { 544 if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') { 545 decl += vtxIn + ' ' + type + ' ' + valueName + ';\n'; 546 } else { 547 /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType); 548 549 decl += vtxIn + ' ' + floatType + ' a_' + valueName + ';\n'; 550 setup += type + ' ' + valueName + ' = ' + type + '(a_' + valueName + ');\n'; 551 } 552 } else if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_UNIFORM && 553 !val.valueName.match('\\.')) 554 decl += 'uniform ' + type + ' ' + valueName + ';\n'; 555 } 556 557 /** @type {string} */ 558 var baseSrc = src 559 .replace(/\$\{VERTEX_DECLARATIONS\}/g, decl) 560 .replace(/\$\{VERTEX_DECLARATIONS:single-line\}/g, decl.replace(/\n/g, ' ')) 561 .replace(/\$\{VERTEX_SETUP\}/g, setup) 562 .replace(/\$\{VERTEX_OUTPUT\}/g, output); 563 564 /** @type {string} */ 565 var withExt = glsShaderLibraryCase.injectExtensionRequirements(baseSrc, gluShaderProgram.shaderType.VERTEX, state.currentTest.spec.requirements); 566 567 return withExt; 568 }; 569 570 /** Specialize a shader for the fragment shader test case. 571 * @param {string} src 572 * @param { {values:Array}} valueBlock 573 * @return {string} withExt 574 */ 575 glsShaderLibraryCase.specializeFragmentShader = function(src, valueBlock) { 576 /** @type {string} */ var decl = ''; 577 /** @type {string} */ var setup = ''; 578 /** @type {string} */ var output = ''; 579 580 /** @type {Object} */ var state = tcuTestCase.runner; 581 582 /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion); 583 /** @type {boolean} */ var customColorOut = usesInout; 584 /** @type {string} */ var fragIn = usesInout ? 'in' : 'varying'; 585 /** @type {string} */ var fragColor = customColorOut ? 'dEQP_FragColor' : 'gl_FragColor'; 586 587 decl += glsShaderLibraryCase.genCompareFunctions(valueBlock, false); 588 output += glsShaderLibraryCase.genCompareOp(fragColor, valueBlock, '', null); 589 590 if (customColorOut) 591 decl += 'layout(location = 0) out mediump vec4 dEQP_FragColor;\n'; 592 593 for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { 594 /** @type {Array} */ var val = valueBlock.values[ndx]; 595 /** @type {string} */ var valueName = val.valueName; 596 /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType); 597 /** @type {string} */ var refType = gluShaderUtil.getDataTypeName(val.dataType); 598 599 if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) { 600 if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') 601 decl += fragIn + ' ' + floatType + ' ' + valueName + ';\n'; 602 else { 603 decl += fragIn + ' ' + floatType + ' v_' + valueName + ';\n'; 604 var offset = gluShaderUtil.isDataTypeIntOrIVec(val.dataType) ? ' * 1.0025' : ''; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation 605 setup += refType + ' ' + valueName + ' = ' + refType + '(v_' + valueName + offset + ');\n'; 606 } 607 } else if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) { 608 decl += 'uniform ' + refType + ' ref_' + valueName + ';\n'; 609 decl += refType + ' ' + valueName + ';\n'; 610 } 611 } 612 613 /* \todo [2010-04-01 petri] Check all outputs. */ 614 615 /** @type {string} */ 616 var baseSrc = src 617 .replace(/\$\{DECLARATIONS\}/g, decl) 618 .replace(/\$\{DECLARATIONS:single-line\}/g, decl.replace(/\n/g, ' ')) 619 .replace(/\$\{SETUP\}/g, setup) 620 .replace(/\$\{OUTPUT\}/g, output) 621 .replace(/\$\{POSITION_FRAG_COLOR\}/g, fragColor); 622 623 /** @type {string} */ 624 var withExt = glsShaderLibraryCase.injectExtensionRequirements(baseSrc, gluShaderProgram.shaderType.FRAGMENT, state.currentTest.spec.requirements); 625 626 return withExt; 627 }; 628 629 /** Specialize a shader only for the fragment test case. 630 * @param {string} src 631 * @param { {values:Array}} valueBlock 632 * @return {string} withExt 633 */ 634 glsShaderLibraryCase.specializeFragmentOnly = function(src, valueBlock) { 635 /** @type {string} */ var decl = ''; 636 /** @type {string} */ var output = ''; 637 /** @type {Object} */ var state = tcuTestCase.runner; 638 /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion); 639 /** @type {boolean} */ var customColorOut = usesInout; 640 /** @type {string} */ var fragIn = usesInout ? 'in' : 'varying'; 641 /** @type {string} */ var fragColor = customColorOut ? 'dEQP_FragColor' : 'gl_FragColor'; 642 643 decl += glsShaderLibraryCase.genCompareFunctions(valueBlock, false); 644 output += glsShaderLibraryCase.genCompareOp(fragColor, valueBlock, '', null); 645 646 if (customColorOut) 647 decl += 'layout(location = 0) out mediump vec4 dEQP_FragColor;\n'; 648 649 for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { 650 /** @type {Array} */ var val = valueBlock.values[ndx]; 651 /** @type {string} */ var valueName = val.valueName; 652 /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType); 653 /** @type {string} */ var refType = gluShaderUtil.getDataTypeName(val.dataType); 654 655 if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) { 656 decl += 'uniform ' + refType + ' ref_' + valueName + ';\n'; 657 decl += refType + ' ' + valueName + ';\n'; 658 } else if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_UNIFORM && 659 !valueName.match('\\.')) 660 decl += 'uniform ' + refType + ' ' + valueName + ';\n'; 661 } 662 663 /** @type {string} */ 664 var baseSrc = src 665 .replace(/\$\{FRAGMENT_DECLARATIONS\}/g, decl) 666 .replace(/\$\{FRAGMENT_DECLARATIONS:single-line\}/g, decl.replace(/\n/g, ' ')) 667 .replace(/\$\{FRAGMENT_OUTPUT\}/g, output) 668 .replace(/\$\{FRAG_COLOR\}/g, fragColor); 669 670 /** @type {string} */ 671 var withExt = glsShaderLibraryCase.injectExtensionRequirements(baseSrc, gluShaderProgram.shaderType.FRAGMENT, state.currentTest.spec.requirements); 672 673 return withExt; 674 }; 675 676 /** 677 * Is tessellation present 678 * @return {boolean} True if tessellation is present 679 */ 680 glsShaderLibraryCase.isTessellationPresent = function() { 681 /* TODO: GLES 3.1: implement */ 682 return false; 683 }; 684 685 glsShaderLibraryCase.setUniformValue = function(gl, pipelinePrograms, name, val, arrayNdx) { 686 /** @type {boolean} */ var foundAnyMatch = false; 687 688 for (var programNdx = 0; programNdx < pipelinePrograms.length; ++programNdx) { 689 /** @const @type {WebGLUniformLocation} */ var loc = gl.getUniformLocation(pipelinePrograms[programNdx], name); 690 /** @const @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(val.dataType); 691 /** @const @type {number} */ var elemNdx = (val.arrayLength === 1) ? (0) : (arrayNdx * scalarSize); 692 693 if (!loc) 694 continue; 695 696 foundAnyMatch = true; 697 698 gl.useProgram(pipelinePrograms[programNdx]); 699 700 /** @type {Array} */ var element = val.elements.slice(elemNdx, elemNdx + scalarSize); 701 switch (val.dataType) { 702 case gluShaderUtil.DataType.FLOAT: gl.uniform1fv(loc, new Float32Array(element)); break; 703 case gluShaderUtil.DataType.FLOAT_VEC2: gl.uniform2fv(loc, new Float32Array(element)); break; 704 case gluShaderUtil.DataType.FLOAT_VEC3: gl.uniform3fv(loc, new Float32Array(element)); break; 705 case gluShaderUtil.DataType.FLOAT_VEC4: gl.uniform4fv(loc, new Float32Array(element)); break; 706 case gluShaderUtil.DataType.FLOAT_MAT2: gl.uniformMatrix2fv(loc, false, new Float32Array(element)); break; 707 case gluShaderUtil.DataType.FLOAT_MAT3: gl.uniformMatrix3fv(loc, false, new Float32Array(element)); break; 708 case gluShaderUtil.DataType.FLOAT_MAT4: gl.uniformMatrix4fv(loc, false, new Float32Array(element)); break; 709 case gluShaderUtil.DataType.INT: gl.uniform1iv(loc, new Int32Array(element)); break; 710 case gluShaderUtil.DataType.INT_VEC2: gl.uniform2iv(loc, new Int32Array(element)); break; 711 case gluShaderUtil.DataType.INT_VEC3: gl.uniform3iv(loc, new Int32Array(element)); break; 712 case gluShaderUtil.DataType.INT_VEC4: gl.uniform4iv(loc, new Int32Array(element)); break; 713 714 /** TODO: What type should be used for bool uniforms? */ 715 case gluShaderUtil.DataType.BOOL: gl.uniform1iv(loc, new Int32Array(element)); break; 716 case gluShaderUtil.DataType.BOOL_VEC2: gl.uniform2iv(loc, new Int32Array(element)); break; 717 case gluShaderUtil.DataType.BOOL_VEC3: gl.uniform3iv(loc, new Int32Array(element)); break; 718 case gluShaderUtil.DataType.BOOL_VEC4: gl.uniform4iv(loc, new Int32Array(element)); break; 719 720 case gluShaderUtil.DataType.UINT: gl.uniform1uiv(loc, new Uint32Array(element)); break; 721 case gluShaderUtil.DataType.UINT_VEC2: gl.uniform2uiv(loc, new Uint32Array(element)); break; 722 case gluShaderUtil.DataType.UINT_VEC3: gl.uniform3uiv(loc, new Uint32Array(element)); break; 723 case gluShaderUtil.DataType.UINT_VEC4: gl.uniform4uiv(loc, new Uint32Array(element)); break; 724 case gluShaderUtil.DataType.FLOAT_MAT2X3: gl.uniformMatrix2x3fv(loc, false, new Float32Array(element)); break; 725 case gluShaderUtil.DataType.FLOAT_MAT2X4: gl.uniformMatrix2x4fv(loc, false, new Float32Array(element)); break; 726 case gluShaderUtil.DataType.FLOAT_MAT3X2: gl.uniformMatrix3x2fv(loc, false, new Float32Array(element)); break; 727 case gluShaderUtil.DataType.FLOAT_MAT3X4: gl.uniformMatrix3x4fv(loc, false, new Float32Array(element)); break; 728 case gluShaderUtil.DataType.FLOAT_MAT4X2: gl.uniformMatrix4x2fv(loc, false, new Float32Array(element)); break; 729 case gluShaderUtil.DataType.FLOAT_MAT4X3: gl.uniformMatrix4x3fv(loc, false, new Float32Array(element)); break; 730 731 default: 732 testFailed('Unknown data type ' + val.dataType); 733 } 734 } 735 736 if (!foundAnyMatch) 737 bufferedLogToConsole('WARNING // Uniform \"' + name + '\" location is not valid, location = -1. Cannot set value to the uniform.'); 738 }; 739 740 /** 741 * Evaluates pixels, if they are white, black or there is any unexpected result 742 * @param {gluDrawUtil.Surface} surface 743 * @param {number} minX 744 * @param {number} maxX 745 * @param {number} minY 746 * @param {number} maxY 747 * @return {boolean} True if tessellation is present 748 */ 749 glsShaderLibraryCase.checkPixels = function(surface, minX, maxX, minY, maxY) { 750 /** @type {boolean} */ var allWhite = true; 751 /** @type {boolean} */ var allBlack = true; 752 /** @type {boolean} */ var anyUnexpected = false; 753 754 assertMsgOptions((maxX > minX) && (maxY > minY), 'glsShaderLibraryCase.checkPixels sanity check', false, true); 755 756 for (var y = minY; y <= maxY; y++) { 757 for (var x = minX; x <= maxX; x++) { 758 /** @type {number} */ var pixel = surface.getPixelUintRGB8(x, y); 759 /** @type {boolean} */ var isWhite = (pixel == 0xFFFFFF); 760 /** @type {boolean} */ var isBlack = (pixel == 0x000000); 761 762 allWhite = allWhite && isWhite; 763 allBlack = allBlack && isBlack; 764 anyUnexpected = anyUnexpected || (!isWhite && !isBlack); 765 766 // Early terminate as soon as we know the check hasn't passed 767 if (!allWhite && !allBlack) 768 break; 769 } 770 } 771 772 if (!allWhite) { 773 if (anyUnexpected) 774 testFailed('WARNING: expecting all rendered pixels to be white or black, but got other colors as well!'); 775 else if (!allBlack) 776 testFailed('WARNING: got inconsistent results over the image, when all pixels should be the same color!'); 777 778 return false; 779 } 780 return true; 781 }; 782 783 /** 784 * Initialize a test case 785 */ 786 glsShaderLibraryCase.init = function() { 787 /** @type {Object} */ var state = tcuTestCase.runner; 788 /** @type {Object} */ var test = state.currentTest; 789 790 bufferedLogToConsole('Processing ' + test.fullName()); 791 792 if (!test.spec.valueBlockList.length) 793 test.spec.valueBlockList.push(glsShaderLibraryCase.genValueBlock()); 794 /** @type { {values:Array}} */ var valueBlock = test.spec.valueBlockList[0]; 795 796 if (test.spec.requirements) 797 for (var ndx = 0; ndx < test.spec.requirements.length; ++ndx) 798 test.spec.requirements[ndx].checkRequirements(); 799 800 /** @type {Array<gluShaderProgram.ShaderInfo>} */ var sources = []; 801 802 if (test.spec.caseType === glsShaderLibraryCase.caseType.CASETYPE_COMPLETE) { 803 /** @type {string} */ var vertex = glsShaderLibraryCase.specializeVertexOnly(test.spec.vertexSource, valueBlock); 804 /** @type {string} */ var fragment = glsShaderLibraryCase.specializeFragmentOnly(test.spec.fragmentSource, valueBlock); 805 sources.push(gluShaderProgram.genVertexSource(vertex)); 806 sources.push(gluShaderProgram.genFragmentSource(fragment)); 807 } else if (test.spec.caseType === glsShaderLibraryCase.caseType.CASETYPE_VERTEX_ONLY) { 808 sources.push(gluShaderProgram.genVertexSource(glsShaderLibraryCase.specializeVertexShader(test.spec.vertexSource, valueBlock))); 809 sources.push(gluShaderProgram.genFragmentSource(glsShaderLibraryCase.genFragmentShader(valueBlock))); 810 } else if (test.spec.caseType === glsShaderLibraryCase.caseType.CASETYPE_FRAGMENT_ONLY) { 811 sources.push(gluShaderProgram.genVertexSource(glsShaderLibraryCase.genVertexShader(valueBlock))); 812 sources.push(gluShaderProgram.genFragmentSource(glsShaderLibraryCase.specializeFragmentShader(test.spec.fragmentSource, valueBlock))); 813 } 814 815 test.programs = []; 816 test.programs.push({ 817 programSources: { 818 sources: sources 819 } 820 } 821 ); 822 823 }; 824 825 /** 826 * Execute a test case 827 * @return {boolean} True if test case passed 828 */ 829 glsShaderLibraryCase.execute = function() { 830 /** @const @type {number} */ var quadSize = 1.0; 831 /** @const @type {Array<number>} */ 832 var s_positions = [ 833 -quadSize, -quadSize, 0.0, 1.0, 834 -quadSize, +quadSize, 0.0, 1.0, 835 +quadSize, -quadSize, 0.0, 1.0, 836 +quadSize, +quadSize, 0.0, 1.0 837 ]; 838 839 /** @const @type {Array<number>} */ 840 var s_indices = [ 841 0, 1, 2, 842 1, 3, 2 843 ]; 844 845 var wtu = WebGLTestUtils; 846 /** @type {WebGL2RenderingContext} */ var gl = wtu.create3DContext('canvas'); 847 /** @type {Object} */ var state = tcuTestCase.runner; 848 /** @type {Object} */ var test = state.currentTest; 849 /** @type {Object} */ var spec = test.spec; 850 851 // Compute viewport. 852 /* TODO: original code used random number generator to compute viewport, we use whole canvas */ 853 /** @const @type {number} */ var width = Math.min(canvas.width, glsShaderLibraryCase.VIEWPORT_WIDTH); 854 /** @const @type {number} */ var height = Math.min(canvas.height, glsShaderLibraryCase.VIEWPORT_HEIGHT); 855 /** @const @type {number} */ var viewportX = 0; 856 /** @const @type {number} */ var viewportY = 0; 857 /** @const @type {number} */ var numVerticesPerDraw = 4; 858 /** @const @type {boolean} */ var tessellationPresent = glsShaderLibraryCase.isTessellationPresent(); 859 860 /** @type {boolean} */ var allCompilesOk = true; 861 /** @type {boolean} */ var allLinksOk = true; 862 /** @type {?string} */ var failReason = null; 863 864 /** @type {number} */ var vertexProgramID = -1; 865 /** @type {Array<WebGLProgram>} */ var pipelineProgramIDs = []; 866 /** @type {Array<gluShaderProgram.ShaderProgram>} */ var programs = []; 867 var programPipeline; 868 869 // Set the name of the current test so testFailedOptions/testPassedOptions can use it. 870 setCurrentTestName(test.fullName()); 871 debug('Start testcase: ' + test.fullName()); 872 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Start testcase: ' + test.fullName(), false, true); 873 874 /** @type {gluShaderProgram.ShaderProgram} */ var program = new gluShaderProgram.ShaderProgram(gl, test.programs[0].programSources); 875 876 vertexProgramID = program.getProgram(); 877 pipelineProgramIDs.push(program.getProgram()); 878 programs.push(program); 879 880 // Check that compile/link results are what we expect. 881 882 for (var i = 0; i < program.shaders.length; i++) { 883 if (!program.shaders[i].info.compileOk) 884 allCompilesOk = false; 885 } 886 887 if (!program.getProgramInfo().linkOk) 888 allLinksOk = false; 889 890 switch (spec.expectResult) { 891 case glsShaderLibraryCase.expectResult.EXPECT_PASS: 892 case glsShaderLibraryCase.expectResult.EXPECT_VALIDATION_FAIL: 893 case glsShaderLibraryCase.expectResult.EXPECT_BUILD_SUCCESSFUL: 894 if (!allCompilesOk) 895 failReason = 'expected shaders to compile and link properly, but failed to compile.'; 896 else if (!allLinksOk) 897 failReason = 'expected shaders to compile and link properly, but failed to link.'; 898 break; 899 900 case glsShaderLibraryCase.expectResult.EXPECT_COMPILE_FAIL: 901 if (allCompilesOk && !allLinksOk) 902 failReason = 'expected compilation to fail, but shaders compiled and link failed.'; 903 else if (allCompilesOk) 904 failReason = 'expected compilation to fail, but shaders compiled correctly.'; 905 break; 906 907 case glsShaderLibraryCase.expectResult.EXPECT_LINK_FAIL: 908 if (!allCompilesOk) 909 failReason = 'expected linking to fail, but unable to compile.'; 910 else if (allLinksOk) 911 failReason = 'expected linking to fail, but passed.'; 912 break; 913 914 case glsShaderLibraryCase.expectResult.EXPECT_COMPILE_LINK_FAIL: 915 if (allCompilesOk && allLinksOk) 916 failReason = 'expected compile or link to fail, but passed.'; 917 break; 918 919 default: 920 testFailedOptions('Unknown expected result', true); 921 return false; 922 } 923 924 if (failReason != null) { 925 // \todo [2010-06-07 petri] These should be handled in the test case? 926 927 // If implementation parses shader at link time, report it as quality warning. 928 if (spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_COMPILE_FAIL && allCompilesOk && !allLinksOk) 929 bufferedLogToConsole('Quality warning: implementation parses shader at link time: ' + failReason); 930 else { 931 bufferedLogToConsole('ERROR: ' + failReason); 932 testFailedOptions(failReason, true); 933 } 934 return false; 935 } 936 937 // Return if compile/link expected to fail. 938 if (spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_COMPILE_FAIL || 939 spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_COMPILE_LINK_FAIL || 940 spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_LINK_FAIL || 941 spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_BUILD_SUCCESSFUL) { 942 if (spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_BUILD_SUCCESSFUL) { 943 testPassedOptions('Compile/link is expected to succeed', true); 944 } else { 945 testPassedOptions('Compile/link is expected to fail', true); 946 } 947 setCurrentTestName(''); 948 return (failReason === null); 949 } 950 951 // Setup viewport. 952 gl.viewport(viewportX, viewportY, width, height); 953 954 // Start using program 955 gl.useProgram(vertexProgramID); 956 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'glUseProgram()', false, true); 957 958 // Fetch location for positions positions. 959 /** @type {number} */ var positionLoc = gl.getAttribLocation(vertexProgramID, 'dEQP_Position'); 960 if (positionLoc === -1) { 961 testFailedOptions("no location found for attribute 'dEQP_Position'", true); 962 return false; 963 } 964 965 // Iterate all value blocks. 966 for (var blockNdx = 0; blockNdx < spec.valueBlockList.length; blockNdx++) { 967 /** @type { {values:Array}} */ var block = spec.valueBlockList[blockNdx]; 968 969 // always render at least one pass even if there is no input/output data 970 /** @const @type {number} */ var numRenderPasses = Math.max(block.arrayLength, 1); 971 972 // Iterate all array sub-cases. 973 for (var arrayNdx = 0; arrayNdx < numRenderPasses; arrayNdx++) { 974 /** @const @type {number} */ var numValues = block.values.length; 975 /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = []; 976 /** @type {number} */ var attribValueNdx = 0; 977 /** @type {number} */ var postDrawError; 978 979 vertexArrays.push(new gluDrawUtil.VertexArrayBinding(gl.FLOAT, positionLoc, 4, numVerticesPerDraw, s_positions)); 980 981 // Collect VA pointer for inputs 982 for (var valNdx = 0; valNdx < numValues; valNdx++) { 983 var val = block.values[valNdx]; 984 /** @const @type {string} */ var valueName = val.valueName; 985 /** @const @type {gluShaderUtil.DataType} */ var dataType = val.dataType; 986 /** @const @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(val.dataType); 987 988 if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) { 989 // Replicate values four times. 990 /** @type {Array} */ var scalars = []; 991 992 for (var repNdx = 0; repNdx < numVerticesPerDraw; repNdx++) 993 for (var ndx = 0; ndx < scalarSize; ndx++) 994 scalars[repNdx * scalarSize + ndx] = val.elements[arrayNdx * scalarSize + ndx]; 995 996 // Attribute name prefix. 997 /** @type {string} */ var attribPrefix = ''; 998 // \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)? 999 if ((spec.caseType === glsShaderLibraryCase.caseType.CASETYPE_FRAGMENT_ONLY) || (gluShaderUtil.getDataTypeScalarType(dataType) !== 'float')) 1000 attribPrefix = 'a_'; 1001 1002 // Input always given as attribute. 1003 /** @type {string} */ var attribName = attribPrefix + valueName; 1004 /** @type {number} */ var attribLoc = gl.getAttribLocation(vertexProgramID, attribName); 1005 if (attribLoc === -1) { 1006 bufferedLogToConsole("Warning: no location found for attribute '" + attribName + "'"); 1007 continue; 1008 } 1009 1010 if (gluShaderUtil.isDataTypeMatrix(dataType)) { 1011 var numCols = gluShaderUtil.getDataTypeMatrixNumColumns(dataType); 1012 var numRows = gluShaderUtil.getDataTypeMatrixNumRows(dataType); 1013 1014 assertMsgOptions(scalarSize === numCols * numRows, 'Matrix size sanity check', false, true); 1015 1016 for (var i = 0; i < numCols; i++) 1017 vertexArrays.push(new gluDrawUtil.VertexArrayBinding(gl.FLOAT, attribLoc + i, numRows, numVerticesPerDraw, scalars, scalarSize * 4, i * numRows * 4)); 1018 } else 1019 vertexArrays.push(new gluDrawUtil.VertexArrayBinding(gl.FLOAT, attribLoc, scalarSize, numVerticesPerDraw, scalars)); 1020 1021 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'set vertex attrib array', false, true); 1022 } 1023 } 1024 1025 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'before set uniforms', false, true); 1026 1027 // set uniform values for outputs (refs). 1028 for (var valNdx = 0; valNdx < numValues; valNdx++) { 1029 /** @type {Array} */ var val1 = block.values[valNdx]; 1030 /** @type {string} */ var valueName1 = val1.valueName; 1031 1032 if (val1.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) { 1033 // Set reference value. 1034 glsShaderLibraryCase.setUniformValue(gl, pipelineProgramIDs, 'ref_' + valueName1, val1, arrayNdx); 1035 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'set reference uniforms', false, true); 1036 } else if (val1.storageType === glsShaderLibraryCase.shaderCase.STORAGE_UNIFORM) { 1037 glsShaderLibraryCase.setUniformValue(gl, pipelineProgramIDs, valueName1, val1, arrayNdx); 1038 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'set uniforms', false, true); 1039 } 1040 } 1041 1042 // Clear. 1043 gl.clearColor(0.125, 0.25, 0.5, 1); 1044 gl.clear(gl.COLOR_BUFFER_BIT); 1045 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'clear buffer', false, true); 1046 1047 // Use program or pipeline 1048 if (spec.separatePrograms) 1049 gl.useProgram(null); 1050 else 1051 gl.useProgram(vertexProgramID); 1052 1053 // Draw. 1054 // if (tessellationPresent) { 1055 // gl.patchParameteri(gl.PATCH_VERTICES, 3); 1056 // assertMsgOptions(gl.getError() === gl.NO_ERROR, 'set patchParameteri(PATCH_VERTICES, 3)', false, true); 1057 // } 1058 1059 gluDrawUtil.draw(gl, vertexProgramID, vertexArrays, gluDrawUtil.triangles(s_indices)); 1060 1061 postDrawError = gl.getError(); 1062 1063 if (spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_PASS) { 1064 /** @type {gluDrawUtil.Surface} */ var surface = new gluDrawUtil.Surface(); 1065 /** @const @type {number} */ var w = s_positions[3]; 1066 /** @const @type {number} */ var minY = Math.ceil(((-quadSize / w) * 0.5 + 0.5) * height + 1.0); 1067 /** @const @type {number} */ var maxY = Math.floor(((+quadSize / w) * 0.5 + 0.5) * height - 0.5); 1068 /** @const @type {number} */ var minX = Math.ceil(((-quadSize / w) * 0.5 + 0.5) * width + 1.0); 1069 /** @const @type {number} */ var maxX = Math.floor(((+quadSize / w) * 0.5 + 0.5) * width - 0.5); 1070 1071 assertMsgOptions(postDrawError === gl.NO_ERROR, 'draw', false, true); 1072 1073 surface.readSurface(gl, viewportX, viewportY, width, height); 1074 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'read pixels', false, true); 1075 1076 if (!glsShaderLibraryCase.checkPixels(surface, minX, maxX, minY, maxY)) { 1077 testFailedOptions(( 1078 'INCORRECT RESULT for (value block ' + (blockNdx + 1) + 1079 ' of ' + spec.valueBlockList.length + ', sub-case ' + 1080 (arrayNdx + 1) + ' of ' + block.arrayLength + '):' 1081 ), true); 1082 1083 /* TODO: Port */ 1084 /* 1085 log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage; 1086 dumpValues(block, arrayNdx); 1087 1088 // Dump image on failure. 1089 log << TestLog::Image("Result", "Rendered result image", surface); 1090 1091 */ 1092 gl.useProgram(null); 1093 1094 return false; 1095 } 1096 } else if (spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_VALIDATION_FAIL) { 1097 /** TODO: GLES 3.1: Implement */ 1098 testFailedOptions('Unsupported test case', true); 1099 } 1100 } 1101 } 1102 gl.useProgram(null); 1103 1104 assertMsgOptions(gl.getError() === gl.NO_ERROR, '', true, true); 1105 setCurrentTestName(''); 1106 1107 return true; 1108 }; 1109 1110 glsShaderLibraryCase.runTestCases = function() { 1111 /** @type {Object} */ var state = tcuTestCase.runner; 1112 if (state.next()) { 1113 try { 1114 glsShaderLibraryCase.init(); 1115 glsShaderLibraryCase.execute(); 1116 } catch (err) { 1117 bufferedLogToConsole(err); 1118 } 1119 tcuTestCase.runner.runCallback(glsShaderLibraryCase.runTestCases); 1120 } else 1121 tcuTestCase.runner.terminate(); 1122 1123 }; 1124 1125 glsShaderLibraryCase.genValueBlock = function() { 1126 return { 1127 /** @type {Array} */ values: [], 1128 /** @type {number} */ arrayLength: 0 1129 }; 1130 }; 1131 1132 });