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.
*/
// Some variables that will be used in this file
var canvas;
var gl;
var OES_vertex_array_object;
var uniformLocation;
var WEBGL_lose_context;
var buffer;
var framebuffer;
var program;
var renderbuffer;
var shader;
var texture;
var arrayBuffer;
var arrayBufferView;
var vertexArrayObject;
var imageData;
var float32array;
var int32array;
var OES_texture_float;
var new_WEBGL_lose_context;
var allowRestore;
var contextLostEventFired;
var contextRestoredEventFired;
var newExtension;
function compareGLError(glError, evalStr) {
var exception;
try {
eval(evalStr);
} catch (e) {
exception = e;
}
if (exception) {
return false;
} else {
if (gl.getError() == glError)
return true;
return false;
}
}
function contextCreation(contextType) {
canvas = new OffscreenCanvas(10, 10);
gl = canvas.getContext(contextType);
if (contextType == 'webgl') {
if (gl instanceof WebGLRenderingContext)
return true;
return false;
} else if (contextType == 'webgl2') {
if (gl instanceof WebGL2RenderingContext)
return true;
return false;
} else {
return false;
}
}
function transferredOffscreenCanvasCreation(placeholder, width, height) {
placeholder.width = width;
placeholder.height = height;
return placeholder.transferControlToOffscreen();
}
function assertWidthAndHeight(entity, entityName, width, height) {
if (entity.width == width && entity.height == height) {
testPassed("The width and height of " + entityName + " are correct.");
return;
}
var errMsg = "";
if (entity.width != width) {
errMsg += "The width of " + entityName + " is " + entity.width + " while expected value is " + width + ". ";
}
if (entity.height != height) {
errMsg += "The height of " + entityName + " is " + entity.height + " while expected value is " + height + ". ";
}
testFailed(errMsg);
}
var webgl1Methods = [
"getContextAttributes",
"activeTexture",
"attachShader",
"bindAttribLocation",
"bindBuffer",
"bindFramebuffer",
"bindRenderbuffer",
"bindTexture",
"blendColor",
"blendEquation",
"blendEquationSeparate",
"blendFunc",
"blendFuncSeparate",
"bufferData",
"bufferSubData",
"checkFramebufferStatus",
"clear",
"clearColor",
"clearDepth",
"clearStencil",
"colorMask",
"compileShader",
"compressedTexImage2D",
"compressedTexSubImage2D",
"copyTexImage2D",
"copyTexSubImage2D",
"createBuffer",
"createFramebuffer",
"createProgram",
"createRenderbuffer",
"createShader",
"createTexture",
"cullFace",
"deleteBuffer",
"deleteFramebuffer",
"deleteProgram",
"deleteRenderbuffer",
"deleteShader",
"deleteTexture",
"depthFunc",
"depthMask",
"depthRange",
"detachShader",
"disable",
"disableVertexAttribArray",
"drawArrays",
"drawElements",
"enable",
"enableVertexAttribArray",
"finish",
"flush",
"framebufferRenderbuffer",
"framebufferTexture2D",
"frontFace",
"generateMipmap",
"getActiveAttrib",
"getActiveUniform",
"getAttachedShaders",
"getAttribLocation",
"getParameter",
"getBufferParameter",
"getError",
"getExtension",
"getFramebufferAttachmentParameter",
"getProgramParameter",
"getProgramInfoLog",
"getRenderbufferParameter",
"getShaderParameter",
"getShaderInfoLog",
"getShaderPrecisionFormat",
"getShaderSource",
"getSupportedExtensions",
"getTexParameter",
"getUniform",
"getUniformLocation",
"getVertexAttrib",
"getVertexAttribOffset",
"hint",
"isBuffer",
"isContextLost",
"isEnabled",
"isFramebuffer",
"isProgram",
"isRenderbuffer",
"isShader",
"isTexture",
"lineWidth",
"linkProgram",
"pixelStorei",
"polygonOffset",
"readPixels",
"renderbufferStorage",
"sampleCoverage",
"scissor",
"shaderSource",
"stencilFunc",
"stencilFuncSeparate",
"stencilMask",
"stencilMaskSeparate",
"stencilOp",
"stencilOpSeparate",
"texImage2D",
"texParameterf",
"texParameteri",
"texSubImage2D",
"uniform1f",
"uniform1fv",
"uniform1i",
"uniform1iv",
"uniform2f",
"uniform2fv",
"uniform2i",
"uniform2iv",
"uniform3f",
"uniform3fv",
"uniform3i",
"uniform3iv",
"uniform4f",
"uniform4fv",
"uniform4i",
"uniform4iv",
"uniformMatrix2fv",
"uniformMatrix3fv",
"uniformMatrix4fv",
"useProgram",
"validateProgram",
"vertexAttrib1f",
"vertexAttrib1fv",
"vertexAttrib2f",
"vertexAttrib2fv",
"vertexAttrib3f",
"vertexAttrib3fv",
"vertexAttrib4f",
"vertexAttrib4fv",
"vertexAttribPointer",
"viewport",
];
var webgl2Methods = [
"getBufferSubData",
"copyBufferSubData",
"blitFramebuffer",
"framebufferTextureLayer",
"getInternalformatParameter",
"invalidateFramebuffer",
"invalidateSubFramebuffer",
"readBuffer",
"renderbufferStorageMultisample",
"texImage3D",
"texStorage2D",
"texStorage3D",
"texSubImage3D",
"copyTexSubImage3D",
"compressedTexImage3D",
"compressedTexSubImage3D",
"getFragDataLocation",
"uniform1ui",
"uniform2ui",
"uniform3ui",
"uniform4ui",
"uniform1uiv",
"uniform2uiv",
"uniform3uiv",
"uniform4uiv",
"uniformMatrix2x3fv",
"uniformMatrix3x2fv",
"uniformMatrix2x4fv",
"uniformMatrix4x2fv",
"uniformMatrix3x4fv",
"uniformMatrix4x3fv",
"vertexAttribI4i",
"vertexAttribI4iv",
"vertexAttribI4ui",
"vertexAttribI4uiv",
"vertexAttribIPointer",
"vertexAttribDivisor",
"drawArraysInstanced",
"drawElementsInstanced",
"drawRangeElements",
"drawBuffers",
"clearBufferiv",
"clearBufferuiv",
"clearBufferfv",
"clearBufferfi",
"createQuery",
"deleteQuery",
"isQuery",
"beginQuery",
"endQuery",
"getQuery",
"getQueryParameter",
"createSampler",
"deleteSampler",
"isSampler",
"bindSampler",
"samplerParameteri",
"samplerParameterf",
"getSamplerParameter",
"fenceSync",
"isSync",
"deleteSync",
"clientWaitSync",
"waitSync",
"getSyncParameter",
"createTransformFeedback",
"deleteTransformFeedback",
"isTransformFeedback",
"bindTransformFeedback",
"beginTransformFeedback",
"endTransformFeedback",
"transformFeedbackVaryings",
"getTransformFeedbackVarying",
"pauseTransformFeedback",
"resumeTransformFeedback",
"bindBufferBase",
"bindBufferRange",
"getIndexedParameter",
"getUniformIndices",
"getActiveUniforms",
"getUniformBlockIndex",
"getActiveUniformBlockParameter",
"getActiveUniformBlockName",
"uniformBlockBinding",
"createVertexArray",
"deleteVertexArray",
"isVertexArray",
"bindVertexArray",
];
function assertFunction(v, f) {
try {
if (typeof v[f] != "function") {
return false;
} else {
return true;
}
} catch(e) {
return false;
}
}
function testAPIs(contextType) {
canvas = new OffscreenCanvas(10, 10);
gl = canvas.getContext(contextType);
var passed = true;
var methods;
if (contextType == 'webgl')
methods = webgl1Methods;
else
methods = webgl1Methods.concat(webgl2Methods);
for (var i=0; i<methods.length; i++) {
var r = assertFunction(gl, methods[i]);
passed = passed && r;
}
methods.push(...["makeXRCompatible"]);
var extended = false;
for (var i in gl) {
if (typeof gl[i] == "function" && methods.indexOf(i) == -1) {
if (!extended) {
extended = true;
}
}
}
if (!passed || extended)
return false;
return true;
}
var simpleTextureVertexShader = [
'attribute vec4 vPosition;',
'attribute vec2 texCoord0;',
'varying vec2 texCoord;',
'void main() {',
' gl_Position = vPosition;',
' texCoord = texCoord0;',
'}'].join('\n');
var simpleTextureFragmentShader = [
'precision mediump float;',
'uniform sampler2D tex;',
'varying vec2 texCoord;',
'void main() {',
' gl_FragData[0] = texture2D(tex, texCoord);',
'}'].join('\n');
function getShader(gl, shaderStr, type)
{
var shader = gl.createShader(type);
gl.shaderSource(shader, shaderStr);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
return null;
return shader;
}
function setupProgram(gl, shaders, opt_attribs, opt_locations)
{
var vertexShader = getShader(gl, simpleTextureVertexShader, gl.VERTEX_SHADER);
var fragmentShader = getShader(gl, simpleTextureFragmentShader, gl.FRAGMENT_SHADER);
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
if (opt_attribs) {
for (var ii = 0; ii < opt_attribs.length; ++ii) {
gl.bindAttribLocation(
program,
opt_locations ? opt_locations[ii] : ii,
opt_attribs[ii]);
}
}
gl.linkProgram(program);
// Check the link status
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linked) {
// something went wrong with the link
gl.deleteProgram(program);
return null;
}
gl.useProgram(program);
return program;
}
function setupSimpleTextureProgram(gl, opt_positionLocation, opt_texcoordLocation)
{
opt_positionLocation = opt_positionLocation || 0;
opt_texcoordLocation = opt_texcoordLocation || 1;
return setupProgram(gl,
[simpleTextureVertexShader, simpleTextureFragmentShader],
['vPosition', 'texCoord0'],
[opt_positionLocation, opt_texcoordLocation]);
}
function testLostContextWithoutRestore()
{
// Functions with special return values.
if (!gl.isContextLost())
return false;
if (gl.getError() != gl.CONTEXT_LOST_WEBGL)
return false;
if (gl.getError() != gl.NO_ERROR)
return false;
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_UNSUPPORTED ||
gl.getAttribLocation(program, 'u_modelViewProjMatrix') != -1 ||
gl.getVertexAttribOffset(0, gl.VERTEX_ATTRIB_ARRAY_POINTER) != 0)
return false;
// Test the extension itself.
if (!compareGLError(gl.INVALID_OPERATION, "WEBGL_lose_context.loseContext()"))
return false;
imageData = new ImageData(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.
if (!compareGLError(gl.NO_ERROR, "gl.activeTexture(gl.TEXTURE0)") ||
!compareGLError(gl.NO_ERROR, "gl.attachShader(program, shader)") ||
!compareGLError(gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer)") ||
!compareGLError(gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer)") ||
!compareGLError(gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer)") ||
!compareGLError(gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, texture)") ||
!compareGLError(gl.NO_ERROR, "gl.blendColor(1.0, 1.0, 1.0, 1.0)") ||
!compareGLError(gl.NO_ERROR, "gl.blendEquation(gl.FUNC_ADD)") ||
!compareGLError(gl.NO_ERROR, "gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD)") ||
!compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.ONE, gl.ONE)") ||
!compareGLError(gl.NO_ERROR, "gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE)") ||
!compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, 0, gl.STATIC_DRAW)") ||
!compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, arrayBufferView, gl.STATIC_DRAW)") ||
!compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, arrayBuffer, gl.STATIC_DRAW)") ||
!compareGLError(gl.NO_ERROR, "gl.bufferSubData(gl.ARRAY_BUFFRE, 0, arrayBufferView)") ||
!compareGLError(gl.NO_ERROR, "gl.bufferSubData(gl.ARRAY_BUFFRE, 0, arrayBuffer)") ||
!compareGLError(gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)") ||
!compareGLError(gl.NO_ERROR, "gl.clearColor(1, 1, 1, 1)") ||
!compareGLError(gl.NO_ERROR, "gl.clearDepth(1)") ||
!compareGLError(gl.NO_ERROR, "gl.clearStencil(0)") ||
!compareGLError(gl.NO_ERROR, "gl.colorMask(1, 1, 1, 1)") ||
!compareGLError(gl.NO_ERROR, "gl.compileShader(shader)") ||
!compareGLError(gl.NO_ERROR, "gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.cullFace(gl.FRONT)") ||
!compareGLError(gl.NO_ERROR, "gl.deleteBuffer(buffer)") ||
!compareGLError(gl.NO_ERROR, "gl.deleteFramebuffer(framebuffer)") ||
!compareGLError(gl.NO_ERROR, "gl.deleteProgram(program)") ||
!compareGLError(gl.NO_ERROR, "gl.deleteRenderbuffer(renderbuffer)") ||
!compareGLError(gl.NO_ERROR, "gl.deleteShader(shader)") ||
!compareGLError(gl.NO_ERROR, "gl.deleteTexture(texture)") ||
!compareGLError(gl.NO_ERROR, "gl.depthFunc(gl.NEVER)") ||
!compareGLError(gl.NO_ERROR, "gl.depthMask(0)") ||
!compareGLError(gl.NO_ERROR, "gl.depthRange(0, 1)") ||
!compareGLError(gl.NO_ERROR, "gl.detachShader(program, shader)") ||
!compareGLError(gl.NO_ERROR, "gl.disable(gl.BLEND)") ||
!compareGLError(gl.NO_ERROR, "gl.disableVertexAttribArray(0)") ||
!compareGLError(gl.NO_ERROR, "gl.drawArrays(gl.POINTS, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.drawElements(gl.POINTS, 0, gl.UNSIGNED_SHORT, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.enable(gl.BLEND)") ||
!compareGLError(gl.NO_ERROR, "gl.enableVertexAttribArray(0)") ||
!compareGLError(gl.NO_ERROR, "gl.finish()") ||
!compareGLError(gl.NO_ERROR, "gl.flush()") ||
!compareGLError(gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, renderbuffer)") ||
!compareGLError(gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.frontFace(gl.CW)") ||
!compareGLError(gl.NO_ERROR, "gl.generateMipmap(gl.TEXTURE_2D)") ||
!compareGLError(gl.NO_ERROR, "gl.hint(gl.GENERATE_MIPMAP_HINT, gl.FASTEST)") ||
!compareGLError(gl.NO_ERROR, "gl.lineWidth(0)") ||
!compareGLError(gl.NO_ERROR, "gl.linkProgram(program)") ||
!compareGLError(gl.NO_ERROR, "gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.polygonOffset(0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.readPixels(0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") ||
!compareGLError(gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.sampleCoverage(0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.scissor(0, 0, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.shaderSource(shader, '')") ||
!compareGLError(gl.NO_ERROR, "gl.stencilFunc(gl.NEVER, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.stencilFuncSeparate(gl.FRONT, gl.NEVER, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.stencilMask(0)") ||
!compareGLError(gl.NO_ERROR, "gl.stencilMaskSeparate(gl.FRONT, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP)") ||
!compareGLError(gl.NO_ERROR, "gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.KEEP)") ||
!compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") ||
!compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData)") ||
!compareGLError(gl.NO_ERROR, "gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)") ||
!compareGLError(gl.NO_ERROR, "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)") ||
!compareGLError(gl.NO_ERROR, "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") ||
!compareGLError(gl.NO_ERROR, "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, imageData)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform1f(uniformLocation, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform1fv(uniformLocation, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform1fv(uniformLocation, [0])") ||
!compareGLError(gl.NO_ERROR, "gl.uniform1i(uniformLocation, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform1iv(uniformLocation, int32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform1iv(uniformLocation, [0])") ||
!compareGLError(gl.NO_ERROR, "gl.uniform2f(uniformLocation, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform2fv(uniformLocation, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform2fv(uniformLocation, [0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.uniform2i(uniformLocation, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform2iv(uniformLocation, int32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform2iv(uniformLocation, [0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.uniform3f(uniformLocation, 0, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform3fv(uniformLocation, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform3fv(uniformLocation, [0, 0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.uniform3i(uniformLocation, 0, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform3iv(uniformLocation, int32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform3iv(uniformLocation, [0, 0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.uniform4f(uniformLocation, 0, 0, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform4fv(uniformLocation, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform4fv(uniformLocation, [0, 0, 0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.uniform4i(uniformLocation, 0, 0, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform4iv(uniformLocation, int32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniform4iv(uniformLocation, [0, 0, 0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.uniformMatrix2fv(uniformLocation, false, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniformMatrix2fv(uniformLocation, false, [0, 0, 0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.uniformMatrix3fv(uniformLocation, false, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniformMatrix3fv(uniformLocation, false, [0, 0, 0, 0, 0, 0, 0, 0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.uniformMatrix4fv(uniformLocation, false, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.uniformMatrix4fv(uniformLocation, false, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.useProgram(program)") ||
!compareGLError(gl.NO_ERROR, "gl.validateProgram(program)") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib1f(0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib1fv(0, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib1fv(0, [0])") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib2f(0, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib2fv(0, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib2fv(0, [0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib3f(0, 0, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib3fv(0, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib3fv(0, [0, 0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib4f(0, 0, 0, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib4fv(0, float32array)") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttrib4fv(0, [0, 0, 0, 0])") ||
!compareGLError(gl.NO_ERROR, "gl.vertexAttribPointer(0, 0, gl.FLOAT, false, 0, 0)") ||
!compareGLError(gl.NO_ERROR, "gl.viewport(0, 0, 0, 0)"))
return false;
// Functions return nullable values should all return null.
if (gl.getActiveAttrib(program, 0) != null ||
gl.getActiveUniform(program, 0) != null ||
gl.getAttachedShaders(program) != null ||
gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE) != null ||
gl.getContextAttributes() != null ||
gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) != null ||
gl.getParameter(gl.CURRENT_PROGRAM) != null ||
gl.getProgramInfoLog(program) != null ||
gl.getProgramParameter(program, gl.LINK_STATUS) != null ||
gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH) != null ||
gl.getShaderInfoLog(shader) != null ||
gl.getShaderParameter(shader, gl.SHADER_TYPE) != null ||
gl.getShaderSource(shader) != null ||
gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S) != null ||
gl.getUniform(program, uniformLocation) != null ||
gl.getUniformLocation(program, 'vPosition') != null ||
gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) != null ||
gl.getSupportedExtensions() != null ||
gl.getExtension("WEBGL_lose_context") != null)
return false;
const failedTests = [
"gl.createBuffer()",
"gl.createFramebuffer()",
"gl.createProgram()",
"gl.createRenderbuffer()",
"gl.createShader(gl.VERTEX_SHADER)",
"gl.createTexture()",
].reduce(s => {
const v = eval(s);
return !v;
});
if (failedTests.length) {
console.log({failedTests});
return false;
}
// "Is" queries should all return false.
if (gl.isBuffer(buffer) || gl.isEnabled(gl.BLEND) || gl.isFramebuffer(framebuffer) ||
gl.isProgram(program) || gl.isRenderbuffer(renderbuffer) || gl.isShader(shader) ||
gl.isTexture(texture))
return false;
if (gl.getError() != gl.NO_ERROR)
return false;
// test extensions
if (OES_vertex_array_object) {
if (!compareGLError(gl.NO_ERROR, "OES_vertex_array_object.bindVertexArrayOES(vertexArrayObject)") ||
!compareGLError(gl.NO_ERROR, "OES_vertex_array_object.isVertexArrayOES(vertexArrayObject)") ||
!compareGLError(gl.NO_ERROR, "OES_vertex_array_object.deleteVertexArrayOES(vertexArrayObject)"))
return false;
if (!OES_vertex_array_object.createVertexArrayOES())
return false;
}
return true;
}
function testValidContext()
{
if (gl.isContextLost())
return false;
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 = 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);
if (gl.getError() != gl.NO_ERROR)
return false;
// Test is queries that will later be false
if (!compareGLError(gl.NO_ERROR, "gl.enable(gl.BLEND)"))
return false;
if (!gl.isBuffer(buffer) || !gl.isEnabled(gl.BLEND) || !gl.isFramebuffer(framebuffer) ||
!gl.isProgram(program) || !gl.isRenderbuffer(renderbuffer) || !gl.isShader(shader) ||
!gl.isTexture(texture))
return false;
if (OES_vertex_array_object) {
vertexArrayObject = OES_vertex_array_object.createVertexArrayOES();
if (gl.getError() != gl.NO_ERROR)
return false;
if (!OES_vertex_array_object.isVertexArrayOES(vertexArrayObject))
return false;
}
return true;
}
function setupTest()
{
canvas = new OffscreenCanvas(10, 10);
gl = canvas.getContext('webgl');
WEBGL_lose_context = gl.getExtension("WEBGL_lose_context");
if (!WEBGL_lose_context)
return false;
// Try to get a few extensions
OES_vertex_array_object = gl.getExtension("OES_vertex_array_object");
OES_texture_float = gl.getExtension("OES_texture_float");
return true;
}
function testOriginalContext()
{
if (gl.isContextLost())
return false;
if (gl.getError() != gl.NO_ERROR)
return false;
return true;
}
function testLostContext(e)
{
if (contextLostEventFired)
return false;
contextLostEventFired = true;
if (!gl.isContextLost())
return false;
if (gl.getError() != gl.NO_ERROR)
return false;
if (allowRestore)
e.preventDefault();
return true;
}
function testLosingAndRestoringContext()
{
return new Promise(function(resolve, reject) {
if (!setupTest())
reject("Test failed");
canvas.addEventListener("webglcontextlost", function(e) {
if (!testLostContext(e))
reject("Test failed");
// restore the context after this event has exited.
setTimeout(function() {
if (!compareGLError(gl.NO_ERROR, "WEBGL_lose_context.restoreContext()"))
reject("Test failed");
// The context should still be lost. It will not get restored until the
// webglrestorecontext event is fired.
if (!gl.isContextLost())
reject("Test failed");
if (gl.getError() != gl.NO_ERROR)
reject("Test failed");
// gl methods should still be no-ops
if (!compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)"))
reject("Test failed");
}, 0);
});
canvas.addEventListener("webglcontextrestored", function() {
if (!testRestoredContext())
reject("Test failed: !testRestoredContext()");
else
resolve("Test passed");
});
allowRestore = true;
contextLostEventFired = false;
contextRestoredEventFired = false;
if (!testOriginalContext())
reject("Test failed");
WEBGL_lose_context.loseContext();
// The context should be lost immediately.
if (!gl.isContextLost())
reject("Test failed");
if (gl.getError() != gl.CONTEXT_LOST_WEBGL)
reject("Test failed");
if (gl.getError() != gl.NO_ERROR)
reject("Test failed");
// gl methods should be no-ops
if (!compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)"))
reject("Test failed");
// but the event should not have been fired.
if (contextLostEventFired)
reject("Test failed");
});
}
function reGetExtensionAndTestForProperty(gl, name, expectProperty) {
var newExtension = gl.getExtension(name);
// NOTE: while getting a extension after context lost/restored is allowed to fail
// for the purpose the conformance tests it is not.
//
// Hypothetically the user can switch GPUs live. For example on Windows, install 2 GPUs,
// then in the control panen enable 1, disable the others and visa versa. Since the GPUs
// have different capabilities one or the other may not support a particlar extension.
//
// But, for the purpose of the conformance tests the context is expected to restore
// on the same GPU and therefore the extensions that succeeded previously should
// succeed on restore.
if (newExtension == null)
return false;
if (expectProperty) {
if (!(newExtension.webglTestProperty === true))
return false;
} else {
if (!(newExtension.webglTestProperty === undefined))
return false;
}
return newExtension;
}
function testOESTextureFloat() {
if (OES_texture_float) {
// Extension must still be lost.
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
if (!compareGLError(gl.INVALID_ENUM, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null)"))
return false;
// Try re-enabling extension
OES_texture_float = reGetExtensionAndTestForProperty(gl, "OES_texture_float", false);
if (!compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null)"))
return false;
return true;
}
}
function testOESVertexArrayObject() {
if (OES_vertex_array_object) {
// Extension must still be lost.
if (!OES_vertex_array_object.createVertexArrayOES()) {
console.error("!OES_vertex_array_object.createVertexArrayOES()");
return false;
}
// Try re-enabling extension
var old_OES_vertex_array_object = OES_vertex_array_object;
OES_vertex_array_object = reGetExtensionAndTestForProperty(gl, "OES_vertex_array_object", false);
if (!OES_vertex_array_object.createVertexArrayOES()) {
console.error("!OES_vertex_array_object.createVertexArrayOES() 2");
return false;
}
if (!old_OES_vertex_array_object.createVertexArrayOES()) {
console.error("!old_OES_vertex_array_object.createVertexArrayOES()");
return false;
}
return true;
}
}
function testExtensions() {
if (!testOESTextureFloat() || !testOESVertexArrayObject())
return false;
return true;
}
function testRestoredContext()
{
if (contextRestoredEventFired)
return false;
contextRestoredEventFired = true;
if (gl.isContextLost())
return false;
if (gl.getError() != gl.NO_ERROR)
return false;
if (!testExtensions())
return false;
return true;
}