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 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});
// Helpers that set expandos and verify they are set to the correct value.
var expandoValue = "WebGL is awesome!"
function setTestExpandos(instance) {
instance.expando1 = expandoValue;
instance.expando2 = { subvalue : expandoValue };
}
function verifyTestExpandos(instance, msg) {
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.");
}
// 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 = [
{
creationFn: glProt.createTexture,
bindFn: glProt.bindTexture,
bindConstant: glProt.TEXTURE_2D,
retrieveConstant: glProt.TEXTURE_BINDING_2D,
name: "TEXTURE_BINDING_2D",
},
{
creationFn: glProt.createFramebuffer,
bindFn: glProt.bindFramebuffer,
bindConstant: glProt.FRAMEBUFFER,
retrieveConstant: glProt.FRAMEBUFFER_BINDING,
name: "FRAMEBUFFER_BINDING",
},
{
creationFn: glProt.createRenderbuffer,
bindFn: glProt.bindRenderbuffer,
bindConstant: glProt.RENDERBUFFER,
retrieveConstant: glProt.RENDERBUFFER_BINDING,
name: "RENDERBUFFER_BINDING",
},
{
creationFn: glProt.createBuffer,
bindFn: glProt.bindBuffer,
bindConstant: glProt.ELEMENT_ARRAY_BUFFER,
retrieveConstant: glProt.ELEMENT_ARRAY_BUFFER_BINDING,
name: "ELEMENT_ARRAY_BUFFER_BINDING",
},
{
creationFn: glProt.createBuffer,
bindFn: glProt.bindBuffer,
bindConstant: glProt.ARRAY_BUFFER,
retrieveConstant: glProt.ARRAY_BUFFER_BINDING,
name: "ARRAY_BUFFER_BINDING",
},
{
creationFn: glProt.createTexture,
bindFn: glProt.bindTexture,
bindConstant: glProt.TEXTURE_CUBE_MAP,
retrieveConstant: glProt.TEXTURE_BINDING_CUBE_MAP,
name: "TEXTURE_BINDING_CUBE_MAP",
},
];
simpleData.forEach(function(test) {
var instance = test.creationFn.apply(gl, []);
var msg = "getParameter(" + test.name + ")";
setTestExpandos(instance);
test.bindFn.apply(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();
verifyTestExpandos(gl.getParameter(test.retrieveConstant), msg);
});
debug('');
}
// Attach a couple of shaders to a program and verify no expando loss when you call
// getAttachedShaders and getParameter(CURRENT_PROGRAM).
function testProgramsAndShaders() {
debug('Programs and Shaders');
var vs = wtu.loadShader(gl, wtu.simpleVertexShader, gl.VERTEX_SHADER);
setTestExpandos(vs);
var fs = wtu.loadShader(gl, wtu.simpleColorFragmentShader, gl.FRAGMENT_SHADER);
setTestExpandos(fs);
var program = wtu.setupProgram(gl, [vs, fs]);
setTestExpandos(program);
assertMsg(program === gl.getParameter(gl.CURRENT_PROGRAM), "getParameter(gl.CURRENT_PROGRAM) return instance set with useProgram");
var attachedShaders = gl.getAttachedShaders(program);
assertMsg(attachedShaders.indexOf(vs) !== -1, "Vertex shader instance found in getAttachedShaders");
assertMsg(attachedShaders.indexOf(fs) !== -1, "Fragment shader instance found in getAttachedShaders");
// Garbage collect Javascript references. Remaining references should be internal to WebGL.
attachedShaders = null;
program = null;
vs = null;
fs = null;
webglHarnessCollectGarbage();
var currentProgram = gl.getParameter(gl.CURRENT_PROGRAM);
verifyTestExpandos(currentProgram, "Current program");
shouldBeType(currentProgram, 'WebGLProgram');
var retrievedShaders = gl.getAttachedShaders(currentProgram);
verifyTestExpandos(retrievedShaders[0], "Shader[0]");
shouldBeType(retrievedShaders[0], "WebGLShader");
verifyTestExpandos(retrievedShaders[1], "Shader[1]");
shouldBeType(retrievedShaders[1], "WebGLShader");
debug('');
}
// Attach a buffer via vertexAttribPointer and verify no expando loss when you call getVertexAttrib.
function testVertexAttributeBuffers() {
debug('Vertex Attribute Buffers');
var program = wtu.setupSimpleColorProgram(gl);
var position = gl.getAttribLocation(program, "vPosition");
var buffer = gl.createBuffer();
setTestExpandos(buffer);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
assertMsg(buffer === gl.getVertexAttrib(position, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING),
"getVertexAttrib(VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) return instance set with vertexAttribPointer");
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Garbage collect Javascript references. Remaining references should be internal to WebGL.
buffer = null;
program = null;
webglHarnessCollectGarbage();
var retrievedBuffer = gl.getVertexAttrib(position, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
verifyTestExpandos(retrievedBuffer, "Vertex Attribute Buffer");
shouldBeType(retrievedBuffer, 'WebGLBuffer');
debug('');
}
// Attach renderbuffers to framebuffers and verify no expando loss ocurrs when you call
// getFramebufferAttachmentParameter
function testFrameBufferAttachments() {
debug('FrameBuffer Attachments');
var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
var attachments = [
{ enum: gl.COLOR_ATTACHMENT0, name: "COLOR_ATTACHMENT0" },
{ enum: gl.DEPTH_ATTACHMENT, name: "DEPTH_ATTACHMENT" },
{ enum: gl.STENCIL_ATTACHMENT, name: "STENCIL_ATTACHMENT" },
{ enum: gl.DEPTH_STENCIL_ATTACHMENT,name: "DEPTH_STENCIL_ATTACHMENT" },
];
// Attach a renderbuffer to all attachment points.
attachments.forEach(function(attachment) {
var renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
setTestExpandos(renderbuffer);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment.enum, gl.RENDERBUFFER, renderbuffer);
assertMsg(renderbuffer === gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, attachment.enum, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME),
"getFramebufferAttachmentParameter(" + attachment.name + ") returns instance set with framebufferRenderbuffer");
renderbuffer = null;
});
// Garbage collect Javascript references. Remaining references should be internal to WebGL.
webglHarnessCollectGarbage();
// Verify all attached renderbuffers have expandos.
attachments.forEach(function(attachment) {
var retrievedRenderbuffer = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, attachment.enum, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
verifyTestExpandos(retrievedRenderbuffer, attachment.name);
shouldBeType(retrievedRenderbuffer, 'WebGLRenderbuffer');
});
debug('');
}
// Run tests
testBasicBindings();
testProgramsAndShaders();
testVertexAttributeBuffers();
testFrameBufferAttachments();
var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>
</body>
</html>