canvas-tests-utils.js (30012B)
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 7 // Some variables that will be used in this file 8 var canvas; 9 var gl; 10 var OES_vertex_array_object; 11 var uniformLocation; 12 var WEBGL_lose_context; 13 var buffer; 14 var framebuffer; 15 var program; 16 var renderbuffer; 17 var shader; 18 var texture; 19 var arrayBuffer; 20 var arrayBufferView; 21 var vertexArrayObject; 22 var imageData; 23 var float32array; 24 var int32array; 25 26 var OES_texture_float; 27 var new_WEBGL_lose_context; 28 var allowRestore; 29 var contextLostEventFired; 30 var contextRestoredEventFired; 31 var newExtension; 32 33 function compareGLError(glError, evalStr) { 34 var exception; 35 try { 36 eval(evalStr); 37 } catch (e) { 38 exception = e; 39 } 40 if (exception) { 41 return false; 42 } else { 43 if (gl.getError() == glError) 44 return true; 45 return false; 46 } 47 } 48 49 function contextCreation(contextType) { 50 canvas = new OffscreenCanvas(10, 10); 51 gl = canvas.getContext(contextType); 52 53 if (contextType == 'webgl') { 54 if (gl instanceof WebGLRenderingContext) 55 return true; 56 return false; 57 } else if (contextType == 'webgl2') { 58 if (gl instanceof WebGL2RenderingContext) 59 return true; 60 return false; 61 } else { 62 return false; 63 } 64 } 65 66 function transferredOffscreenCanvasCreation(placeholder, width, height) { 67 placeholder.width = width; 68 placeholder.height = height; 69 return placeholder.transferControlToOffscreen(); 70 } 71 72 function assertWidthAndHeight(entity, entityName, width, height) { 73 if (entity.width == width && entity.height == height) { 74 testPassed("The width and height of " + entityName + " are correct."); 75 return; 76 } 77 var errMsg = ""; 78 if (entity.width != width) { 79 errMsg += "The width of " + entityName + " is " + entity.width + " while expected value is " + width + ". "; 80 } 81 if (entity.height != height) { 82 errMsg += "The height of " + entityName + " is " + entity.height + " while expected value is " + height + ". "; 83 } 84 testFailed(errMsg); 85 } 86 87 var webgl1Methods = [ 88 "getContextAttributes", 89 "activeTexture", 90 "attachShader", 91 "bindAttribLocation", 92 "bindBuffer", 93 "bindFramebuffer", 94 "bindRenderbuffer", 95 "bindTexture", 96 "blendColor", 97 "blendEquation", 98 "blendEquationSeparate", 99 "blendFunc", 100 "blendFuncSeparate", 101 "bufferData", 102 "bufferSubData", 103 "checkFramebufferStatus", 104 "clear", 105 "clearColor", 106 "clearDepth", 107 "clearStencil", 108 "colorMask", 109 "compileShader", 110 "compressedTexImage2D", 111 "compressedTexSubImage2D", 112 "copyTexImage2D", 113 "copyTexSubImage2D", 114 "createBuffer", 115 "createFramebuffer", 116 "createProgram", 117 "createRenderbuffer", 118 "createShader", 119 "createTexture", 120 "cullFace", 121 "deleteBuffer", 122 "deleteFramebuffer", 123 "deleteProgram", 124 "deleteRenderbuffer", 125 "deleteShader", 126 "deleteTexture", 127 "depthFunc", 128 "depthMask", 129 "depthRange", 130 "detachShader", 131 "disable", 132 "disableVertexAttribArray", 133 "drawArrays", 134 "drawElements", 135 "enable", 136 "enableVertexAttribArray", 137 "finish", 138 "flush", 139 "framebufferRenderbuffer", 140 "framebufferTexture2D", 141 "frontFace", 142 "generateMipmap", 143 "getActiveAttrib", 144 "getActiveUniform", 145 "getAttachedShaders", 146 "getAttribLocation", 147 "getParameter", 148 "getBufferParameter", 149 "getError", 150 "getExtension", 151 "getFramebufferAttachmentParameter", 152 "getProgramParameter", 153 "getProgramInfoLog", 154 "getRenderbufferParameter", 155 "getShaderParameter", 156 "getShaderInfoLog", 157 "getShaderPrecisionFormat", 158 "getShaderSource", 159 "getSupportedExtensions", 160 "getTexParameter", 161 "getUniform", 162 "getUniformLocation", 163 "getVertexAttrib", 164 "getVertexAttribOffset", 165 "hint", 166 "isBuffer", 167 "isContextLost", 168 "isEnabled", 169 "isFramebuffer", 170 "isProgram", 171 "isRenderbuffer", 172 "isShader", 173 "isTexture", 174 "lineWidth", 175 "linkProgram", 176 "pixelStorei", 177 "polygonOffset", 178 "readPixels", 179 "renderbufferStorage", 180 "sampleCoverage", 181 "scissor", 182 "shaderSource", 183 "stencilFunc", 184 "stencilFuncSeparate", 185 "stencilMask", 186 "stencilMaskSeparate", 187 "stencilOp", 188 "stencilOpSeparate", 189 "texImage2D", 190 "texParameterf", 191 "texParameteri", 192 "texSubImage2D", 193 "uniform1f", 194 "uniform1fv", 195 "uniform1i", 196 "uniform1iv", 197 "uniform2f", 198 "uniform2fv", 199 "uniform2i", 200 "uniform2iv", 201 "uniform3f", 202 "uniform3fv", 203 "uniform3i", 204 "uniform3iv", 205 "uniform4f", 206 "uniform4fv", 207 "uniform4i", 208 "uniform4iv", 209 "uniformMatrix2fv", 210 "uniformMatrix3fv", 211 "uniformMatrix4fv", 212 "useProgram", 213 "validateProgram", 214 "vertexAttrib1f", 215 "vertexAttrib1fv", 216 "vertexAttrib2f", 217 "vertexAttrib2fv", 218 "vertexAttrib3f", 219 "vertexAttrib3fv", 220 "vertexAttrib4f", 221 "vertexAttrib4fv", 222 "vertexAttribPointer", 223 "viewport", 224 ]; 225 226 var webgl2Methods = [ 227 "getBufferSubData", 228 "copyBufferSubData", 229 "blitFramebuffer", 230 "framebufferTextureLayer", 231 "getInternalformatParameter", 232 "invalidateFramebuffer", 233 "invalidateSubFramebuffer", 234 "readBuffer", 235 "renderbufferStorageMultisample", 236 "texImage3D", 237 "texStorage2D", 238 "texStorage3D", 239 "texSubImage3D", 240 "copyTexSubImage3D", 241 "compressedTexImage3D", 242 "compressedTexSubImage3D", 243 "getFragDataLocation", 244 "uniform1ui", 245 "uniform2ui", 246 "uniform3ui", 247 "uniform4ui", 248 "uniform1uiv", 249 "uniform2uiv", 250 "uniform3uiv", 251 "uniform4uiv", 252 "uniformMatrix2x3fv", 253 "uniformMatrix3x2fv", 254 "uniformMatrix2x4fv", 255 "uniformMatrix4x2fv", 256 "uniformMatrix3x4fv", 257 "uniformMatrix4x3fv", 258 "vertexAttribI4i", 259 "vertexAttribI4iv", 260 "vertexAttribI4ui", 261 "vertexAttribI4uiv", 262 "vertexAttribIPointer", 263 "vertexAttribDivisor", 264 "drawArraysInstanced", 265 "drawElementsInstanced", 266 "drawRangeElements", 267 "drawBuffers", 268 "clearBufferiv", 269 "clearBufferuiv", 270 "clearBufferfv", 271 "clearBufferfi", 272 "createQuery", 273 "deleteQuery", 274 "isQuery", 275 "beginQuery", 276 "endQuery", 277 "getQuery", 278 "getQueryParameter", 279 "createSampler", 280 "deleteSampler", 281 "isSampler", 282 "bindSampler", 283 "samplerParameteri", 284 "samplerParameterf", 285 "getSamplerParameter", 286 "fenceSync", 287 "isSync", 288 "deleteSync", 289 "clientWaitSync", 290 "waitSync", 291 "getSyncParameter", 292 "createTransformFeedback", 293 "deleteTransformFeedback", 294 "isTransformFeedback", 295 "bindTransformFeedback", 296 "beginTransformFeedback", 297 "endTransformFeedback", 298 "transformFeedbackVaryings", 299 "getTransformFeedbackVarying", 300 "pauseTransformFeedback", 301 "resumeTransformFeedback", 302 "bindBufferBase", 303 "bindBufferRange", 304 "getIndexedParameter", 305 "getUniformIndices", 306 "getActiveUniforms", 307 "getUniformBlockIndex", 308 "getActiveUniformBlockParameter", 309 "getActiveUniformBlockName", 310 "uniformBlockBinding", 311 "createVertexArray", 312 "deleteVertexArray", 313 "isVertexArray", 314 "bindVertexArray", 315 ]; 316 317 function assertFunction(v, f) { 318 try { 319 if (typeof v[f] != "function") { 320 return false; 321 } else { 322 return true; 323 } 324 } catch(e) { 325 return false; 326 } 327 } 328 329 function testAPIs(contextType) { 330 canvas = new OffscreenCanvas(10, 10); 331 gl = canvas.getContext(contextType); 332 var passed = true; 333 var methods; 334 if (contextType == 'webgl') 335 methods = webgl1Methods; 336 else 337 methods = webgl1Methods.concat(webgl2Methods); 338 for (var i=0; i<methods.length; i++) { 339 var r = assertFunction(gl, methods[i]); 340 passed = passed && r; 341 } 342 343 methods.push(...["makeXRCompatible"]); 344 var extended = false; 345 for (var i in gl) { 346 if (typeof gl[i] == "function" && methods.indexOf(i) == -1) { 347 if (!extended) { 348 extended = true; 349 } 350 } 351 } 352 353 if (!passed || extended) 354 return false; 355 return true; 356 } 357 358 var simpleTextureVertexShader = [ 359 'attribute vec4 vPosition;', 360 'attribute vec2 texCoord0;', 361 'varying vec2 texCoord;', 362 'void main() {', 363 ' gl_Position = vPosition;', 364 ' texCoord = texCoord0;', 365 '}'].join('\n'); 366 367 var simpleTextureFragmentShader = [ 368 'precision mediump float;', 369 'uniform sampler2D tex;', 370 'varying vec2 texCoord;', 371 'void main() {', 372 ' gl_FragData[0] = texture2D(tex, texCoord);', 373 '}'].join('\n'); 374 375 function getShader(gl, shaderStr, type) 376 { 377 var shader = gl.createShader(type); 378 gl.shaderSource(shader, shaderStr); 379 gl.compileShader(shader); 380 381 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) 382 return null; 383 return shader; 384 } 385 386 function setupProgram(gl, shaders, opt_attribs, opt_locations) 387 { 388 var vertexShader = getShader(gl, simpleTextureVertexShader, gl.VERTEX_SHADER); 389 var fragmentShader = getShader(gl, simpleTextureFragmentShader, gl.FRAGMENT_SHADER); 390 var program = gl.createProgram(); 391 gl.attachShader(program, vertexShader); 392 gl.attachShader(program, fragmentShader); 393 394 if (opt_attribs) { 395 for (var ii = 0; ii < opt_attribs.length; ++ii) { 396 gl.bindAttribLocation( 397 program, 398 opt_locations ? opt_locations[ii] : ii, 399 opt_attribs[ii]); 400 } 401 } 402 gl.linkProgram(program); 403 404 // Check the link status 405 var linked = gl.getProgramParameter(program, gl.LINK_STATUS); 406 if (!linked) { 407 // something went wrong with the link 408 gl.deleteProgram(program); 409 return null; 410 } 411 gl.useProgram(program); 412 return program; 413 } 414 415 function setupSimpleTextureProgram(gl, opt_positionLocation, opt_texcoordLocation) 416 { 417 opt_positionLocation = opt_positionLocation || 0; 418 opt_texcoordLocation = opt_texcoordLocation || 1; 419 return setupProgram(gl, 420 [simpleTextureVertexShader, simpleTextureFragmentShader], 421 ['vPosition', 'texCoord0'], 422 [opt_positionLocation, opt_texcoordLocation]); 423 } 424 425 function testLostContextWithoutRestore() 426 { 427 // Functions with special return values. 428 if (!gl.isContextLost()) 429 return false; 430 431 if (gl.getError() != gl.CONTEXT_LOST_WEBGL) 432 return false; 433 if (gl.getError() != gl.NO_ERROR) 434 return false; 435 436 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_UNSUPPORTED || 437 gl.getAttribLocation(program, 'u_modelViewProjMatrix') != -1 || 438 gl.getVertexAttribOffset(0, gl.VERTEX_ATTRIB_ARRAY_POINTER) != 0) 439 return false; 440 441 // Test the extension itself. 442 if (!compareGLError(gl.INVALID_OPERATION, "WEBGL_lose_context.loseContext()")) 443 return false; 444 445 imageData = new ImageData(1, 1); 446 float32array = new Float32Array(1); 447 int32array = new Int32Array(1); 448 449 // Functions returning void should return immediately. 450 // This is untestable, but we can at least be sure they cause no errors 451 // and the codepaths are exercised. 452 if (!compareGLError(gl.NO_ERROR, "gl.activeTexture(gl.TEXTURE0)") || 453 !compareGLError(gl.NO_ERROR, "gl.attachShader(program, shader)") || 454 !compareGLError(gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer)") || 455 !compareGLError(gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer)") || 456 !compareGLError(gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer)") || 457 !compareGLError(gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, texture)") || 458 !compareGLError(gl.NO_ERROR, "gl.blendColor(1.0, 1.0, 1.0, 1.0)") || 459 !compareGLError(gl.NO_ERROR, "gl.blendEquation(gl.FUNC_ADD)") || 460 !compareGLError(gl.NO_ERROR, "gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD)") || 461 !compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.ONE, gl.ONE)") || 462 !compareGLError(gl.NO_ERROR, "gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE)") || 463 !compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, 0, gl.STATIC_DRAW)") || 464 !compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, arrayBufferView, gl.STATIC_DRAW)") || 465 !compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, arrayBuffer, gl.STATIC_DRAW)") || 466 !compareGLError(gl.NO_ERROR, "gl.bufferSubData(gl.ARRAY_BUFFRE, 0, arrayBufferView)") || 467 !compareGLError(gl.NO_ERROR, "gl.bufferSubData(gl.ARRAY_BUFFRE, 0, arrayBuffer)") || 468 !compareGLError(gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)") || 469 !compareGLError(gl.NO_ERROR, "gl.clearColor(1, 1, 1, 1)") || 470 !compareGLError(gl.NO_ERROR, "gl.clearDepth(1)") || 471 !compareGLError(gl.NO_ERROR, "gl.clearStencil(0)") || 472 !compareGLError(gl.NO_ERROR, "gl.colorMask(1, 1, 1, 1)") || 473 !compareGLError(gl.NO_ERROR, "gl.compileShader(shader)") || 474 !compareGLError(gl.NO_ERROR, "gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, 0, 0)") || 475 !compareGLError(gl.NO_ERROR, "gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 0, 0)") || 476 !compareGLError(gl.NO_ERROR, "gl.cullFace(gl.FRONT)") || 477 !compareGLError(gl.NO_ERROR, "gl.deleteBuffer(buffer)") || 478 !compareGLError(gl.NO_ERROR, "gl.deleteFramebuffer(framebuffer)") || 479 !compareGLError(gl.NO_ERROR, "gl.deleteProgram(program)") || 480 !compareGLError(gl.NO_ERROR, "gl.deleteRenderbuffer(renderbuffer)") || 481 !compareGLError(gl.NO_ERROR, "gl.deleteShader(shader)") || 482 !compareGLError(gl.NO_ERROR, "gl.deleteTexture(texture)") || 483 !compareGLError(gl.NO_ERROR, "gl.depthFunc(gl.NEVER)") || 484 !compareGLError(gl.NO_ERROR, "gl.depthMask(0)") || 485 !compareGLError(gl.NO_ERROR, "gl.depthRange(0, 1)") || 486 !compareGLError(gl.NO_ERROR, "gl.detachShader(program, shader)") || 487 !compareGLError(gl.NO_ERROR, "gl.disable(gl.BLEND)") || 488 !compareGLError(gl.NO_ERROR, "gl.disableVertexAttribArray(0)") || 489 !compareGLError(gl.NO_ERROR, "gl.drawArrays(gl.POINTS, 0, 0)") || 490 !compareGLError(gl.NO_ERROR, "gl.drawElements(gl.POINTS, 0, gl.UNSIGNED_SHORT, 0)") || 491 !compareGLError(gl.NO_ERROR, "gl.enable(gl.BLEND)") || 492 !compareGLError(gl.NO_ERROR, "gl.enableVertexAttribArray(0)") || 493 !compareGLError(gl.NO_ERROR, "gl.finish()") || 494 !compareGLError(gl.NO_ERROR, "gl.flush()") || 495 !compareGLError(gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, renderbuffer)") || 496 !compareGLError(gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0)") || 497 !compareGLError(gl.NO_ERROR, "gl.frontFace(gl.CW)") || 498 !compareGLError(gl.NO_ERROR, "gl.generateMipmap(gl.TEXTURE_2D)") || 499 !compareGLError(gl.NO_ERROR, "gl.hint(gl.GENERATE_MIPMAP_HINT, gl.FASTEST)") || 500 !compareGLError(gl.NO_ERROR, "gl.lineWidth(0)") || 501 !compareGLError(gl.NO_ERROR, "gl.linkProgram(program)") || 502 !compareGLError(gl.NO_ERROR, "gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0)") || 503 !compareGLError(gl.NO_ERROR, "gl.polygonOffset(0, 0)") || 504 !compareGLError(gl.NO_ERROR, "gl.readPixels(0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") || 505 !compareGLError(gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0)") || 506 !compareGLError(gl.NO_ERROR, "gl.sampleCoverage(0, 0)") || 507 !compareGLError(gl.NO_ERROR, "gl.scissor(0, 0, 0, 0)") || 508 !compareGLError(gl.NO_ERROR, "gl.shaderSource(shader, '')") || 509 !compareGLError(gl.NO_ERROR, "gl.stencilFunc(gl.NEVER, 0, 0)") || 510 !compareGLError(gl.NO_ERROR, "gl.stencilFuncSeparate(gl.FRONT, gl.NEVER, 0, 0)") || 511 !compareGLError(gl.NO_ERROR, "gl.stencilMask(0)") || 512 !compareGLError(gl.NO_ERROR, "gl.stencilMaskSeparate(gl.FRONT, 0)") || 513 !compareGLError(gl.NO_ERROR, "gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP)") || 514 !compareGLError(gl.NO_ERROR, "gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.KEEP)") || 515 !compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") || 516 !compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData)") || 517 !compareGLError(gl.NO_ERROR, "gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)") || 518 !compareGLError(gl.NO_ERROR, "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)") || 519 !compareGLError(gl.NO_ERROR, "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") || 520 !compareGLError(gl.NO_ERROR, "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, imageData)") || 521 !compareGLError(gl.NO_ERROR, "gl.uniform1f(uniformLocation, 0)") || 522 !compareGLError(gl.NO_ERROR, "gl.uniform1fv(uniformLocation, float32array)") || 523 !compareGLError(gl.NO_ERROR, "gl.uniform1fv(uniformLocation, [0])") || 524 !compareGLError(gl.NO_ERROR, "gl.uniform1i(uniformLocation, 0)") || 525 !compareGLError(gl.NO_ERROR, "gl.uniform1iv(uniformLocation, int32array)") || 526 !compareGLError(gl.NO_ERROR, "gl.uniform1iv(uniformLocation, [0])") || 527 !compareGLError(gl.NO_ERROR, "gl.uniform2f(uniformLocation, 0, 0)") || 528 !compareGLError(gl.NO_ERROR, "gl.uniform2fv(uniformLocation, float32array)") || 529 !compareGLError(gl.NO_ERROR, "gl.uniform2fv(uniformLocation, [0, 0])") || 530 !compareGLError(gl.NO_ERROR, "gl.uniform2i(uniformLocation, 0, 0)") || 531 !compareGLError(gl.NO_ERROR, "gl.uniform2iv(uniformLocation, int32array)") || 532 !compareGLError(gl.NO_ERROR, "gl.uniform2iv(uniformLocation, [0, 0])") || 533 !compareGLError(gl.NO_ERROR, "gl.uniform3f(uniformLocation, 0, 0, 0)") || 534 !compareGLError(gl.NO_ERROR, "gl.uniform3fv(uniformLocation, float32array)") || 535 !compareGLError(gl.NO_ERROR, "gl.uniform3fv(uniformLocation, [0, 0, 0])") || 536 !compareGLError(gl.NO_ERROR, "gl.uniform3i(uniformLocation, 0, 0, 0)") || 537 !compareGLError(gl.NO_ERROR, "gl.uniform3iv(uniformLocation, int32array)") || 538 !compareGLError(gl.NO_ERROR, "gl.uniform3iv(uniformLocation, [0, 0, 0])") || 539 !compareGLError(gl.NO_ERROR, "gl.uniform4f(uniformLocation, 0, 0, 0, 0)") || 540 !compareGLError(gl.NO_ERROR, "gl.uniform4fv(uniformLocation, float32array)") || 541 !compareGLError(gl.NO_ERROR, "gl.uniform4fv(uniformLocation, [0, 0, 0, 0])") || 542 !compareGLError(gl.NO_ERROR, "gl.uniform4i(uniformLocation, 0, 0, 0, 0)") || 543 !compareGLError(gl.NO_ERROR, "gl.uniform4iv(uniformLocation, int32array)") || 544 !compareGLError(gl.NO_ERROR, "gl.uniform4iv(uniformLocation, [0, 0, 0, 0])") || 545 !compareGLError(gl.NO_ERROR, "gl.uniformMatrix2fv(uniformLocation, false, float32array)") || 546 !compareGLError(gl.NO_ERROR, "gl.uniformMatrix2fv(uniformLocation, false, [0, 0, 0, 0])") || 547 !compareGLError(gl.NO_ERROR, "gl.uniformMatrix3fv(uniformLocation, false, float32array)") || 548 !compareGLError(gl.NO_ERROR, "gl.uniformMatrix3fv(uniformLocation, false, [0, 0, 0, 0, 0, 0, 0, 0, 0])") || 549 !compareGLError(gl.NO_ERROR, "gl.uniformMatrix4fv(uniformLocation, false, float32array)") || 550 !compareGLError(gl.NO_ERROR, "gl.uniformMatrix4fv(uniformLocation, false, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])") || 551 !compareGLError(gl.NO_ERROR, "gl.useProgram(program)") || 552 !compareGLError(gl.NO_ERROR, "gl.validateProgram(program)") || 553 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib1f(0, 0)") || 554 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib1fv(0, float32array)") || 555 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib1fv(0, [0])") || 556 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib2f(0, 0, 0)") || 557 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib2fv(0, float32array)") || 558 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib2fv(0, [0, 0])") || 559 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib3f(0, 0, 0, 0)") || 560 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib3fv(0, float32array)") || 561 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib3fv(0, [0, 0, 0])") || 562 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib4f(0, 0, 0, 0, 0)") || 563 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib4fv(0, float32array)") || 564 !compareGLError(gl.NO_ERROR, "gl.vertexAttrib4fv(0, [0, 0, 0, 0])") || 565 !compareGLError(gl.NO_ERROR, "gl.vertexAttribPointer(0, 0, gl.FLOAT, false, 0, 0)") || 566 !compareGLError(gl.NO_ERROR, "gl.viewport(0, 0, 0, 0)")) 567 return false; 568 569 // Functions return nullable values should all return null. 570 if (gl.getActiveAttrib(program, 0) != null || 571 gl.getActiveUniform(program, 0) != null || 572 gl.getAttachedShaders(program) != null || 573 gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE) != null || 574 gl.getContextAttributes() != null || 575 gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) != null || 576 gl.getParameter(gl.CURRENT_PROGRAM) != null || 577 gl.getProgramInfoLog(program) != null || 578 gl.getProgramParameter(program, gl.LINK_STATUS) != null || 579 gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH) != null || 580 gl.getShaderInfoLog(shader) != null || 581 gl.getShaderParameter(shader, gl.SHADER_TYPE) != null || 582 gl.getShaderSource(shader) != null || 583 gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S) != null || 584 gl.getUniform(program, uniformLocation) != null || 585 gl.getUniformLocation(program, 'vPosition') != null || 586 gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) != null || 587 gl.getSupportedExtensions() != null || 588 gl.getExtension("WEBGL_lose_context") != null) 589 return false; 590 591 const failedTests = [ 592 "gl.createBuffer()", 593 "gl.createFramebuffer()", 594 "gl.createProgram()", 595 "gl.createRenderbuffer()", 596 "gl.createShader(gl.VERTEX_SHADER)", 597 "gl.createTexture()", 598 ].reduce(s => { 599 const v = eval(s); 600 return !v; 601 }); 602 if (failedTests.length) { 603 console.log({failedTests}); 604 return false; 605 } 606 607 // "Is" queries should all return false. 608 if (gl.isBuffer(buffer) || gl.isEnabled(gl.BLEND) || gl.isFramebuffer(framebuffer) || 609 gl.isProgram(program) || gl.isRenderbuffer(renderbuffer) || gl.isShader(shader) || 610 gl.isTexture(texture)) 611 return false; 612 613 if (gl.getError() != gl.NO_ERROR) 614 return false; 615 616 // test extensions 617 if (OES_vertex_array_object) { 618 if (!compareGLError(gl.NO_ERROR, "OES_vertex_array_object.bindVertexArrayOES(vertexArrayObject)") || 619 !compareGLError(gl.NO_ERROR, "OES_vertex_array_object.isVertexArrayOES(vertexArrayObject)") || 620 !compareGLError(gl.NO_ERROR, "OES_vertex_array_object.deleteVertexArrayOES(vertexArrayObject)")) 621 return false; 622 if (!OES_vertex_array_object.createVertexArrayOES()) 623 return false; 624 } 625 return true; 626 } 627 function testValidContext() 628 { 629 if (gl.isContextLost()) 630 return false; 631 632 arrayBuffer = new ArrayBuffer(4); 633 arrayBufferView = new Int8Array(arrayBuffer); 634 635 // Generate resources for testing. 636 buffer = gl.createBuffer(); 637 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 638 framebuffer = gl.createFramebuffer(); 639 gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); 640 program = setupSimpleTextureProgram(gl); 641 renderbuffer = gl.createRenderbuffer(); 642 gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); 643 shader = gl.createShader(gl.VERTEX_SHADER); 644 texture = gl.createTexture(); 645 gl.bindTexture(gl.TEXTURE_2D, texture); 646 if (gl.getError() != gl.NO_ERROR) 647 return false; 648 649 // Test is queries that will later be false 650 if (!compareGLError(gl.NO_ERROR, "gl.enable(gl.BLEND)")) 651 return false; 652 if (!gl.isBuffer(buffer) || !gl.isEnabled(gl.BLEND) || !gl.isFramebuffer(framebuffer) || 653 !gl.isProgram(program) || !gl.isRenderbuffer(renderbuffer) || !gl.isShader(shader) || 654 !gl.isTexture(texture)) 655 return false; 656 657 if (OES_vertex_array_object) { 658 vertexArrayObject = OES_vertex_array_object.createVertexArrayOES(); 659 if (gl.getError() != gl.NO_ERROR) 660 return false; 661 if (!OES_vertex_array_object.isVertexArrayOES(vertexArrayObject)) 662 return false; 663 } 664 return true; 665 } 666 667 function setupTest() 668 { 669 canvas = new OffscreenCanvas(10, 10); 670 gl = canvas.getContext('webgl'); 671 WEBGL_lose_context = gl.getExtension("WEBGL_lose_context"); 672 if (!WEBGL_lose_context) 673 return false; 674 675 // Try to get a few extensions 676 OES_vertex_array_object = gl.getExtension("OES_vertex_array_object"); 677 OES_texture_float = gl.getExtension("OES_texture_float"); 678 679 return true; 680 } 681 682 function testOriginalContext() 683 { 684 if (gl.isContextLost()) 685 return false; 686 if (gl.getError() != gl.NO_ERROR) 687 return false; 688 return true; 689 } 690 691 function testLostContext(e) 692 { 693 if (contextLostEventFired) 694 return false; 695 contextLostEventFired = true; 696 if (!gl.isContextLost()) 697 return false; 698 if (gl.getError() != gl.NO_ERROR) 699 return false; 700 if (allowRestore) 701 e.preventDefault(); 702 return true; 703 } 704 705 function testLosingAndRestoringContext() 706 { 707 return new Promise(function(resolve, reject) { 708 if (!setupTest()) 709 reject("Test failed"); 710 711 canvas.addEventListener("webglcontextlost", function(e) { 712 if (!testLostContext(e)) 713 reject("Test failed"); 714 // restore the context after this event has exited. 715 setTimeout(function() { 716 if (!compareGLError(gl.NO_ERROR, "WEBGL_lose_context.restoreContext()")) 717 reject("Test failed"); 718 // The context should still be lost. It will not get restored until the 719 // webglrestorecontext event is fired. 720 if (!gl.isContextLost()) 721 reject("Test failed"); 722 if (gl.getError() != gl.NO_ERROR) 723 reject("Test failed"); 724 // gl methods should still be no-ops 725 if (!compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)")) 726 reject("Test failed"); 727 }, 0); 728 }); 729 canvas.addEventListener("webglcontextrestored", function() { 730 if (!testRestoredContext()) 731 reject("Test failed: !testRestoredContext()"); 732 else 733 resolve("Test passed"); 734 }); 735 allowRestore = true; 736 contextLostEventFired = false; 737 contextRestoredEventFired = false; 738 739 if (!testOriginalContext()) 740 reject("Test failed"); 741 WEBGL_lose_context.loseContext(); 742 // The context should be lost immediately. 743 if (!gl.isContextLost()) 744 reject("Test failed"); 745 if (gl.getError() != gl.CONTEXT_LOST_WEBGL) 746 reject("Test failed"); 747 if (gl.getError() != gl.NO_ERROR) 748 reject("Test failed"); 749 // gl methods should be no-ops 750 if (!compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)")) 751 reject("Test failed"); 752 // but the event should not have been fired. 753 if (contextLostEventFired) 754 reject("Test failed"); 755 }); 756 } 757 758 function reGetExtensionAndTestForProperty(gl, name, expectProperty) { 759 var newExtension = gl.getExtension(name); 760 // NOTE: while getting a extension after context lost/restored is allowed to fail 761 // for the purpose the conformance tests it is not. 762 // 763 // Hypothetically the user can switch GPUs live. For example on Windows, install 2 GPUs, 764 // then in the control panen enable 1, disable the others and visa versa. Since the GPUs 765 // have different capabilities one or the other may not support a particlar extension. 766 // 767 // But, for the purpose of the conformance tests the context is expected to restore 768 // on the same GPU and therefore the extensions that succeeded previously should 769 // succeed on restore. 770 if (newExtension == null) 771 return false; 772 if (expectProperty) { 773 if (!(newExtension.webglTestProperty === true)) 774 return false; 775 } else { 776 if (!(newExtension.webglTestProperty === undefined)) 777 return false; 778 } 779 return newExtension; 780 } 781 782 783 function testOESTextureFloat() { 784 if (OES_texture_float) { 785 // Extension must still be lost. 786 var tex = gl.createTexture(); 787 gl.bindTexture(gl.TEXTURE_2D, tex); 788 if (!compareGLError(gl.INVALID_ENUM, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null)")) 789 return false; 790 // Try re-enabling extension 791 OES_texture_float = reGetExtensionAndTestForProperty(gl, "OES_texture_float", false); 792 if (!compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null)")) 793 return false; 794 return true; 795 } 796 } 797 798 function testOESVertexArrayObject() { 799 if (OES_vertex_array_object) { 800 // Extension must still be lost. 801 if (!OES_vertex_array_object.createVertexArrayOES()) { 802 console.error("!OES_vertex_array_object.createVertexArrayOES()"); 803 return false; 804 } 805 // Try re-enabling extension 806 807 var old_OES_vertex_array_object = OES_vertex_array_object; 808 OES_vertex_array_object = reGetExtensionAndTestForProperty(gl, "OES_vertex_array_object", false); 809 if (!OES_vertex_array_object.createVertexArrayOES()) { 810 console.error("!OES_vertex_array_object.createVertexArrayOES() 2"); 811 return false; 812 } 813 if (!old_OES_vertex_array_object.createVertexArrayOES()) { 814 console.error("!old_OES_vertex_array_object.createVertexArrayOES()"); 815 return false; 816 } 817 return true; 818 } 819 } 820 821 function testExtensions() { 822 if (!testOESTextureFloat() || !testOESVertexArrayObject()) 823 return false; 824 return true; 825 } 826 827 function testRestoredContext() 828 { 829 if (contextRestoredEventFired) 830 return false; 831 contextRestoredEventFired = true; 832 if (gl.isContextLost()) 833 return false; 834 if (gl.getError() != gl.NO_ERROR) 835 return false; 836 837 if (!testExtensions()) 838 return false; 839 return true; 840 }