| <!-- |
| 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. |
| --> |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <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> |
| <title>WebGL 2 Object Expandos Conformance Test</title> |
| </head> |
| <body> |
| <div id="description"></div> |
| <div id="console"></div> |
| <canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas> |
| <script> |
| "use strict"; |
| description("This test verifies that WebGL object expandos are preserved across garbage collections."); |
| |
| var wtu = WebGLTestUtils; |
| var canvas = document.getElementById("canvas"); |
| var gl = wtu.create3DContext(canvas, {antialias: false}, 2); |
| |
| // Helpers that set expandos and verify they are set to the correct value. |
| var expandoValue = "WebGL is awesome!" |
| function setTestExpandos(instance, extra) { |
| instance.expando1 = expandoValue; |
| instance.expando2 = { subvalue : expandoValue }; |
| instance.expando_extra = extra; |
| } |
| function verifyTestExpandos(instance, msg, extra) { |
| assertMsg(instance.expando1 === expandoValue, msg + ": Expect basic expando to survive despite GC."); |
| assertMsg(instance.expando2 && instance.expando2.subvalue === expandoValue, msg + ": Expect subobject expando to survive despite GC."); |
| assertMsg(instance.expando_extra === extra, msg + ": Expect extra expando to survive despite GC."); |
| } |
| |
| // Tests that we don't get expando loss for bound resources where the |
| // only remaining reference is internal to WebGL |
| function testBasicBindings() { |
| debug('Basic Bindings'); |
| |
| // Test data that describes how to create, bind, and retrieve an object off of the context |
| var glProt = Object.getPrototypeOf(gl); |
| var simpleData = [ |
| { |
| typeName: 'WebGLSampler', |
| creationFn: glProt.createSampler, |
| bindFn: glProt.bindSampler, |
| bindConstant: 0, |
| retrieveConstant: glProt.SAMPLER_BINDING, |
| name: "SAMPLER_BINDING", |
| }, |
| { |
| typeName: 'WebGLTransformFeedback', |
| creationFn: glProt.createTransformFeedback, |
| bindFn: glProt.bindTransformFeedback, |
| bindConstant: glProt.TRANSFORM_FEEDBACK, |
| retrieveConstant: glProt.TRANSFORM_FEEDBACK_BINDING, |
| name: "TRANSFORM_FEEDBACK_BINDING", |
| }, |
| { |
| typeName: 'WebGLVertexArrayObject', |
| creationFn: glProt.createVertexArray, |
| bindFn: glProt.bindVertexArray, |
| bindConstant: null, |
| retrieveConstant: glProt.VERTEX_ARRAY_BINDING, |
| name: "VERTEX_ARRAY_BINDING", |
| }, |
| { |
| typeName: 'WebGLTexture', |
| creationFn: glProt.createTexture, |
| bindFn: glProt.bindTexture, |
| bindConstant: glProt.TEXTURE_3D, |
| retrieveConstant: glProt.TEXTURE_BINDING_3D, |
| name: "TEXTURE_BINDING_3D", |
| }, |
| { |
| typeName: 'WebGLTexture', |
| creationFn: glProt.createTexture, |
| bindFn: glProt.bindTexture, |
| bindConstant: glProt.TEXTURE_2D_ARRAY, |
| retrieveConstant: glProt.TEXTURE_BINDING_2D_ARRAY, |
| name: "TEXTURE_BINDING_2D_ARRAY", |
| }, |
| { |
| typeName: 'WebGLFramebuffer', |
| creationFn: glProt.createFramebuffer, |
| bindFn: glProt.bindFramebuffer, |
| bindConstant: glProt.READ_FRAMEBUFFER, |
| retrieveConstant: glProt.READ_FRAMEBUFFER_BINDING, |
| name: "READ_FRAMEBUFFER_BINDING", |
| }, |
| { |
| typeName: 'WebGLFramebuffer', |
| creationFn: glProt.createFramebuffer, |
| bindFn: glProt.bindFramebuffer, |
| bindConstant: glProt.DRAW_FRAMEBUFFER, |
| retrieveConstant: glProt.DRAW_FRAMEBUFFER_BINDING, |
| name: "DRAW_FRAMEBUFFER_BINDING", |
| }, |
| { |
| typeName: 'WebGLBuffer', |
| creationFn: glProt.createBuffer, |
| bindFn: glProt.bindBuffer, |
| bindConstant: glProt.COPY_READ_BUFFER, |
| retrieveConstant: glProt.COPY_READ_BUFFER_BINDING, |
| name: "COPY_READ_BUFFER_BINDING", |
| }, |
| { |
| typeName: 'WebGLBuffer', |
| creationFn: glProt.createBuffer, |
| bindFn: glProt.bindBuffer, |
| bindConstant: glProt.COPY_WRITE_BUFFER, |
| retrieveConstant: glProt.COPY_WRITE_BUFFER_BINDING, |
| name: "COPY_WRITE_BUFFER_BINDING", |
| }, |
| { |
| typeName: 'WebGLBuffer', |
| creationFn: glProt.createBuffer, |
| bindFn: glProt.bindBuffer, |
| bindConstant: glProt.PIXEL_PACK_BUFFER, |
| retrieveConstant: glProt.PIXEL_PACK_BUFFER_BINDING, |
| name: "PIXEL_PACK_BUFFER_BINDING", |
| }, |
| { |
| typeName: 'WebGLBuffer', |
| creationFn: glProt.createBuffer, |
| bindFn: glProt.bindBuffer, |
| bindConstant: glProt.PIXEL_UNPACK_BUFFER, |
| retrieveConstant: glProt.PIXEL_UNPACK_BUFFER_BINDING, |
| name: "PIXEL_UNPACK_BUFFER_BINDING", |
| }, |
| { |
| typeName: 'WebGLBuffer', |
| creationFn: glProt.createBuffer, |
| bindFn: glProt.bindBuffer, |
| bindConstant: glProt.TRANSFORM_FEEDBACK_BUFFER, |
| retrieveConstant: glProt.TRANSFORM_FEEDBACK_BUFFER_BINDING, |
| name: "TRANSFORM_FEEDBACK_BUFFER_BINDING", |
| }, |
| { |
| typeName: 'WebGLBuffer', |
| creationFn: glProt.createBuffer, |
| bindFn: glProt.bindBuffer, |
| bindConstant: glProt.UNIFORM_BUFFER, |
| retrieveConstant: glProt.UNIFORM_BUFFER_BINDING, |
| name: "UNIFORM_BUFFER_BINDING", |
| }, |
| ]; |
| |
| simpleData.forEach(function(test) { |
| var instance = test.creationFn.call(gl); |
| var msg = "getParameter(" + test.name + ")"; |
| setTestExpandos(instance); |
| |
| if (test.bindConstant === null) { |
| test.bindFn.call(gl, instance); |
| } else { |
| test.bindFn.call(gl, test.bindConstant, instance); |
| } |
| assertMsg(instance === gl.getParameter(test.retrieveConstant), msg + " returns instance that was bound."); |
| |
| // Garbage collect Javascript references. Remaining references should be internal to WebGL. |
| instance = null; |
| webglHarnessCollectGarbage(); |
| |
| var retrievedObject = gl.getParameter(test.retrieveConstant); |
| verifyTestExpandos(retrievedObject, msg); |
| shouldBeType(retrievedObject, test.typeName); |
| debug(''); |
| }); |
| } |
| |
| function testIndexedBindings() { |
| debug('Indexed Bindings'); |
| |
| // Test data that describes how to create, bind, and retrieve an indexed object off of the context |
| var glProt = Object.getPrototypeOf(gl); |
| var simpleData = [ |
| { |
| typeName: 'WebGLBuffer', |
| creationFn: glProt.createBuffer, |
| bindFn: glProt.bindBufferBase, |
| indexMax: gl.getParameter(glProt.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS) - 1, |
| bindConstant: glProt.TRANSFORM_FEEDBACK_BUFFER, |
| retrieveConstant: glProt.TRANSFORM_FEEDBACK_BUFFER_BINDING, |
| name: "TRANSFORM_FEEDBACK_BUFFER_BINDING", |
| }, |
| { |
| typeName: 'WebGLBuffer', |
| creationFn: glProt.createBuffer, |
| bindFn: glProt.bindBufferBase, |
| indexMax: gl.getParameter(glProt.MAX_UNIFORM_BUFFER_BINDINGS) - 1, |
| bindConstant: glProt.UNIFORM_BUFFER, |
| retrieveConstant: glProt.UNIFORM_BUFFER_BINDING, |
| name: "UNIFORM_BUFFER_BINDING", |
| }, |
| ]; |
| |
| simpleData.forEach(function(test) { |
| // This test sets all of the separate indexed bindings first, then |
| // tests them all. It puts a different extra expando on each indexed |
| // parameter so that we can ensure they're all distinct. |
| var instances = []; |
| for (var i = 0; i <= test.indexMax; i++) { |
| var instance = test.creationFn.call(gl); |
| var msg = "getIndexedParameter(" + test.name + ", " + i + ")"; |
| setTestExpandos(instance, i); |
| instances[i] = instance; |
| test.bindFn.call(gl, test.bindConstant, i, instance); |
| } |
| |
| for (var i = 0; i <= test.indexMax; i++) { |
| var msg = "getIndexedParameter(" + test.name + ", " + i + ")"; |
| assertMsg(instances[i] === gl.getIndexedParameter(test.retrieveConstant, i), msg + " returns instance that was bound."); |
| } |
| |
| // Garbage collect Javascript references. Remaining references should be internal to WebGL. |
| instances = null; |
| webglHarnessCollectGarbage(); |
| |
| for (var i = 0; i <= test.indexMax; i++) { |
| var msg = "getIndexedParameter(" + test.name + ", " + i + ")"; |
| var retrievedObject = gl.getIndexedParameter(test.retrieveConstant, i); |
| verifyTestExpandos(retrievedObject, msg, i); |
| shouldBeType(retrievedObject, test.typeName); |
| debug(''); |
| } |
| }); |
| } |
| |
| function testQueries() { |
| debug('Query'); |
| |
| expandoValue = "First query"; |
| var query1 = gl.createQuery(); |
| setTestExpandos(query1); |
| gl.beginQuery(gl.ANY_SAMPLES_PASSED, query1); |
| |
| expandoValue = "Second query"; |
| var query2 = gl.createQuery(); |
| setTestExpandos(query2); |
| gl.beginQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query2); |
| |
| |
| assertMsg(query1 === gl.getQuery(gl.ANY_SAMPLES_PASSED, gl.CURRENT_QUERY), "CURRENT_QUERY returns instance that was bound."); |
| assertMsg(query2 === gl.getQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, gl.CURRENT_QUERY), "CURRENT_QUERY returns instance that was bound."); |
| |
| // Garbage collect Javascript references. Remaining references should be internal to WebGL. |
| query1 = null; |
| query2 = null; |
| webglHarnessCollectGarbage(); |
| |
| var retrievedQuery1 = gl.getQuery(gl.ANY_SAMPLES_PASSED, gl.CURRENT_QUERY); |
| var retrievedQuery2 = gl.getQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, gl.CURRENT_QUERY); |
| expandoValue = "First query"; |
| verifyTestExpandos(retrievedQuery1, "Query"); |
| shouldBeType(retrievedQuery1, 'WebGLQuery'); |
| |
| expandoValue = "Second query"; |
| verifyTestExpandos(retrievedQuery2, "Query"); |
| shouldBeType(retrievedQuery2, 'WebGLQuery'); |
| |
| gl.endQuery(gl.ANY_SAMPLES_PASSED); |
| gl.endQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); |
| |
| debug(''); |
| } |
| |
| // Run tests |
| testBasicBindings(); |
| testIndexedBindings(); |
| testQueries(); |
| |
| // FYI: There's no need to test WebGLSync objects because there is no notion of an "active" sync, |
| // and thus no way to query them back out of the context. |
| |
| var successfullyParsed = true; |
| </script> |
| <script src="../../js/js-test-post.js"></script> |
| </body> |
| </html> |