### Setup and Run WebGL Occlusion Query Tests Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/query/occlusion-query.html Initializes the WebGL context, sets up test cases for occlusion queries, and begins the execution of the occlusion query tests. It handles context creation and the initial call to start the testing loop. ```javascript "use strict"; var tests = []; var currentTest; var currentTestIndex = 0; var numberOfTestAttempts = 4; // Just to stress implementations a bit more. var query; var numberOfCompletionAttempts = 0; function setupTests(gl) { tests = [ { target: gl.ANY_SAMPLES_PASSED_CONSERVATIVE, name: "ANY_SAMPLES_PASSED_CONSERVATIVE", result: 1, }, { target: gl.ANY_SAMPLES_PASSED, name: "ANY_SAMPLES_PASSED", result: 1, }, ]; } var wtu = WebGLTestUtils; var canvas = document.getElementById("canvas"); var gl = wtu.create3DContext(canvas, null, 2); if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); setupTests(gl); runOcclusionQueryTest(); } ``` -------------------------------- ### Install Git Smudge Filter (Windows CMD) Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/README.md Installs the git smudge filter configuration and forces a re-checkout of index.html files to update their last edited dates. This is for Windows Command Prompt. ```cmd install-gitconfig.bat del specs/latest/1.0/index.html specs/latest/2.0/index.html git checkout specs/latest/1.0/index.html specs/latest/2.0/index.html ``` -------------------------------- ### WebGL Multisample Test Setup and Execution Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/renderbuffers/multisample-with-full-sample-counts.html Sets up a WebGL context, compiles a color quad shader, and iterates through different multisample configurations. It calls the runTest function for each configuration. ```javascript "use strict"; var wtu = WebGLTestUtils; description(' Test multisample with sample number from 1 to max sample number which also includes the samples that may not be in the supported sample list'); var gl = wtu.create3DContext("canvas", null, 2); var size = 32; var program; if (!gl) { testFailed('canvas.getContext() failed'); } else { program = wtu.setupColorQuad(gl); gl.viewport(0, 0, size, size); var supportedSampleCountArray = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES); var iterationCount = supportedSampleCountArray[0] + 1; for (var i = 1; i < iterationCount; i++) { runTest(gl, i, false); runTest(gl, i, true); } } function runTest(gl, sampleCount, isInverted) { // Setup multi-sample RBO var msColorRbo = gl.createRenderbuffer(); gl.bindRenderbuffer(gl.RENDERBUFFER, msColorRbo); gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGBA8, size, size); // Setup multi-sample FBO. var msFbo = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, msFbo); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, msColorRbo); // Setup resolve color RBO. var resolveColorRbo = gl.createRenderbuffer(); gl.bindRenderbuffer(gl.RENDERBUFFER, resolveColorRbo); gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, size, size); // Setup resolve FBO var resolveFbo = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, resolveFbo); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, resolveColorRbo); gl.bindFramebuffer(gl.FRAMEBUFFER, msFbo); if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { testFailed("Framebuffer incomplete."); return; } gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); gl.enable(gl.SAMPLE_COVERAGE); var coverageValue = isInverted ? 0.0 : 1.0; gl.sampleCoverage(coverageValue, isInverted); var quadColor = [1.0, 0.0, 0.0, 1.0]; gl.useProgram(program); wtu.drawFloatColorQuad(gl, quadColor); gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, resolveFbo); gl.blitFramebuffer(0, 0, size, size, 0, 0, size, size, gl.COLOR_BUFFER_BIT, gl.NEAREST); gl.bindFramebuffer(gl.FRAMEBUFFER, resolveFbo); wtu.checkCanvasRect(gl, 0, 0, size, size, [255, 0, 0, 255], "User buffer has been rendered to red with sample = " + sampleCount + ", coverageValue = " + coverageValue + " and isInverted = " + isInverted, 3); gl.disable(gl.SAMPLE_COVERAGE); gl.deleteRenderbuffer(msColorRbo); gl.deleteRenderbuffer(resolveColorRbo); gl.deleteFramebuffer(msFbo); gl.deleteFramebuffer(resolveFbo); } var successfullyParsed = true; ``` -------------------------------- ### Install Git Smudge Filter (Unix-like) Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/README.md Installs the git smudge filter configuration and forces a re-checkout of index.html files to update their last edited dates. This is for Unix-based systems or Git Bash/Cygwin. ```bash ./install-gitconfig.sh rm specs/latest/*/index.html git checkout !$ ``` -------------------------------- ### JavaScript WebGL Test Setup and Execution Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/buffers/one-large-uniform-buffer.html Sets up a WebGL context, compiles shaders, and runs a test for uniform blocks with large data stores. It uses the WebGLTestUtils library for convenience. ```javascript "use strict"; description("This test covers an ANGLE bug when using a large uniform block data store. ANGLE would confuse an internal clipped uniform buffer size and produce an assert or error."); debug(""); var wtu = WebGLTestUtils; var canvas = document.getElementById("canvas"); var gl = wtu.create3DContext(canvas, null, 2); var quadVB; if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); debug(""); debug("Testing uniform block with large data store"); runTest(); } function getQuadVerts(depth) { var quadVerts = new Float32Array(3 * 6); quadVerts[0] = -1.0; quadVerts[1] = 1.0; quadVerts[2] = depth; quadVerts[3] = -1.0; quadVerts[4] = -1.0; quadVerts[5] = depth; quadVerts[6] = 1.0; quadVerts[7] = -1.0; quadVerts[8] = depth; quadVerts[9] = -1.0; quadVerts[10] = 1.0; quadVerts[11] = depth; quadVerts[12] = 1.0; quadVerts[13] = -1.0; quadVerts[14] = depth; quadVerts[15] = 1.0; quadVerts[16] = 1.0; quadVerts[17] = depth; return quadVerts; } function drawQuad(depth) { if (!quadVB) { quadVB = gl.createBuffer() } var quadVerts = getQuadVerts(depth); gl.bindBuffer(gl.ARRAY_BUFFER, quadVB); gl.bufferData(gl.ARRAY_BUFFER, quadVerts, gl.STATIC_DRAW); gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, 0); gl.enableVertexAttribArray(0); gl.drawArrays(gl.TRIANGLES, 0, 6); } function runTest() { // Create the program var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["position"]); if (!program) { testFailed("Failed to set up the program"); return; } // Init uniform buffer. To trigger the bug, it's necessary to use the // DYNAMIC_DRAW usage. This makes ANGLE attempt to map the buffer internally // with an incorrect copy size. var ubo = gl.createBuffer(); var big_size = 4096 * 64; var data = new Float32Array([0.5, 0.75, 0.25, 1.0]); gl.bindBuffer(gl.UNIFORM_BUFFER, ubo); gl.bufferData(gl.UNIFORM_BUFFER, big_size, gl.DYNAMIC_DRAW); gl.bufferSubData(gl.UNIFORM_BUFFER, 0, data); gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, ubo); var buffer_index = gl.getUniformBlockIndex(program, "uni"); if (buffer_index == -1) { testFailed("Failed to get uniform block index"); return; } gl.uniformBlockBinding(program, buffer_index, 0); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up uniform block should succeed"); // Draw the quad gl.useProgram(program); drawQuad(0.5); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Draw with uniform block should succeed"); // Verify the output color var color = [127, 191, 64, 255]; wtu.checkCanvas(gl, color, "canvas should be same as input uniform", 1); } debug(""); var successfullyParsed = true; ``` -------------------------------- ### WebGL Buffer Data and Vertex Attribute Setup Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/element-index-uint.html This snippet demonstrates setting up vertex and index buffers, configuring vertex attributes, and performing draw calls. It includes tests for out-of-range indices and error handling. ```javascript gl.bufferData(gl.ARRAY_BUFFER, dataComplete, drawType); var elements = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elements); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType); gl.useProgram(program); var vertexLoc = gl.getAttribLocation(program, "a_vertex"); var normalLoc = gl.getAttribLocation(program, "a_normal"); gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 0); gl.enableVertexAttribArray(vertexLoc); gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT)); gl.enableVertexAttribArray(normalLoc); shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); wtu.glErrorShouldBe(gl, gl.NO_ERROR); shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); wtu.glErrorShouldBe(gl, gl.NO_ERROR); debug("Testing with out-of-range indices"); var bufferIncomplete = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, bufferIncomplete); gl.bufferData(gl.ARRAY_BUFFER, dataIncomplete, drawType); gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 0); gl.enableVertexAttribArray(vertexLoc); gl.disableVertexAttribArray(normalLoc); debug("Enable vertices, valid"); wtu.glErrorShouldBe(gl, gl.NO_ERROR); shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); wtu.glErrorShouldBe(gl, gl.NO_ERROR); debug("Enable normals, out-of-range"); gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT)); gl.enableVertexAttribArray(normalLoc); wtu.glErrorShouldBe(gl, gl.NO_ERROR); shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); wtu.glErrorShouldBe(gl, [gl.NO_ERROR, gl.INVALID_OPERATION]); debug("Test with enabled attribute that does not belong to current program"); gl.disableVertexAttribArray(normalLoc); var extraLoc = Math.max(vertexLoc, normalLoc) + 1; gl.enableVertexAttribArray(extraLoc); debug("Enable an extra attribute with null"); wtu.glErrorShouldBe(gl, gl.NO_ERROR); shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); debug("Enable an extra attribute with insufficient data buffer"); gl.vertexAttribPointer(extraLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT)); wtu.glErrorShouldBe(gl, gl.NO_ERROR); shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); debug("Pass large negative index to vertexAttribPointer"); gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), -2000000000 * sizeInBytes(gl.FLOAT)); wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); ``` -------------------------------- ### Install spglsl using npm Source: https://github.com/salvatorepreviti/spglsl/blob/master/README.md This command installs the spglsl package as a project dependency using npm. It's the standard way to add the minifier to your JavaScript project. ```sh npm i spglsl --save ``` -------------------------------- ### JavaScript WebGL Test Setup and Initialization Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/element-index-uint.html Initializes WebGL context and sets up the testing environment. It iterates through STATIC_DRAW and DYNAMIC_DRAW modes to test different buffer update behaviors. Includes basic error checking for context creation. ```javascript "use strict"; description("This test verifies the functionality of the Uint element indices."); debug(""); var wtu = WebGLTestUtils; var gl = null; var canvas = null; // Test both STATIC_DRAW and DYNAMIC_DRAW as a regression test // for a bug in ANGLE which has since been fixed. for (var ii = 0; ii < 2; ++ii) { canvas = document.createElement("canvas"); canvas.width = 50; canvas.height = 50; gl = wtu.create3DContext(canvas, null, 2); if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); var drawType = (ii == 0) ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW; debug("Testing " + ((ii == 0) ? "STATIC_DRAW" : "DYNAMIC_DRAW")); runDrawTests(drawType); // These tests are tweaked duplicates of the buffers/index-validation* tests // using unsigned int indices to ensure that behavior remains consistent runIndexValidationTests(drawType); runCopiesIndicesTests(drawType); runResizedBufferTests(drawType); runVerifiesTooManyIndicesTests(drawType); runCrashWithBufferSubDataTests(drawType); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); } } ``` -------------------------------- ### JavaScript WebGL UniformBlock Buffer Size Test Setup Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/uniform-block-buffer-size.html Initializes the WebGL context and sets up the testing environment for UniformBlock buffer size conformance. It checks for context creation and then proceeds to run drawArrays and drawElements tests. ```javascript "use strict"; description("This test verifies an active UniformBlock should be populated with a large enough buffer object"); debug(""); var wtu = WebGLTestUtils; var canvas = document.getElementById("canvas"); var gl = wtu.create3DContext(canvas, null, 2); if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); runDrawArraysTests(); runDrawElementsTests(); } ``` -------------------------------- ### WebGL Test Setup and Execution Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/blitframebuffer-stencil-only.html Sets up the WebGL context, compiles shaders, links programs, and initializes uniforms for blitFramebuffer tests. It then executes stencil-only blit tests with different depth-stencil formats. ```javascript if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); program = wtu.setupProgram(gl, ["vs", "fs"], ["position"]); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after program initialization"); shouldBe('gl.getProgramParameter(program, gl.LINK_STATUS)', 'true'); colorLoc = gl.getUniformLocation(program, "color") wtu.glErrorShouldBe(gl, gl.NO_ERROR, "query uniform location"); shouldBeNonNull('colorLoc') test_stencil_only_blit(gl.DEPTH24_STENCIL8); test_stencil_only_blit(gl.DEPTH32F_STENCIL8); } ``` -------------------------------- ### WebGL Transform Feedback Test Setup (JavaScript) Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/transform_feedback/two-unreferenced-varyings.html This JavaScript code sets up and runs a WebGL transform feedback test. It initializes the WebGL context, creates buffers, and configures transform feedback. It relies on the WebGLTestUtils library. ```javascript "use strict"; description("This test covers an ANGLE bug with two transform feedback varyings. When the two are declared, but not referenced in the fragment shader, ANGLE would fail capture."); debug(""); var wtu = WebGLTestUtils; var canvas = document.getElementById("canvas"); var gl = wtu.create3DContext(canvas, null, 2); var quadVB; if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); debug(""); debug("Testing transform feedback with two unreferenced outputs"); runTest(); } ``` -------------------------------- ### JavaScript: WebGL Context Initialization and Test Setup Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/attrib-type-match.html This JavaScript code initializes a WebGL rendering context and performs initial setup for conformance tests. It checks for context creation success and calls functions to test generic vertex attributes and run main test procedures. ```javascript "use strict"; description("This test verifies an active vertex attribute's base type has to match the verexAttrib function type."); debug(""); var wtu = WebGLTestUtils; var canvas = document.getElementById("canvas"); var gl = wtu.create3DContext(canvas, null, 2); if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); testGenericAttribs(); runTests(); } ``` -------------------------------- ### JavaScript WebGL Feedback Loop Test Setup and Execution Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/rendering-sampling-feedback-loop.html Sets up the WebGL context, shaders, and resources for testing rendering feedback loops. It then executes tests with different draw buffer configurations and checks for expected WebGL errors. ```javascript "use strict"; var wtu = WebGLTestUtils; description("This test verifies the functionality of rendering to the same texture where it samples from."); var gl = wtu.create3DContext("example", undefined, 2); var width = 8; var height = 8; var tex0; var tex1; var fbo; var program; var positionLoc; var texCoordLoc; if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); init(); // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation allocate_resource(); rendering_sampling_feedback_loop([gl.NONE, gl.COLOR_ATTACHMENT1], gl.INVALID_OPERATION); rendering_sampling_feedback_loop([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1], gl.INVALID_OPERATION); rendering_sampling_feedback_loop([gl.COLOR_ATTACHMENT0, gl.NONE], gl.NO_ERROR); } function init() { program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['aPosition', 'aTexCoord'], [0, 1]); positionLoc = gl.getAttribLocation(program, "aPosition"); texCoordLoc = gl.getAttribLocation(program, "aTexCoord"); if (!program || positionLoc < 0 || texCoordLoc < 0) { testFailed("Set up program failed"); return; } testPassed("Set up program succeeded"); wtu.setupUnitQuad(gl, 0, 1); gl.viewport(0, 0, width, height); } function allocate_resource() { tex0 = gl.createTexture(); tex1 = gl.createTexture(); fbo = gl.createFramebuffer(); wtu.fillTexture(gl, tex0, width, height, [0xff, 0x0, 0x0, 0xff], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.RGBA); wtu.fillTexture(gl, tex1, width, height, [0x0, 0xff, 0x0, 0xff], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.RGBA); gl.bindTexture(gl.TEXTURE_2D, tex1); var texLoc = gl.getUniformLocation(program, "tex"); gl.uniform1i(texLoc, 0); gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex0, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex1, 0); } function rendering_sampling_feedback_loop(draw_buffers, error) { gl.drawBuffers(draw_buffers); // Make sure framebuffer is complete before feedback loop detection if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { testFailed("Framebuffer incomplete."); return; } wtu.clearAndDrawUnitQuad(gl); wtu.glErrorShouldBe(gl, error, "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise, it should be NO_ERROR"); } gl.bindTexture(gl.TEXTURE_2D, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.deleteTexture(tex0); gl.deleteTexture(tex1); gl.deleteFramebuffer(fbo); var successfullyParsed = true; ``` -------------------------------- ### Clone Repository with Git Submodules Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/README.md Clones the WebGL repository and its git submodules, ensuring that dependent repositories like WebGLDeveloperTools are correctly installed. ```bash git clone --recursive [URL] ``` -------------------------------- ### Setup WebGL Program for SPGLSL Tests Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/reading/format-r11f-g11f-b10f.html Sets up a WebGL program by compiling and linking vertex and fragment shaders. It retrieves uniform locations for color, tolerance, and texture, and also sets up unit quad buffers. This function is crucial for rendering and testing operations within the SPGLSL project. Dependencies include WebGL context and utility functions like wtu.setupProgram and wtu.setupUnitQuad. ```javascript function setupProgram() { var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["pos", "texCoord0"]); if (!program) return null; program.colorPos = gl.getUniformLocation(program, "u_color"); program.tolPos = gl.getUniformLocation(program, "u_tol"); var texPos = gl.getUniformLocation(program, "u_tex"); program.buffers = wtu.setupUnitQuad(gl, 0, 1); if (!program.colorPos || !program.tolPos || !texPos || program.buffers.length == 0) { gl.deleteProgram(program); return null; } gl.useProgram(program); gl.uniform1i(texPos, 0); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup program should succeed."); return program; } ``` -------------------------------- ### JavaScript - WebGL Context Setup and Shader Program Creation Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/draw-buffers.html JavaScript code to set up a WebGL 2 context and create a shader program. It includes error handling for context creation and uses helper functions for shader compilation and linking. ```javascript "use strict"; description("This test verifies the functionality of Multiple Render Targets."); debug(""); var wtu = WebGLTestUtils; var canvas = document.getElementById("canvas"); var output = document.getElementById("console"); var gl = wtu.create3DContext(canvas, null, 2); if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); if (testParameters()) { runShadersTest(); runAttachmentTest(); runDrawTests(); } wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); } function createDrawBuffersProgram(scriptId, sub) { var fsource = wtu.getScript(scriptId); fsource = wtu.replaceParams(fsource, sub); wtu.addShaderSource(output, "fragment shader", fsource); return wtu.setupProgram(gl, ["vshaderESSL3", fsource], ["a_position"]) } ``` -------------------------------- ### Setup WebGL Context and Canvas Texture Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/samplers/sampler-drawing-test.html Initializes the WebGL context and sets up a 1x1 pixel canvas texture with a specific color. This function is crucial for providing the texture data used in subsequent drawing operations. ```javascript "use strict"; description("Tests drawing with sampler works as expected"); debug(""); var wtu = WebGLTestUtils; var gl = wtu.create3DContext("canvas_drawing", null, 2); var canvas_texture = null; var samplerParam = [ gl.REPEAT, gl.CLAMP_TO_EDGE, gl.MIRRORED_REPEAT, ]; var color = [200, 0, 254, 255]; if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); wtu.setupTexturedQuadWithTexCoords(gl, [-2.5, -2.5], [3.5, 3.5]); setupCanvasTexture(); for (var ii = 0; ii < samplerParam.length; ++ii) { runDrawingTest(samplerParam[ii]); } wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); } function setupCanvasTexture() { canvas_texture = document.getElementById("canvas_texture"); var ctx2d = canvas_texture.getContext("2d"); ctx2d.fillStyle = "rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + color[3] + ")"; ctx2d.fillRect(0, 0, 1, 1); } ``` -------------------------------- ### WebGL Setup and Drawing with Vertex Attributes (JavaScript) Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/attrib-type-match.html This snippet covers the setup of vertex attribute pointers and subsequent drawing calls using `gl.drawArrays` and `gl.drawArraysInstanced`. It tests correct attribute pointer configuration and verifies that drawing operations succeed without errors when attributes are set up properly. Dependencies include a WebGLRenderingContext (`gl`), utility functions `wtu.setupUnitQuad`, `wtu.glErrorShouldBe`, `wtu.checkCanvasRect`, and `setupAttribPointers`. ```javascript gl.enableVertexAttribArray(offsetILoc); gl.enableVertexAttribArray(offsetULoc); gl.enableVertexAttribArray(colorLoc); debug(""); debug("Test vertexAttrib{I}Pointer with drawArrays and drawArraysInstanced"); wtu.setupUnitQuad(gl, 0); debug("Correct setup"); setupAttribPointers(offsetILoc, offsetULoc, colorLoc, offsetIBuffer, offsetUBuffer, colorBuffer); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); gl.drawArrays(gl.TRIANGLES, 0, 6); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds"); wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]); gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced succeeds"); wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]); ``` -------------------------------- ### WebGL Transform Feedback Varyings Setup and Test Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/transform_feedback/transform_feedback.html Sets up a transform feedback program and tests the gl.transformFeedbackVaryings function. It verifies the number of varyings and checks individual varying properties before and after relinking the program. ```javascript function runVaryingsTest() { debug(""); debug("Testing transform feedback varyings"); // Create the transform feedback shader. This is explicitly run after runFeedbackTest, // as re-llinking the shader here will test browser caching. program = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"], ["out_add", "out_mul"], gl.SEPARATE_ATTRIBS, ["in_data"]); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error"); shouldBeNonNull("program"); // Check the varyings shouldBe("gl.getProgramParameter(program, gl.TRANSFORM_FEEDBACK_VARYINGS)", "2"); verifyTransformFeedbackVarying(program, 0, true, "out_add"); verifyTransformFeedbackVarying(program, 1, true, "out_mul"); verifyTransformFeedbackVarying(program, 2, false); // transformFeedbackVaryings() doesn't take effect until a successful link. gl.transformFeedbackVaryings(program, ["out_mul"], gl.SEPARATE_ATTRIBS); shouldBe("gl.getProgramParameter(program, gl.TRANSFORM_FEEDBACK_VARYINGS)", "2"); verifyTransformFeedbackVarying(program, 0, true, "out_add"); verifyTransformFeedbackVarying(program, 1, true, "out_mul"); verifyTransformFeedbackVarying(program, 2, false); // Now relink. gl.linkProgram(program); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error"); shouldBeTrue("gl.getProgramParameter(program, gl.LINK_STATUS)"); shouldBe("gl.getProgramParameter(program, gl.TRANSFORM_FEEDBACK_VARYINGS)", "1"); verifyTransformFeedbackVarying(program, 0, true, "out_mul"); verifyTransformFeedbackVarying(program, 1, false); verifyTransformFeedbackVarying(program, 2, false); finishTest(); } debug(""); ``` -------------------------------- ### WebGL Indexed Drawing Setup and Tests with drawElements Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/attrib-type-match.html Sets up an indexed quad using `setupIndexedQuad` and tests `drawElements`, `drawRangeElements`, and `drawElementsInstanced`. It verifies correct rendering and checks for `NO_ERROR` after successful operations. Dependencies include `wtu` and `setupAttribValues`. ```javascript wtu.setupIndexedQuad(gl, 1, 0); setupAttribValues(offsetILoc, offsetULoc, colorLoc); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements succeeds"); wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]); gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawRangeElements succeeds"); wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]); gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced succeeds"); wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]); ``` -------------------------------- ### GLSL Fragment Shader - Multiple Render Targets Setup Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/draw-buffers.html A GLSL fragment shader demonstrating the setup for Multiple Render Targets (MRT). It declares an array of output variables 'my_FragData' and uses a uniform array 'u_colors' to set their values. This shader is designed to work with ESSL 3. ```glsl #version 300 es precision mediump float; uniform vec4 u_colors[$(numDrawingBuffers)]; // Only one out variable - does not need explicit output layout (ESSL 3 section 4.3.8.2) out vec4 my_FragData[$(numDrawingBuffers)]; void main() { $(assignUColorsToFragData) } ``` -------------------------------- ### WebGL Setup and Basic Drawing with drawArrays Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/attrib-type-match.html Sets up a WebGL program and a unit quad, then uses `drawArrays` to render it. It includes error checking and canvas content verification. Dependencies include `wtu` (WebGL Test Utilities) and `setupAttribValues`. ```javascript const [positionLoc, offsetILoc, offsetULoc, colorLoc] = wtu.getProgramAttributeLocations(program, ['aPosition', 'aOffsetI', 'aOffsetU', 'aColor']); setupAttribValues(offsetILoc, offsetULoc, colorLoc); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); gl.drawArrays(gl.TRIANGLES, 0, 6); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds"); wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]); ``` -------------------------------- ### Initialize WebGL Context and Setup Color Quad Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/blitframebuffer-multisampled-readbuffer.html Initializes the WebGL rendering context and sets up a shader program for drawing a colored quad. This is a prerequisite for most rendering operations within the test suite. It checks for context creation success and sets the viewport. ```javascript "use strict"; var wtu = WebGLTestUtils; description("This test verifies the functionality of blitFramebuffer with multisampled sRGB color buffer."); var gl = wtu.create3DContext("canvas", undefined, 2); var tex_blit = gl.createTexture(); var fb0 = gl.createFramebuffer(); var rb0 = gl.createRenderbuffer(); var fbo_blit = gl.createFramebuffer(); var size = 32; var program; if (!gl) { testFailed("WebGL context does not exist"); } else { testPassed("WebGL context exists"); init(); var filters = [gl.LINEAR, gl.NEAREST]; for (var ii = 0; ii < filters.length; ++ii) { blitframebuffer_multisampled_readbuffer(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, filters[ii]); } } function init() { program = wtu.setupColorQuad(gl); gl.viewport(0, 0, size, size); } ``` -------------------------------- ### Setup and Initialization for Draw Tests (JavaScript) Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/rendering/draw-buffers.html Initializes WebGL context, creates multiple framebuffers (fb, fb2, halfFB1, halfFB2, endsFB, middleFB), and retrieves WebGL limits such as MAX_DRAW_BUFFERS and MAX_COLOR_ATTACHMENTS. It prepares color attachment arrays and shader programs for testing. ```javascript function runDrawTests() { debug(""); debug("--------- draw tests -----------"); var fb = gl.createFramebuffer(); var fb2 = gl.createFramebuffer(); var halfFB1 = gl.createFramebuffer(); var halfFB2 = gl.createFramebuffer(); var endsFB = gl.createFramebuffer(); var middleFB = gl.createFramebuffer(); var maxDrawingBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS); var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS); var maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS); var maxUsable = Math.min(maxDrawingBuffers, maxColorAttachments, maxUniformVectors); var half = Math.floor(maxUsable / 2); var bufs = makeColorAttachmentArray(maxUsable); var nones = makeArray(maxUsable, gl.NONE); [fb, fb2, halfFB1, halfFB2, endsFB, middleFB].forEach(function (fbo) { gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); gl.drawBuffers(bufs); }); var checkProgram = wtu.setupTexturedQuad(gl); var redProgram = wtu.setupProgram(gl, ["vshaderESSL3", "fshaderRed"], ["a_position"] ); var blueProgramESSL1 = wtu.setupProgram(gl, ["vshaderESSL1", "fshaderBlueESSL1"], ["a_position"] ); var assignCode = []; for (var i = 0; i < maxDrawingBuffers; ++i) { assignCode.push(" my_FragData[" + i + "] = u_colors[" + i + "];"); } var drawProgram = createDrawBuffersProgram("fshader", { numDrawingBuffers: maxDrawingBuffers, assignUColorsToFragData: assignCode.join("\n") }); var width = 64; var height = 64; var attachments = []; // Makes 6 framebuffers. // fb and fb2 have all the attachments. // halfFB1 has the first half of the attachments // halfFB2 has the second half of the attachments // endsFB has the first and last attachments // middleFB has all but the first and last attachments for (var ii = 0; ii < maxUsable; ++ii) { var tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.bindFramebuffer(gl.FRAMEBUFFER, fb); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0); gl.bindFramebuffer(gl.FRAMEBUFFER, fb2); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0); gl.bindFramebuffer(gl.FRAMEBUFFER, ii < half ? halfFB1 : halfFB2); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0); gl.bindFramebuffer(gl.FRAMEBUFFER, (ii == 0 || ii == (maxUsable - 1)) ? endsFB : middleFB); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0); var location = gl.getUniformLocation(drawProgram, "u_colors[" + ii + "]"); var color = makeColorByIndex(ii + 1); var floatColor = [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255]; gl.uniform4fv(location, floatColor); attachments.push({ texture: tex, location: location, color: color }); } gl.bindFramebuffer(gl.FRAMEBUFFER, fb); shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); gl.bindFramebuffer(gl.FRAMEBUFFER, fb2); shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); ``` -------------------------------- ### Setup and Execute Transform Feedback with Multiple Outputs (WebGL) Source: https://github.com/salvatorepreviti/spglsl/blob/master/project/conformance/khronos/conformance2/transform_feedback/transform_feedback.html This snippet demonstrates setting up and executing a WebGL transform feedback operation with multiple output buffers ('out_add' and 'out_mul'). It involves creating buffers, compiling and linking a transform feedback shader program, binding buffers, and drawing arrays. It also includes verification of the output buffer contents and checking the timing of the `TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN` query. ```javascript uffer(); gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer); gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, Float32Array.BYTES_PER_ELEMENT * in_data.length, gl.STATIC_DRAW); var out_mul_buffer = gl.createBuffer(); gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_mul_buffer); gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, Float32Array.BYTES_PER_ELEMENT * in_data.length, gl.STATIC_DRAW); // Create the transform feedback shader program = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"], ["out_add", "out_mul"], gl.SEPARATE_ATTRIBS, ["in_data"]); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error"); shouldBeNonNull("program"); // Create a query object to check the number of primitives written query = gl.createQuery(); // Draw the the transform feedback buffers tf = gl.createTransformFeedback(); gl.enableVertexAttribArray(0); gl.bindBuffer(gl.ARRAY_BUFFER, in_buffer); gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 16, 0); gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, out_add_buffer); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, out_mul_buffer); gl.enable(gl.RASTERIZER_DISCARD); gl.beginTransformFeedback(gl.POINTS); gl.beginQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query); gl.drawArrays(gl.POINTS, 0, 3); gl.endQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); gl.endTransformFeedback(); gl.disable(gl.RASTERIZER_DISCARD); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, null); // Verify the output buffer contents var add_expected = [ 3.0, 5.0, 7.0, 9.0, 4.0, 7.0, 12.0, 21.0, 2.75, 3.5, 4.25, 5.0 ]; gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer); wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, add_expected); var mul_expected = [ 2.0, 6.0, 12.0, 20.0, 4.0, 12.0, 32.0, 80.0, 1.5, 1.5, 1.0, 0.0 ]; gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_mul_buffer); wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, mul_expected); tf = null; program = null; // Check the result of the query. It should not be available yet. // This constant was chosen arbitrarily to take around 1 second on // one WebGL implementation on one desktop operating system. (Busy- // loops based on calling Date.now() have been found unreliable.) var numEarlyTests = 50000; while (--numEarlyTests > 0) { gl.finish(); if (gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE)) { testFailed("Query's result became available too early"); finishTest(); return; } } testPassed("TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query's result didn't become available too early"); // Complete the rest of the test asynchronously. requestAnimationFrame(completeTransformFeedbackQueryTest); ```