ogles-utils.js (23290B)
1 /* 2 Copyright (c) 2019 The Khronos Group Inc. 3 Use of this source code is governed by an MIT-style license that can be 4 found in the LICENSE.txt file. 5 */ 6 OpenGLESTestRunner = (function(){ 7 var wtu = WebGLTestUtils; 8 var gl; 9 10 var HALF_GRID_MAX_SIZE = 32; 11 var KNOWN_ATTRIBS = [ 12 "gtf_Vertex", 13 "gtf_Color" 14 ]; 15 16 var GTFPIXELTOLERANCE = 24; 17 var GTFACCEPTABLEFAILURECONT = 10; 18 var GTFAMDPIXELTOLERANCE = 12; 19 var GTFSCORETOLERANCE = 0.65; 20 var GTFNCCTOLARANCEZERO = 0.25; 21 var GTFKERNALSIZE = 5; 22 23 function log(msg) { 24 // debug(msg); 25 } 26 27 function compareImages(refData, tstData, width, height, diff) { 28 function isPixelSame(offset) { 29 // First do simple check 30 if (Math.abs(refData[offset + 0] - tstData[offset + 0]) <= GTFPIXELTOLERANCE && 31 Math.abs(refData[offset + 1] - tstData[offset + 1]) <= GTFPIXELTOLERANCE && 32 Math.abs(refData[offset + 2] - tstData[offset + 2]) <= GTFPIXELTOLERANCE) { 33 return true; 34 } 35 36 // TODO: Implement crazy check that's used in OpenGL ES 2.0 conformance tests. 37 // NOTE: on Desktop things seem to be working. Maybe the more complex check 38 // is needed for embedded systems? 39 return false; 40 } 41 42 var same = true; 43 for (var yy = 0; yy < height; ++yy) { 44 for (var xx = 0; xx < width; ++xx) { 45 var offset = (yy * width + xx) * 4; 46 var diffOffset = ((height - yy - 1) * width + xx) * 4; 47 diff[diffOffset + 0] = 0; 48 diff[diffOffset + 1] = 0; 49 diff[diffOffset + 2] = 0; 50 diff[diffOffset + 3] = 255; 51 if (!isPixelSame(offset)) { 52 diff[diffOffset] = 255; 53 if (same) { 54 same = false; 55 testFailed("pixel @ (" + xx + ", " + yy + " was [" + 56 tstData[offset + 0] + "," + 57 tstData[offset + 1] + "," + 58 tstData[offset + 2] + "," + 59 tstData[offset + 3] + "] expected [" + 60 refData[offset + 0] + "," + 61 refData[offset + 1] + "," + 62 refData[offset + 2] + "," + 63 refData[offset + 3] + "]") 64 } 65 } 66 } 67 } 68 return same; 69 } 70 71 function persp(fovy, aspect, n, f) { 72 var dz = f - n; 73 var rad = fovy / 2.0 * 3.14159265 / 180; 74 75 var s = Math.sin(rad); 76 if (dz == 0 || s == 0 || aspect == 0) 77 return; 78 79 var cot = Math.cos(rad) / s; 80 81 return [ 82 cot / aspect, 83 0.0, 84 0.0, 85 0.0, 86 87 0.0, 88 cot, 89 0.0, 90 0.0, 91 92 0.0, 93 0.0, 94 -(f + n) / dz, 95 -1.0, 96 97 0.0, 98 0.0, 99 -2.0 * f * n / dz, 100 0.0 101 ]; 102 } 103 104 function setAttribs(attribs, buffers) { 105 for (var name in attribs) { 106 var buffer = buffers[name]; 107 if (!buffer) { 108 testFailed("no buffer for attrib:" + name); 109 continue; 110 } 111 var loc = attribs[name]; 112 log("setup attrib: " + loc + " as " + name); 113 var buf = gl.createBuffer(); 114 gl.bindBuffer(gl.ARRAY_BUFFER, buf); 115 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(buffer.data), gl.STATIC_DRAW); 116 gl.enableVertexAttribArray(loc); 117 gl.vertexAttribPointer(loc, buffer.numComponents, gl.FLOAT, false, 0, 0); 118 } 119 } 120 121 function drawSquare(attribs) { 122 var buffers = { 123 "gtf_Vertex": { 124 data: [ 125 1.0, -1.0, -2.0, 126 1.0, 1.0, -2.0, 127 -1.0, -1.0, -2.0, 128 -1.0, 1.0, -2.0 129 ], 130 numComponents: 3 131 }, 132 "gtf_Color": { 133 data: [ 134 0.5, 1.0, 0.0, 135 0.0, 1.0, 1.0, 136 1.0, 0.0, 0.0, 137 0.5, 0.0, 1.0 138 ], 139 numComponents: 3, 140 }, 141 "gtf_SecondaryColor": { 142 data: [ 143 0.5, 0.0, 1.0, 144 1.0, 0.0, 0.0, 145 0.0, 1.0, 1.0, 146 0.5, 1.0, 0.0 147 ], 148 numComponents: 3, 149 }, 150 "gtf_Normal": { 151 data: [ 152 0.5, 0.0, 1.0, 153 1.0, 0.0, 0.0, 154 0.0, 1.0, 1.0, 155 0.5, 1.0, 0.0 156 ], 157 numComponents: 3, 158 }, 159 "gtf_MultiTexCoord0": { 160 data: [ 161 1.0, 0.0, 162 1.0, 1.0, 163 0.0, 0.0, 164 0.0, 1.0 165 ], 166 numComponents: 2, 167 }, 168 "gtf_FogCoord": { 169 data: [ 170 0.0, 171 1.0, 172 0.0, 173 1.0 174 ], 175 numComponents: 1, 176 } 177 }; 178 setAttribs(attribs, buffers); 179 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 180 } 181 182 function drawFrontBackSquare(attribs) { 183 var front = { 184 "gtf_Vertex": { 185 data: [ 186 1.0, -1.0, -2.0, 187 1.0, 0.0, -2.0, 188 -1.0, -1.0, -2.0, 189 -1.0, 0.0, -2.0 190 ], 191 numComponents: 3 192 }, 193 "gtf_Color": { 194 data: [ 195 0.0, 1.0, 0.0, 196 0.0, 1.0, 0.0, 197 0.0, 1.0, 0.0, 198 0.0, 1.0, 0.0 199 ], 200 numComponents: 3, 201 }, 202 "gtf_MultiTexCoord0": { 203 data: [ 204 1.0, 0.0, 205 1.0, 0.5, 206 0.0, 0.0, 207 0.0, 0.5 208 ], 209 numComponents: 2, 210 } 211 }; 212 setAttribs(attribs, front); 213 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 214 215 var back = { 216 "gtf_Vertex": { 217 data: [ 218 1.0, 1.0, -2.0, 219 1.0, 0.0, -2.0, 220 -1.0, 1.0, -2.0, 221 -1.0, 0.0, -2.0 222 ], 223 numComponents: 3 224 }, 225 "gtf_Color": { 226 data: [ 227 1.0, 0.0, 0.0, 228 1.0, 0.0, 0.0, 229 1.0, 0.0, 0.0, 230 1.0, 0.0, 0.0 231 ], 232 numComponents: 3, 233 }, 234 "gtf_MultiTexCoord0": { 235 data: [ 236 1.0, 0.1, 237 1.0, 0.5, 238 0.0, 0.1, 239 0.0, 0.5 240 ], 241 numComponents: 2, 242 } 243 }; 244 setAttribs(attribs, back); 245 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 246 } 247 248 function drawGrid(attribs, width, height) { 249 var n = Math.min(Math.floor(Math.max(width, height) / 4), HALF_GRID_MAX_SIZE); 250 251 var numVertices = (n + n) * (n + n) * 6; 252 253 var gridVertices = []; 254 var gridColors = []; 255 var gridSecColors = []; 256 var gridNormals = []; 257 var gridFogCoords = []; 258 var gridTexCoords0 = []; 259 260 var currentVertex = 0; 261 var currentColor = 0; 262 var currentSecColor = 0; 263 var currentTexCoord0 = 0; 264 var currentNormal = 0; 265 var currentFogCoord = 0; 266 267 var z = -2.0; 268 for(var i = -n; i < n; ++i) 269 { 270 var x1 = i / n; 271 var x2 = (i + 1) / n; 272 for(var j = -n; j < n; ++j) 273 { 274 var y1 = j / n; 275 var y2 = (j + 1) / n; 276 277 // VERTEX 0 278 gridVertices[currentVertex++] = x1; 279 gridVertices[currentVertex++] = y1; 280 gridVertices[currentVertex++] = z; 281 gridColors[currentColor++] = 1.0 - (x1 + y1 + 2.0) / 4.0; 282 gridColors[currentColor++] = (x1 + 1.0) / 2.0; 283 gridColors[currentColor++] = (y1 + 1.0) / 2.0; 284 gridSecColors[currentSecColor++] = 1.0 - (x2 + y2 + 2.0) / 4.0; 285 gridSecColors[currentSecColor++] = (x2 + 1.0) / 2.0; 286 gridSecColors[currentSecColor++] = (y2 + 1.0) / 2.0; 287 gridTexCoords0[currentTexCoord0++] = (x1 + 1.0) / 2.0; 288 gridTexCoords0[currentTexCoord0++] = (y1 + 1.0) / 2.0; 289 gridNormals[currentNormal++] = 1.0 - (x2 + y2 + 2.0) / 4.0; 290 gridNormals[currentNormal++] = (x2 + 1.0) / 2.0; 291 gridNormals[currentNormal++] = (y2 + 1.0) / 2.0; 292 gridFogCoords[currentFogCoord++] = (y1 + 1.0) / 2.0; 293 294 // VERTEX 1 295 gridVertices[currentVertex++] = x2; 296 gridVertices[currentVertex++] = y1; 297 gridVertices[currentVertex++] = z; 298 gridColors[currentColor++] = 1.0 - (x2 + y1 + 2.0) / 4.0; 299 gridColors[currentColor++] = (x2 + 1.0) / 2.0; 300 gridColors[currentColor++] = (y1 + 1.0) / 2.0; 301 gridSecColors[currentSecColor++] = 1.0 - (x1 + y2 + 2.0) / 4.0; 302 gridSecColors[currentSecColor++] = (x1 + 1.0) / 2.0; 303 gridSecColors[currentSecColor++] = (y2 + 1.0) / 2.0; 304 gridTexCoords0[currentTexCoord0++] = (x2 + 1.0) / 2.0; 305 gridTexCoords0[currentTexCoord0++] = (y1 + 1.0) / 2.0; 306 gridNormals[currentNormal++] = 1.0 - (x1 + y2 + 2.0) / 4.0; 307 gridNormals[currentNormal++] = (x1 + 1.0) / 2.0; 308 gridNormals[currentNormal++] = (y2 + 1.0) / 2.0; 309 gridFogCoords[currentFogCoord++] = (y1 + 1.0) / 2.0; 310 311 // VERTEX 2 312 gridVertices[currentVertex++] = x2; 313 gridVertices[currentVertex++] = y2; 314 gridVertices[currentVertex++] = z; 315 gridColors[currentColor++] = 1.0 - (x2 + y2 + 2.0) / 4.0; 316 gridColors[currentColor++] = (x2 + 1.0) / 2.0; 317 gridColors[currentColor++] = (y2 + 1.0) / 2.0; 318 gridSecColors[currentSecColor++] = 1.0 - (x1 + y1 + 2.0) / 4.0; 319 gridSecColors[currentSecColor++] = (x1 + 1.0) / 2.0; 320 gridSecColors[currentSecColor++] = (y1 + 1.0) / 2.0; 321 gridTexCoords0[currentTexCoord0++] = (x2 + 1.0) / 2.0; 322 gridTexCoords0[currentTexCoord0++] = (y2 + 1.0) / 2.0; 323 gridNormals[currentNormal++] = 1.0 - (x1 + y1 + 2.0) / 4.0; 324 gridNormals[currentNormal++] = (x1 + 1.0) / 2.0; 325 gridNormals[currentNormal++] = (y1 + 1.0) / 2.0; 326 gridFogCoords[currentFogCoord++] = (y2 + 1.0) / 2.0; 327 328 // VERTEX 2 329 gridVertices[currentVertex++] = x2; 330 gridVertices[currentVertex++] = y2; 331 gridVertices[currentVertex++] = z; 332 gridColors[currentColor++] = 1.0 - (x2 + y2 + 2.0) / 4.0; 333 gridColors[currentColor++] = (x2 + 1.0) / 2.0; 334 gridColors[currentColor++] = (y2 + 1.0) / 2.0; 335 gridSecColors[currentSecColor++] = 1.0 - (x1 + y1 + 2.0) / 4.0; 336 gridSecColors[currentSecColor++] = (x1 + 1.0) / 2.0; 337 gridSecColors[currentSecColor++] = (y1 + 1.0) / 2.0; 338 gridTexCoords0[currentTexCoord0++] = (x2 + 1.0) / 2.0; 339 gridTexCoords0[currentTexCoord0++] = (y2 + 1.0) / 2.0; 340 gridNormals[currentNormal++] = 1.0 - (x1 + y1 + 2.0) / 4.0; 341 gridNormals[currentNormal++] = (x1 + 1.0) / 2.0; 342 gridNormals[currentNormal++] = (y1 + 1.0) / 2.0; 343 gridFogCoords[currentFogCoord++] = (y2 + 1.0) / 2.0; 344 345 // VERTEX 3 346 gridVertices[currentVertex++] = x1; 347 gridVertices[currentVertex++] = y2; 348 gridVertices[currentVertex++] = z; 349 gridColors[currentColor++] = 1.0 - (x1 + y2 + 2.0) / 4.0; 350 gridColors[currentColor++] = (x1 + 1.0) / 2.0; 351 gridColors[currentColor++] = (y2 + 1.0) / 2.0; 352 gridSecColors[currentSecColor++] = 1.0 - (x2 + y1 + 2.0) / 4.0; 353 gridSecColors[currentSecColor++] = (x2 + 1.0) / 2.0; 354 gridSecColors[currentSecColor++] = (y1 + 1.0) / 2.0; 355 gridTexCoords0[currentTexCoord0++] = (x1 + 1.0) / 2.0; 356 gridTexCoords0[currentTexCoord0++] = (y2 + 1.0) / 2.0; 357 gridNormals[currentNormal++] = 1.0 - (x2 + y1 + 2.0) / 4.0; 358 gridNormals[currentNormal++] = (x2 + 1.0) / 2.0; 359 gridNormals[currentNormal++] = (y1 + 1.0) / 2.0; 360 gridFogCoords[currentFogCoord++] = (y2 + 1.0) / 2.0; 361 362 // VERTEX 0 363 gridVertices[currentVertex++] = x1; 364 gridVertices[currentVertex++] = y1; 365 gridVertices[currentVertex++] = z; 366 gridColors[currentColor++] = 1.0 - (x1 + y1 + 2.0) / 4.0; 367 gridColors[currentColor++] = (x1 + 1.0) / 2.0; 368 gridColors[currentColor++] = (y1 + 1.0) / 2.0; 369 gridSecColors[currentSecColor++] = 1.0 - (x2 + y2 + 2.0) / 4.0; 370 gridSecColors[currentSecColor++] = (x2 + 1.0) / 2.0; 371 gridSecColors[currentSecColor++] = (y2 + 1.0) / 2.0; 372 gridTexCoords0[currentTexCoord0++] = (x1 + 1.0) / 2.0; 373 gridTexCoords0[currentTexCoord0++] = (y1 + 1.0) / 2.0; 374 gridNormals[currentNormal++] = 1.0 - (x2 + y2 + 2.0) / 4.0; 375 gridNormals[currentNormal++] = (x2 + 1.0) / 2.0; 376 gridNormals[currentNormal++] = (y2 + 1.0) / 2.0; 377 gridFogCoords[currentFogCoord++] = (y1 + 1.0) / 2.0; 378 } 379 } 380 381 var buffers = { 382 "gtf_Vertex": { data: gridVertices, numComponents: 3 }, 383 "gtf_Color": { data: gridColors, numComponents: 3 }, 384 "gtf_SecondaryColor": { data: gridSecColors, numComponents: 3 }, 385 "gtf_Normal": { data: gridNormals, numComponents: 3 }, 386 "gtf_FogCoord": { data: gridFogCoords, numComponents: 1 }, 387 "gtf_MultiTexCoord0": { data: gridTexCoords0, numComponents: 2 } 388 }; 389 setAttribs(attribs, buffers); 390 gl.drawArrays(gl.TRIANGLES, 0, numVertices); 391 } 392 393 var MODEL_FUNCS = { 394 square: drawSquare, 395 frontbacksquare: drawFrontBackSquare, 396 grid: drawGrid 397 }; 398 399 function drawWithProgram(program, programInfo, test) { 400 gl.useProgram(program); 401 var attribs = { }; 402 403 var numAttribs = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); 404 for (var ii = 0; ii < numAttribs; ++ii) { 405 var info = gl.getActiveAttrib(program, ii); 406 var name = info.name; 407 var location = gl.getAttribLocation(program, name); 408 attribs[name] = location; 409 410 if (KNOWN_ATTRIBS.indexOf(name) < 0) { 411 testFailed("unknown attrib:" + name) 412 } 413 } 414 415 var uniforms = { }; 416 var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); 417 for (var ii = 0; ii < numUniforms; ++ii) { 418 var info = gl.getActiveUniform(program, ii); 419 var name = info.name; 420 if (name.match(/\[0\]$/)) { 421 name = name.substr(0, name.length - 3); 422 } 423 var location = gl.getUniformLocation(program, name); 424 uniforms[name] = {location: location}; 425 } 426 427 var getUniformLocation = function(name) { 428 var uniform = uniforms[name]; 429 if (uniform) { 430 uniform.used = true; 431 return uniform.location; 432 } 433 return null; 434 } 435 436 // Set known uniforms 437 var loc = getUniformLocation("gtf_ModelViewProjectionMatrix"); 438 if (loc) { 439 gl.uniformMatrix4fv( 440 loc, 441 false, 442 persp(60, 1, 1, 30)); 443 } 444 var loc = getUniformLocation("viewportwidth"); 445 if (loc) { 446 gl.uniform1f(loc, gl.canvas.width); 447 } 448 var loc = getUniformLocation("viewportheight"); 449 if (loc) { 450 gl.uniform1f(loc, gl.canvas.height); 451 } 452 453 // Set test specific uniforms 454 for (var name in programInfo.uniforms) { 455 var location = getUniformLocation(name); 456 if (!location) { 457 continue; 458 } 459 var uniform = programInfo.uniforms[name]; 460 var type = uniform.type; 461 var value = uniform.value; 462 var transpose = uniform.transpose; 463 if (transpose !== undefined) { 464 log("gl." + type + '("' + name + '", ' + transpose + ", " + value + ")"); 465 gl[type](location, transpose, value); 466 } else if (!type.match("v$")) { 467 var args = [location]; 468 for (var ii = 0; ii < value.length; ++ii) { 469 args.push(value[ii]); 470 } 471 gl[type].apply(gl, args); 472 log("gl." + type + '("' + name + '", ' + args.slice(1) + ")"); 473 } else { 474 log("gl." + type + '("' + name + '", ' + value + ")"); 475 gl[type](location, value); 476 } 477 var err = gl.getError(); 478 if (err != gl.NO_ERROR) { 479 testFailed(wtu.glEnumToString(gl, err) + " generated setting uniform: " + name); 480 } 481 } 482 483 // Filter out specified built-in uniforms 484 if (programInfo.builtin_uniforms) { 485 var num_builtins_found = 0; 486 var valid_values = programInfo.builtin_uniforms.valid_values; 487 for (var index in valid_values) { 488 var uniform = uniforms[valid_values[index]]; 489 if (uniform) { 490 ++num_builtins_found; 491 uniform.builtin = true; 492 } 493 } 494 495 var min_required = programInfo.builtin_uniforms.min_required; 496 if (num_builtins_found < min_required) { 497 testFailed("only found " + num_builtins_found + " of " + min_required + 498 " required built-in uniforms: " + valid_values); 499 } 500 } 501 502 // Check for unset uniforms 503 for (var name in uniforms) { 504 var uniform = uniforms[name]; 505 if (!uniform.used && !uniform.builtin) { 506 testFailed("uniform " + name + " never set"); 507 } 508 } 509 510 511 for (var state in test.state) { 512 var fields = test.state[state]; 513 switch (state) { 514 case 'depthrange': 515 gl.depthRange(fields.near, fields.far); 516 break; 517 default: 518 testFailed("unknown state: " + state) 519 } 520 } 521 522 gl.clearColor(0, 0, 0, 0); 523 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 524 525 var model = test.model || "square"; 526 var fn = MODEL_FUNCS[model]; 527 if (!fn) { 528 testFailed("unknown model type: " + model) 529 } else { 530 log("draw as: " + model) 531 fn(attribs, gl.canvas.width, gl.canvas.height); 532 } 533 534 var pixels = new Uint8Array(gl.canvas.width * gl.canvas.height * 4); 535 gl.readPixels(0, 0, gl.canvas.width, gl.canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels); 536 return { 537 width: gl.canvas.width, 538 height: gl.canvas.height, 539 pixels: pixels, 540 img: wtu.makeImageFromCanvas(gl.canvas) 541 }; 542 } 543 544 function runProgram(programInfo, test, label, callback) { 545 var shaders = []; 546 var source = []; 547 var count = 0; 548 549 function loadShader(path, type, index) { 550 wtu.loadTextFileAsync(path, function(success, text) { 551 addShader(success, text, type, path, index); 552 }); 553 } 554 555 function addShader(success, text, type, path, index) { 556 ++count; 557 if (!success) { 558 testFailed("could not load: " + path); 559 } else { 560 var shader = wtu.loadShader(gl, text, type); 561 shaders.push(shader); 562 source[index] = text; 563 } 564 if (count == 2) { 565 var result; 566 if (shaders.length == 2) { 567 debug(""); 568 if (!quietMode()) { 569 var consoleDiv = document.getElementById("console"); 570 wtu.addShaderSources( 571 gl, consoleDiv, label + " vertex shader", shaders[0], source[0], 572 programInfo.vertexShader); 573 wtu.addShaderSources( 574 gl, consoleDiv, label + " fragment shader", shaders[1], source[1], 575 programInfo.fragmentShader); 576 } 577 var program = wtu.createProgram(gl, shaders[0], shaders[1]); 578 result = drawWithProgram(program, programInfo, test); 579 } 580 callback(result); 581 } 582 } 583 584 loadShader(programInfo.vertexShader, gl.VERTEX_SHADER, 0); 585 loadShader(programInfo.fragmentShader, gl.FRAGMENT_SHADER, 1); 586 } 587 588 function compareResults(expected, actual) { 589 var width = expected.width; 590 var height = expected.height; 591 var canvas = document.createElement("canvas"); 592 canvas.width = width; 593 canvas.height = height; 594 var ctx = canvas.getContext("2d"); 595 var imgData = ctx.getImageData(0, 0, width, height); 596 var tolerance = 0; 597 598 var expData = expected.pixels; 599 var actData = actual.pixels; 600 601 var same = compareImages(expData, actData, width, height, imgData.data); 602 603 var console = document.getElementById("console"); 604 var diffImg = null; 605 if (!same) { 606 ctx.putImageData(imgData, 0, 0); 607 diffImg = wtu.makeImageFromCanvas(canvas); 608 } 609 610 if (!quietMode()) { 611 var div = document.createElement("div"); 612 div.className = "testimages"; 613 wtu.insertImage(div, "reference", expected.img); 614 wtu.insertImage(div, "test", actual.img); 615 if (diffImg) { 616 wtu.insertImage(div, "diff", diffImg); 617 } 618 div.appendChild(document.createElement('br')); 619 620 console.appendChild(div); 621 } 622 623 if (!same) { 624 testFailed("images are different"); 625 } else { 626 testPassed("images are the same"); 627 } 628 629 if (!quietMode()) 630 console.appendChild(document.createElement('hr')); 631 } 632 633 function runCompareTest(test, callback) { 634 debug(""); 635 debug("test: " + test.name); 636 var results = []; 637 var count = 0; 638 639 function storeResults(index) { 640 return function(result) { 641 results[index] = result; 642 ++count; 643 if (count == 2) { 644 compareResults(results[0], results[1]); 645 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); 646 callback(); 647 } 648 } 649 } 650 651 runProgram(test.referenceProgram, test, "reference", storeResults(0)); 652 runProgram(test.testProgram, test, "test", storeResults(1)); 653 } 654 655 function runBuildTest(test, callback) { 656 debug(""); 657 debug("test: " + test.name); 658 659 var shaders = [null, null]; 660 var source = ["",""]; 661 var success = [undefined, undefined]; 662 var count = 0; 663 664 function loadShader(path, type, index) { 665 if (path == "empty") { 666 shaders[index] = gl.createShader(); 667 success[index] = true; 668 source[index] = "/* empty */"; 669 attachAndLink(); 670 } else { 671 wtu.loadTextFileAsync(path, function(loadSuccess, text) { 672 if (!loadSuccess) { 673 success[index] = false; 674 source[index] = "/* could not load */"; 675 testFailed("could not load:" + path); 676 } else { 677 source[index] = text; 678 shaders[index] = wtu.loadShader(gl, text, type, function(index) { 679 return function(msg) { 680 success[index] = false 681 } 682 }(index)); 683 if (success[index] === undefined) { 684 success[index] = true; 685 } 686 } 687 attachAndLink(); 688 }); 689 } 690 } 691 692 function attachAndLink() { 693 ++count; 694 if (count == 2) { 695 if (!quietMode()) { 696 debug(""); 697 var c = document.getElementById("console"); 698 wtu.addShaderSource( 699 c, "vertex shader", source[0], test.testProgram.vertexShader); 700 debug("compile: " + (success[0] ? "success" : "fail")); 701 wtu.addShaderSource( 702 c, "fragment shader", source[1], test.testProgram.fragmentShader); 703 debug("compile: " + (success[1] ? "success" : "fail")); 704 } 705 compileSuccess = (success[0] && success[1]); 706 if (!test.compstat) { 707 if (compileSuccess) { 708 testFailed("expected compile failure but was successful"); 709 } else { 710 testPassed("expected compile failure and it failed"); 711 } 712 } else { 713 if (compileSuccess) { 714 testPassed("expected compile success and it was successful"); 715 } else { 716 testFailed("expected compile success but it failed"); 717 } 718 var linkSuccess = true; 719 var program = wtu.createProgram(gl, shaders[0], shaders[1], function() { 720 linkSuccess = false; 721 }); 722 if (linkSuccess !== test.linkstat) { 723 testFailed("expected link to " + (test.linkstat ? "succeed" : "fail")); 724 } else { 725 testPassed("shaders compiled and linked as expected."); 726 } 727 } 728 callback(); 729 } 730 } 731 732 loadShader(test.testProgram.vertexShader, gl.VERTEX_SHADER, 0); 733 loadShader(test.testProgram.fragmentShader, gl.FRAGMENT_SHADER, 1); 734 } 735 736 var testPatterns = { 737 compare: runCompareTest, 738 build: runBuildTest, 739 740 dummy: null // just here to mark the end 741 }; 742 743 function LogGLCall(functionName, args) { 744 console.log("gl." + functionName + "(" + 745 WebGLDebugUtils.glFunctionArgsToString(functionName, args) + ")"); 746 } 747 748 // Runs the tests async since they will load shaders. 749 function run(obj) { 750 description(); 751 752 var canvas = document.getElementById("example"); 753 gl = wtu.create3DContext(canvas); 754 if (window.WebGLDebugUtils) { 755 gl = WebGLDebugUtils.makeDebugContext(gl, undefined, LogGLCall); 756 } 757 if (!gl) { 758 testFailed("context does not exist"); 759 finishTest(); 760 return; 761 } 762 763 if (gl.canvas.width != 500 || gl.canvas.height != 500) { 764 testFailed("canvas must be 500x500 pixels: Several shaders are hard coded to this size."); 765 } 766 767 var tests = obj.tests; 768 var ndx = 0; 769 770 function runNextTest() { 771 if (ndx < tests.length) { 772 var test = tests[ndx++]; 773 var fn = testPatterns[test.pattern]; 774 if (!fn) { 775 testFailed("test pattern: " + test.pattern + " not supoprted") 776 runNextTest(); 777 } else { 778 fn(test, runNextTest); 779 } 780 } else { 781 finishTest(); 782 } 783 } 784 runNextTest(); 785 } 786 787 return { 788 run: run, 789 }; 790 }());