Source code
Revision control
Copy as Markdown
Other Tools
<!--
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>