| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <!-- |
| Copyright (c) 2019 The Khronos Group Inc. |
| Use of this source code is governed by an MIT-style license that can be |
| found in the LICENSE.txt file. |
| --> |
| <link rel="stylesheet" href="../../resources/js-test-style.css"/> |
| <script src="../../js/js-test-pre.js"></script> |
| <script src="../../js/webgl-test-utils.js"></script> |
| <script> |
| "use strict"; |
| var wtu; |
| var canvas; |
| var gl; |
| var shouldGenerateGLError; |
| var extensionName; |
| var extension; |
| |
| var buffer; |
| var framebuffer; |
| var program; |
| var renderbuffer; |
| var shader; |
| var texture; |
| var uniformLocation; |
| var arrayBuffer; |
| var arrayBufferView |
| var image; |
| var video; |
| var canvas2d; |
| var ctx2d; |
| var imageData; |
| var float32array; |
| var int32array; |
| var OES_vertex_array_object; |
| var vertexArrayObject; |
| |
| function init() |
| { |
| wtu = WebGLTestUtils; |
| canvas = document.getElementById("canvas"); |
| gl = wtu.create3DContext(canvas); |
| shouldGenerateGLError = wtu.shouldGenerateGLError; |
| |
| description("Tests behavior under a lost context"); |
| |
| // call testValidContext() before checking for the extension, because this is where we check |
| // for the isContextLost() method, which we want to do regardless of the extension's presence. |
| testValidContext(); |
| |
| extensionName = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_lose_context"); |
| if (!extensionName) { |
| debug("Could not find WEBGL_lose_context extension"); |
| finishTest(); |
| return false; |
| } |
| extension = gl.getExtension(extensionName); |
| |
| // need an extension that exposes new API methods. |
| OES_vertex_array_object = wtu.getExtensionWithKnownPrefixes(gl, "OES_vertex_array_object"); |
| |
| canvas.addEventListener("webglcontextlost", testLostContext, false); |
| |
| // We need to initialize |uniformLocation| before losing context. |
| // Otherwise gl.getUniform() when context is lost will throw. |
| uniformLocation = gl.getUniformLocation(program, "tex"); |
| loseContext(); |
| } |
| |
| function loseContext() |
| { |
| debug(""); |
| debug("Lose context"); |
| |
| // Note: this will cause the context to be lost, but the |
| // webglcontextlost event listener to be queued. |
| extension.loseContext(); |
| debug(""); |
| } |
| |
| function testValidContext() |
| { |
| debug("Test valid context"); |
| |
| shouldBeFalse("gl.isContextLost()"); |
| |
| arrayBuffer = new ArrayBuffer(4); |
| arrayBufferView = new Int8Array(arrayBuffer); |
| |
| // Generate resources for testing. |
| buffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, buffer); |
| framebuffer = gl.createFramebuffer(); |
| gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); |
| program = wtu.setupSimpleTextureProgram(gl); |
| renderbuffer = gl.createRenderbuffer(); |
| gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); |
| shader = gl.createShader(gl.VERTEX_SHADER); |
| texture = gl.createTexture(); |
| gl.bindTexture(gl.TEXTURE_2D, texture); |
| shouldBe("gl.getError()", "gl.NO_ERROR"); |
| |
| // Test is queries that will later be false |
| shouldGenerateGLError(gl, gl.NO_ERROR, "gl.enable(gl.BLEND)"); |
| shouldBeTrue("gl.isBuffer(buffer)"); |
| shouldBeTrue("gl.isEnabled(gl.BLEND)"); |
| shouldBeTrue("gl.isFramebuffer(framebuffer)"); |
| shouldBeTrue("gl.isProgram(program)"); |
| shouldBeTrue("gl.isRenderbuffer(renderbuffer)"); |
| shouldBeTrue("gl.isShader(shader)"); |
| shouldBeTrue("gl.isTexture(texture)"); |
| |
| if (OES_vertex_array_object) { |
| vertexArrayObject = OES_vertex_array_object.createVertexArrayOES(); |
| shouldBe("gl.getError()", "gl.NO_ERROR"); |
| shouldBeTrue("OES_vertex_array_object.isVertexArrayOES(vertexArrayObject)"); |
| } |
| } |
| |
| function testGLNOErrorFunctions(tests) { |
| tests.forEach(function(test) { |
| shouldGenerateGLError(gl, gl.NO_ERROR, test); |
| }); |
| } |
| |
| function testFunctionsThatReturnNULL(tests) { |
| tests.forEach(function(test) { |
| shouldBeNull(test); |
| }); |
| } |
| |
| function testLostContext() |
| { |
| debug("Test lost context"); |
| |
| // Functions with special return values. |
| shouldBeTrue("gl.isContextLost()"); |
| shouldBe("gl.getError()", "gl.CONTEXT_LOST_WEBGL"); |
| shouldBe("gl.getError()", "gl.NO_ERROR"); |
| shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_UNSUPPORTED"); |
| shouldBe("gl.getAttribLocation(program, 'u_modelViewProjMatrix')", "-1"); |
| shouldBe("gl.getVertexAttribOffset(0, gl.VERTEX_ATTRIB_ARRAY_POINTER)", "0"); |
| |
| // Attempt resize of lost context should succeed, still lost. |
| gl.canvas.width = gl.canvas.width; // Try to hit any same-size resize path. |
| shouldBeTrue("gl.isContextLost()"); |
| |
| const newSize = gl.canvas.width + 1; |
| gl.canvas.width = newSize; |
| shouldBe("gl.canvas.width", newSize); |
| shouldBeTrue("gl.isContextLost()"); |
| |
| // Test the extension itself. |
| shouldGenerateGLError(gl, gl.INVALID_OPERATION, "extension.loseContext()"); |
| |
| image = document.createElement("img"); |
| video = document.createElement("video"); |
| canvas2d = document.createElement("canvas"); |
| ctx2d = canvas2d.getContext("2d"); |
| imageData = ctx2d.createImageData(1, 1); |
| float32array = new Float32Array(1); |
| int32array = new Int32Array(1); |
| |
| // Functions returning void should return immediately. |
| // This is untestable, but we can at least be sure they cause no errors |
| // and the codepaths are exercised. |
| var voidTests = [ |
| "gl.activeTexture(gl.TEXTURE0)", |
| "gl.attachShader(program, shader)", |
| "gl.bindBuffer(gl.ARRAY_BUFFER, buffer)", |
| "gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer)", |
| "gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer)", |
| "gl.bindTexture(gl.TEXTURE_2D, texture)", |
| "gl.blendColor(1.0, 1.0, 1.0, 1.0)", |
| "gl.blendEquation(gl.FUNC_ADD)", |
| "gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD)", |
| "gl.blendFunc(gl.ONE, gl.ONE)", |
| "gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE)", |
| "gl.bufferData(gl.ARRAY_BUFFER, 0, gl.STATIC_DRAW)", |
| "gl.bufferData(gl.ARRAY_BUFFER, arrayBufferView, gl.STATIC_DRAW)", |
| "gl.bufferData(gl.ARRAY_BUFFER, arrayBuffer, gl.STATIC_DRAW)", |
| "gl.bufferSubData(gl.ARRAY_BUFFRE, 0, arrayBufferView)", |
| "gl.bufferSubData(gl.ARRAY_BUFFRE, 0, arrayBuffer)", |
| "gl.clear(gl.COLOR_BUFFER_BIT)", |
| "gl.clearColor(1, 1, 1, 1)", |
| "gl.clearDepth(1)", |
| "gl.clearStencil(0)", |
| "gl.colorMask(1, 1, 1, 1)", |
| "gl.compileShader(shader)", |
| "gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, 0, 0)", |
| "gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 0, 0)", |
| "gl.cullFace(gl.FRONT)", |
| "gl.deleteBuffer(buffer)", |
| "gl.deleteFramebuffer(framebuffer)", |
| "gl.deleteProgram(program)", |
| "gl.deleteRenderbuffer(renderbuffer)", |
| "gl.deleteShader(shader)", |
| "gl.deleteTexture(texture)", |
| "gl.depthFunc(gl.NEVER)", |
| "gl.depthMask(0)", |
| "gl.depthRange(0, 1)", |
| "gl.detachShader(program, shader)", |
| "gl.disable(gl.BLEND)", |
| "gl.disableVertexAttribArray(0)", |
| "gl.drawArrays(gl.POINTS, 0, 0)", |
| "gl.drawElements(gl.POINTS, 0, gl.UNSIGNED_SHORT, 0)", |
| "gl.enable(gl.BLEND)", |
| "gl.enableVertexAttribArray(0)", |
| "gl.finish()", |
| "gl.flush()", |
| "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, renderbuffer)", |
| "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0)", |
| "gl.frontFace(gl.CW)", |
| "gl.generateMipmap(gl.TEXTURE_2D)", |
| "gl.hint(gl.GENERATE_MIPMAP_HINT, gl.FASTEST)", |
| "gl.lineWidth(0)", |
| "gl.linkProgram(program)", |
| "gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0)", |
| "gl.polygonOffset(0, 0)", |
| "gl.readPixels(0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)", |
| "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0)", |
| "gl.sampleCoverage(0, 0)", |
| "gl.scissor(0, 0, 0, 0)", |
| "gl.shaderSource(shader, '')", |
| "gl.stencilFunc(gl.NEVER, 0, 0)", |
| "gl.stencilFuncSeparate(gl.FRONT, gl.NEVER, 0, 0)", |
| "gl.stencilMask(0)", |
| "gl.stencilMaskSeparate(gl.FRONT, 0)", |
| "gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP)", |
| "gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.KEEP)", |
| "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)", |
| "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData)", |
| "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image)", |
| "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas2d)", |
| "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video)", |
| "gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)", |
| "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)", |
| "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)", |
| "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, imageData)", |
| "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, image)", |
| "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, canvas2d)", |
| "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, video)", |
| "gl.uniform1f(uniformLocation, 0)", |
| "gl.uniform1fv(uniformLocation, float32array)", |
| "gl.uniform1fv(uniformLocation, [0])", |
| "gl.uniform1i(uniformLocation, 0)", |
| "gl.uniform1iv(uniformLocation, int32array)", |
| "gl.uniform1iv(uniformLocation, [0])", |
| "gl.uniform2f(uniformLocation, 0, 0)", |
| "gl.uniform2fv(uniformLocation, float32array)", |
| "gl.uniform2fv(uniformLocation, [0, 0])", |
| "gl.uniform2i(uniformLocation, 0, 0)", |
| "gl.uniform2iv(uniformLocation, int32array)", |
| "gl.uniform2iv(uniformLocation, [0, 0])", |
| "gl.uniform3f(uniformLocation, 0, 0, 0)", |
| "gl.uniform3fv(uniformLocation, float32array)", |
| "gl.uniform3fv(uniformLocation, [0, 0, 0])", |
| "gl.uniform3i(uniformLocation, 0, 0, 0)", |
| "gl.uniform3iv(uniformLocation, int32array)", |
| "gl.uniform3iv(uniformLocation, [0, 0, 0])", |
| "gl.uniform4f(uniformLocation, 0, 0, 0, 0)", |
| "gl.uniform4fv(uniformLocation, float32array)", |
| "gl.uniform4fv(uniformLocation, [0, 0, 0, 0])", |
| "gl.uniform4i(uniformLocation, 0, 0, 0, 0)", |
| "gl.uniform4iv(uniformLocation, int32array)", |
| "gl.uniform4iv(uniformLocation, [0, 0, 0, 0])", |
| "gl.uniformMatrix2fv(uniformLocation, false, float32array)", |
| "gl.uniformMatrix2fv(uniformLocation, false, [0, 0, 0, 0])", |
| "gl.uniformMatrix3fv(uniformLocation, false, float32array)", |
| "gl.uniformMatrix3fv(uniformLocation, false, [0, 0, 0, 0, 0, 0, 0, 0, 0])", |
| "gl.uniformMatrix4fv(uniformLocation, false, float32array)", |
| "gl.uniformMatrix4fv(uniformLocation, false, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])", |
| "gl.useProgram(program)", |
| "gl.validateProgram(program)", |
| "gl.vertexAttrib1f(0, 0)", |
| "gl.vertexAttrib1fv(0, float32array)", |
| "gl.vertexAttrib1fv(0, [0])", |
| "gl.vertexAttrib2f(0, 0, 0)", |
| "gl.vertexAttrib2fv(0, float32array)", |
| "gl.vertexAttrib2fv(0, [0, 0])", |
| "gl.vertexAttrib3f(0, 0, 0, 0)", |
| "gl.vertexAttrib3fv(0, float32array)", |
| "gl.vertexAttrib3fv(0, [0, 0, 0])", |
| "gl.vertexAttrib4f(0, 0, 0, 0, 0)", |
| "gl.vertexAttrib4fv(0, float32array)", |
| "gl.vertexAttrib4fv(0, [0, 0, 0, 0])", |
| "gl.vertexAttribPointer(0, 0, gl.FLOAT, false, 0, 0)", |
| "gl.viewport(0, 0, 0, 0)", |
| ]; |
| testGLNOErrorFunctions(voidTests); |
| |
| // Functions return nullable values should all return null. |
| var nullTests = [ |
| "gl.createBuffer()", |
| "gl.createFramebuffer()", |
| "gl.createProgram()", |
| "gl.createRenderbuffer()", |
| "gl.createShader(gl.GL_VERTEX_SHADER)", |
| "gl.createTexture()", |
| "gl.getActiveAttrib(program, 0)", |
| "gl.getActiveUniform(program, 0)", |
| "gl.getAttachedShaders(program)", |
| "gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE)", |
| "gl.getContextAttributes()", |
| "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", |
| "gl.getParameter(gl.CURRENT_PROGRAM)", |
| "gl.getProgramInfoLog(program)", |
| "gl.getProgramParameter(program, gl.LINK_STATUS)", |
| "gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH)", |
| "gl.getShaderInfoLog(shader)", |
| "gl.getShaderParameter(shader, gl.SHADER_TYPE)", |
| "gl.getShaderSource(shader)", |
| "gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S)", |
| "gl.getUniform(program, uniformLocation)", |
| "gl.getUniformLocation(program, 'vPosition')", |
| "gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)", |
| "gl.getSupportedExtensions()", |
| "gl.getExtension('" + extensionName + "')", |
| ]; |
| testFunctionsThatReturnNULL(nullTests); |
| |
| // "Is" queries should all return false. |
| shouldBeFalse("gl.isBuffer(buffer)"); |
| shouldBeFalse("gl.isEnabled(gl.BLEND)"); |
| shouldBeFalse("gl.isFramebuffer(framebuffer)"); |
| shouldBeFalse("gl.isProgram(program)"); |
| shouldBeFalse("gl.isRenderbuffer(renderbuffer)"); |
| shouldBeFalse("gl.isShader(shader)"); |
| shouldBeFalse("gl.isTexture(texture)"); |
| |
| shouldBe("gl.getError()", "gl.NO_ERROR"); |
| |
| // test extensions |
| if (OES_vertex_array_object) { |
| testGLNOErrorFunctions( |
| [ |
| "OES_vertex_array_object.bindVertexArrayOES(vertexArrayObject)", |
| "OES_vertex_array_object.isVertexArrayOES(vertexArrayObject)", |
| "OES_vertex_array_object.deleteVertexArrayOES(vertexArrayObject)", |
| ]); |
| testFunctionsThatReturnNULL( |
| [ |
| "OES_vertex_array_object.createVertexArrayOES()", |
| ]); |
| } |
| |
| debug(""); |
| |
| finishTest(); |
| } |
| |
| </script> |
| </head> |
| <body onload="init()"> |
| <div id="description"></div> |
| <div id="console"></div> |
| <canvas id="canvas"> |
| </body> |
| </html> |