841 lines
29 KiB
JavaScript
841 lines
29 KiB
JavaScript
/*
|
|
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;
|
|
}
|
|
|