| <!-- |
| |
| /* |
| ** Copyright (c) 2013 The Khronos Group Inc. |
| ** |
| ** Permission is hereby granted, free of charge, to any person obtaining a |
| ** copy of this software and/or associated documentation files (the |
| ** "Materials"), to deal in the Materials without restriction, including |
| ** without limitation the rights to use, copy, modify, merge, publish, |
| ** distribute, sublicense, and/or sell copies of the Materials, and to |
| ** permit persons to whom the Materials are furnished to do so, subject to |
| ** the following conditions: |
| ** |
| ** The above copyright notice and this permission notice shall be included |
| ** in all copies or substantial portions of the Materials. |
| ** |
| ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. |
| */ |
| |
| --> |
| |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <title>WebGL ANGLE_instanced_arrays Conformance Tests</title> |
| <link rel="stylesheet" href="../../resources/js-test-style.css"/> |
| <script src="../../js/desktop-gl-constants.js"></script> |
| <script src="../../js/js-test-pre.js"></script> |
| <script src="../../js/webgl-test-utils.js"></script> |
| </head> |
| <body> |
| <div id="description"></div> |
| <canvas id="canvas" style="width: 50px; height: 50px;"> </canvas> |
| <div id="console"></div> |
| <!-- Shaders for testing instanced draws --> |
| <script id="outputVertexShader" type="x-shader/x-vertex"> |
| attribute vec4 aPosition; |
| attribute vec2 aOffset; |
| attribute vec4 aColor; |
| varying vec4 vColor; |
| void main() { |
| vColor = aColor; |
| gl_Position = aPosition + vec4(aOffset, 0.0, 0.0); |
| } |
| </script> |
| |
| <script id="outputFragmentShader" type="x-shader/x-fragment"> |
| precision mediump float; |
| varying vec4 vColor; |
| void main() { |
| gl_FragColor = vColor; |
| } |
| </script> |
| |
| <script id="drawArraysTestVertexShader" type="x-shader/x-vertex"> |
| attribute vec3 aPosition; |
| attribute vec3 aInstancePos; |
| uniform vec3 uOffset; |
| void main() { |
| gl_Position = vec4(aPosition.xyz + aInstancePos.xyz + uOffset, 1.0); |
| } |
| </script> |
| |
| <script id="drawArraysTestFragmentShader" type="x-shader/x-fragment"> |
| void main() { |
| gl_FragColor = vec4(1.0, 0, 0, 1.0); |
| } |
| </script> |
| |
| <script> |
| "use strict"; |
| description("This test verifies the functionality of the ANGLE_instanced_arrays extension, if it is available."); |
| |
| debug(""); |
| |
| var wtu = WebGLTestUtils; |
| var canvas = document.getElementById("canvas"); |
| var gl = wtu.create3DContext(canvas); |
| var ext = null; |
| var vaoext = null; |
| |
| var positionLoc = 0; |
| var offsetLoc = 2; |
| var colorLoc = 3; |
| var program; |
| |
| if (!gl) { |
| testFailed("WebGL context does not exist"); |
| finishTest(); |
| } else { |
| testPassed("WebGL context exists"); |
| |
| runDivisorTestDisabled(); |
| |
| // Query the extension and store globally so shouldBe can access it |
| ext = wtu.getExtensionWithKnownPrefixes(gl, "ANGLE_instanced_arrays"); |
| if (!ext) { |
| testPassed("No ANGLE_instanced_arrays support -- this is legal"); |
| |
| runSupportedTest(false); |
| finishTest(); |
| } else { |
| testPassed("Successfully enabled ANGLE_instanced_arrays extension"); |
| |
| runSupportedTest(true); |
| |
| runDivisorTestEnabled(); |
| runUniqueObjectTest(); |
| |
| setupCanvas(); |
| runOutputTests(); |
| runDrawArraysWithOffsetTest(); |
| runVAOInstancingInteractionTest(); |
| runANGLECorruptionTest(); |
| // Note that the ANGLE corruption test leaves vertex attrib divisors dirty at the moment. |
| // This should be cleaned up if more subtests are added after it. |
| } |
| } |
| |
| function runSupportedTest(extensionEnabled) { |
| var supported = gl.getSupportedExtensions(); |
| if (supported.indexOf("ANGLE_instanced_arrays") >= 0) { |
| if (extensionEnabled) { |
| testPassed("ANGLE_instanced_arrays listed as supported and getExtension succeeded"); |
| } else { |
| testFailed("ANGLE_instanced_arrays listed as supported but getExtension failed"); |
| } |
| } else { |
| if (extensionEnabled) { |
| testFailed("ANGLE_instanced_arrays not listed as supported but getExtension succeeded"); |
| } else { |
| testPassed("ANGLE_instanced_arrays not listed as supported and getExtension failed -- this is legal"); |
| } |
| } |
| } |
| |
| function runDivisorTestDisabled() { |
| debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension disabled"); |
| |
| var VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE; |
| |
| gl.getVertexAttrib(0, VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE); |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE should not be queryable if extension is disabled"); |
| } |
| |
| function runDivisorTestEnabled() { |
| debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension enabled"); |
| |
| shouldBe("ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", "0x88FE"); |
| |
| var max_vertex_attribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); |
| |
| for (var i = 0; i < max_vertex_attribs; ++i) { |
| var queried_value = gl.getVertexAttrib(i, ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE); |
| if(queried_value == 0){ |
| testPassed("Vertex attribute " + i + " must has a default divisor of 0"); |
| } |
| else{ |
| testFailed("Default divisor of vertex attribute " + i + " should be: 0, returned value was: " + queried_value); |
| } |
| } |
| |
| ext.vertexAttribDivisorANGLE(max_vertex_attribs, 2); |
| wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "vertexAttribDivisorANGLE index set greater than or equal to MAX_VERTEX_ATTRIBS should be an invalid value"); |
| |
| ext.vertexAttribDivisorANGLE(max_vertex_attribs-1, 2); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertexAttribDivisorANGLE index set less than MAX_VERTEX_ATTRIBS should succeed"); |
| |
| var queried_value = gl.getVertexAttrib(max_vertex_attribs-1, ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE); |
| if(queried_value == 2){ |
| testPassed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE matches expecation"); |
| } |
| else{ |
| testFailed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE should be: 2, returned value was: " + queried_value); |
| } |
| |
| // Reset vertex attrib divisors so they cannot affect following subtests. |
| ext.vertexAttribDivisorANGLE(max_vertex_attribs-1, 0); |
| } |
| |
| function setupCanvas() { |
| canvas.width = 50; canvas.height = 50; |
| gl.viewport(0, 0, canvas.width, canvas.height); |
| gl.clearColor(0, 0, 0, 0); |
| |
| program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['aPosition', 'aOffset', 'aColor'], [positionLoc, offsetLoc, colorLoc]); |
| ext = gl.getExtension("ANGLE_instanced_arrays"); |
| } |
| |
| function runOutputTests() { |
| var instanceCount = 4; |
| |
| debug("Testing various draws for valid built-in function behavior"); |
| |
| var offsets = new Float32Array([ |
| -1.0, 1.0, |
| 1.0, 1.0, |
| -1.0, -1.0, |
| 1.0, -1.0, |
| ]); |
| var offsetBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW); |
| gl.enableVertexAttribArray(offsetLoc); |
| gl.vertexAttribPointer(offsetLoc, 2, gl.FLOAT, false, 0, 0); |
| ext.vertexAttribDivisorANGLE(offsetLoc, 1); |
| |
| var colors = new Float32Array([ |
| 1.0, 0.0, 0.0, 1.0, // Red |
| 0.0, 1.0, 0.0, 1.0, // Green |
| 0.0, 0.0, 1.0, 1.0, // Blue |
| 1.0, 1.0, 0.0, 1.0, // Yellow |
| ]); |
| var colorBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); |
| gl.enableVertexAttribArray(colorLoc); |
| gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0); |
| ext.vertexAttribDivisorANGLE(colorLoc, 1); |
| |
| wtu.setupUnitQuad(gl, 0); |
| |
| // Draw 1: Regular drawArrays |
| debug(""); |
| debug("Testing drawArrays with non-zero divisor"); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| gl.drawArrays(gl.TRIANGLES, 0, 6); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertex attrib divisor should affect regular drawArrays when the extension is enabled"); |
| wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]); |
| |
| // Draw 2: Draw Non-indexed instances |
| debug(""); |
| debug("Testing drawArraysInstancedANGLE"); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| |
| // Test drawArraysInstancedANGLE error conditions |
| ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount); |
| wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]); |
| wtu.checkCanvasRect(gl, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2, [0, 255, 0, 255]); |
| wtu.checkCanvasRect(gl, 0, 0, canvas.width/2, canvas.height/2, [0, 0, 255, 255]); |
| wtu.checkCanvasRect(gl, canvas.width/2, 0, canvas.width/2, canvas.height/2, [255, 255, 0, 255]); |
| |
| ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, -1); |
| wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstancedANGLE cannot have a primcount less than 0"); |
| |
| ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, -1, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstancedANGLE cannot have a count less than 0"); |
| |
| ext.vertexAttribDivisorANGLE(positionLoc, 1); |
| ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "There must be at least one vertex attribute with a divisor of zero when calling drawArraysInstancedANGLE"); |
| ext.vertexAttribDivisorANGLE(positionLoc, 0); |
| |
| ext.drawArraysInstancedANGLE(gl.POINTS, 0, 6, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with POINTS should succeed"); |
| ext.drawArraysInstancedANGLE(gl.LINES, 0, 6, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with LINES should succeed"); |
| ext.drawArraysInstancedANGLE(gl.LINE_LIST, 0, 6, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with LINE_LIST should return succeed"); |
| ext.drawArraysInstancedANGLE(gl.TRIANGLE_LIST, 0, 6, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with TRIANGLE_LIST should succeed"); |
| |
| ext.drawArraysInstancedANGLE(desktopGL['QUAD_STRIP'], 0, 6, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with QUAD_STRIP should return INVALID_ENUM"); |
| ext.drawArraysInstancedANGLE(desktopGL['QUADS'], 0, 6, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with QUADS should return INVALID_ENUM"); |
| ext.drawArraysInstancedANGLE(desktopGL['POLYGON'], 0, 6, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with POLYGON should return INVALID_ENUM"); |
| |
| debug(""); |
| debug("Testing drawArraysInstancedANGLE with param 'first' > 0"); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| wtu.setupQuad(gl, { |
| positionLocation: 0, |
| scale: 0.5 |
| }); |
| var offsetsHalf = new Float32Array([ |
| -0.5, 0.5, |
| 0.5, 0.5, |
| -0.5, -0.5, |
| 0.5, -0.5 |
| ]); |
| gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, offsetsHalf, gl.STATIC_DRAW); |
| |
| ext.drawArraysInstancedANGLE(gl.TRIANGLES, 3, 3, instanceCount); |
| var w = Math.floor(0.25*canvas.width), |
| h = Math.floor(0.25*canvas.height); |
| wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0.5*canvas.height, w, h, [255, 0, 0, 255]); |
| wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0.5*canvas.height, w, h, [0, 255, 0, 255]); |
| wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0, w, h, [0, 0, 255, 255]); |
| wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0, w, h, [255, 255, 0, 255]); |
| |
| wtu.setupUnitQuad(gl, 0); |
| wtu.setupIndexedQuad(gl, 1, 0); |
| gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW); |
| |
| // Draw 3: Regular drawElements |
| debug(""); |
| debug("Testing drawElements with non-zero divisor"); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| // Point to another location in the buffer so that the draw would overflow without the divisor |
| gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); |
| gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 48); |
| gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertex attrib divisor should affect regular drawElements when the extension is enabled"); |
| wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 255, 0, 255]); |
| // Restore the vertex attrib pointer |
| gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0); |
| |
| // Draw 4: Draw indexed instances |
| debug(""); |
| debug("Testing drawElementsInstancedANGLE"); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); |
| wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]); |
| wtu.checkCanvasRect(gl, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2, [0, 255, 0, 255]); |
| wtu.checkCanvasRect(gl, 0, 0, canvas.width/2, canvas.height/2, [0, 0, 255, 255]); |
| wtu.checkCanvasRect(gl, canvas.width/2, 0, canvas.width/2, canvas.height/2, [255, 255, 0, 255]); |
| |
| // Test drawElementsInstancedANGLE error conditions |
| ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, -1); |
| wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstancedANGLE cannot have a primcount less than 0"); |
| |
| ext.drawElementsInstancedANGLE(gl.TRIANGLES, -1, gl.UNSIGNED_SHORT, 0, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstancedANGLE cannot have a count less than 0"); |
| |
| ext.vertexAttribDivisorANGLE(positionLoc, 1); |
| ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "There must be at least one vertex attribute with a divisor of zero when calling drawElementsInstancedANGLE"); |
| ext.vertexAttribDivisorANGLE(positionLoc, 0); |
| |
| ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with UNSIGNED_BYTE should succeed"); |
| |
| ext.drawElementsInstancedANGLE(gl.POINTS, 6, gl.UNSIGNED_SHORT, 0, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with POINTS should succeed"); |
| ext.drawElementsInstancedANGLE(gl.LINES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with LINES should succeed"); |
| ext.drawElementsInstancedANGLE(gl.LINE_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with LINE_LIST should return succeed"); |
| ext.drawElementsInstancedANGLE(gl.TRIANGLE_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with TRIANGLE_LIST should succeed"); |
| |
| ext.drawElementsInstancedANGLE(desktopGL['QUAD_STRIP'], 6, gl.UNSIGNED_SHORT, 0, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with QUAD_STRIP should return INVALID_ENUM"); |
| ext.drawElementsInstancedANGLE(desktopGL['QUADS'], 6, gl.UNSIGNED_SHORT, 0, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with QUADS should return INVALID_ENUM"); |
| ext.drawElementsInstancedANGLE(desktopGL['POLYGON'], 6, gl.UNSIGNED_SHORT, 0, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with POLYGON should return INVALID_ENUM"); |
| |
| // Reset vertex attrib divisors so they cannot affect following subtests. |
| ext.vertexAttribDivisorANGLE(colorLoc, 0); |
| ext.vertexAttribDivisorANGLE(offsetLoc, 0); |
| } |
| |
| function runDrawArraysTest(program, first, count, instanceCount, offset) |
| { |
| // Get the attribute and uniform locations |
| var positionLoc = gl.getAttribLocation(program, "aPosition"); |
| var instancePosLoc = gl.getAttribLocation(program, "aInstancePos"); |
| var uniformLoc = gl.getUniformLocation(program, "uOffset"); |
| |
| // Load the vertex positions |
| var positions = new Float32Array([ |
| -1, -1, |
| -1, 0, |
| 0, 0, |
| |
| 0, 0, |
| 0, -1, |
| -1, -1, |
| |
| 1, -1, |
| 1, 0, |
| 0, 0, |
| |
| 0, 0, |
| 0, -1, |
| 1, -1, |
| ]); |
| var positionBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); |
| gl.enableVertexAttribArray(positionLoc); |
| gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); |
| |
| // Load the instance positions |
| var instancePositions = new Float32Array([ |
| 0, 0, |
| 1, 0 |
| ]); |
| var instancePositionBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, instancePositionBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, instancePositions, gl.STATIC_DRAW); |
| gl.enableVertexAttribArray(instancePosLoc); |
| gl.vertexAttribPointer(instancePosLoc, 2, gl.FLOAT, false, 0, 0); |
| |
| // Enable instancing |
| ext.vertexAttribDivisorANGLE(instancePosLoc, 1); |
| |
| // Offset |
| gl.uniform3fv(uniformLoc, offset); |
| |
| // Do the instanced draw |
| ext.drawArraysInstancedANGLE(gl.TRIANGLES, first, count, instanceCount); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE should succeed"); |
| |
| // Reset vertex attrib divisors so they cannot affect following subtests. |
| ext.vertexAttribDivisorANGLE(instancePosLoc, 0); |
| } |
| |
| function runDrawArraysWithOffsetTest() |
| { |
| debug(""); |
| debug("Testing that the 'first' parameter to drawArraysInstancedANGLE is only an offset into the non-instanced vertex attributes."); |
| // See: http://crbug.com/457269 and http://crbug.com/447140 |
| |
| var drawArraysProgram = wtu.setupProgram(gl, ["drawArraysTestVertexShader", "drawArraysTestFragmentShader"]); |
| |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| |
| runDrawArraysTest(drawArraysProgram, 0, 6, 2, [0, 0, 0]); |
| |
| runDrawArraysTest(drawArraysProgram, 6, 6, 2, [-1, 1, 0]); |
| |
| wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]); |
| } |
| |
| function runUniqueObjectTest() |
| { |
| debug(""); |
| debug("Testing that getExtension() returns the same object each time"); |
| ext = null; |
| gl.getExtension("ANGLE_instanced_arrays").myProperty = 2; |
| webglHarnessCollectGarbage(); |
| shouldBe('gl.getExtension("ANGLE_instanced_arrays").myProperty', '2'); |
| } |
| |
| function runVAOInstancingInteractionTest() |
| { |
| debug("") |
| debug("Testing that ANGLE_instanced_arrays interacts correctly with OES_vertex_array_object if present"); |
| // See: https://github.com/KhronosGroup/WebGL/issues/1228 |
| |
| // Query the extension and store globally so shouldBe can access it |
| vaoext = gl.getExtension("OES_vertex_array_object"); |
| if (!vaoext) { |
| testPassed("No OES_vertex_array_object support -- this is legal"); |
| return; |
| } |
| |
| testPassed("Successfully enabled OES_vertex_array_object extension"); |
| |
| gl.useProgram(program); |
| |
| var positions = new Float32Array([ |
| 0.0, 1.0, // Left quad |
| -1.0, 1.0, |
| -1.0, -1.0, |
| 0.0, 1.0, |
| -1.0, -1.0, |
| 0.0, -1.0, |
| |
| 1.0, 1.0, // Right quad |
| 0.0, 1.0, |
| 0.0, -1.0, |
| 1.0, 1.0, |
| 0.0, -1.0, |
| 1.0, -1.0 |
| ]); |
| var positionBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); |
| |
| var colors = new Float32Array([ |
| 1.0, 0.0, 0.0, 1.0, // Red |
| 1.0, 0.0, 0.0, 1.0, |
| 1.0, 0.0, 0.0, 1.0, |
| 1.0, 0.0, 0.0, 1.0, |
| 1.0, 0.0, 0.0, 1.0, |
| 1.0, 0.0, 0.0, 1.0, |
| |
| 0.0, 0.0, 1.0, 1.0, // Blue |
| 0.0, 0.0, 1.0, 1.0, |
| 0.0, 0.0, 1.0, 1.0, |
| 0.0, 0.0, 1.0, 1.0, |
| 0.0, 0.0, 1.0, 1.0, |
| 0.0, 0.0, 1.0, 1.0, |
| ]); |
| var colorBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); |
| |
| // Reset the divisor of the default VAO to 0 |
| ext.vertexAttribDivisorANGLE(colorLoc, 0); |
| |
| // Set up VAO with an attrib divisor |
| var vao1 = vaoext.createVertexArrayOES(); |
| vaoext.bindVertexArrayOES(vao1); |
| { |
| gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); |
| gl.enableVertexAttribArray(positionLoc); |
| gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); |
| |
| gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); |
| gl.enableVertexAttribArray(colorLoc); |
| gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0); |
| ext.vertexAttribDivisorANGLE(colorLoc, 1); |
| |
| gl.vertexAttrib2fv(offsetLoc, [0.0, 0.0]); |
| } |
| vaoext.bindVertexArrayOES(null); |
| |
| // Set up VAO with no attrib divisor |
| var vao2 = vaoext.createVertexArrayOES(); |
| vaoext.bindVertexArrayOES(vao2); |
| { |
| gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); |
| gl.enableVertexAttribArray(positionLoc); |
| gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); |
| |
| gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); |
| gl.enableVertexAttribArray(colorLoc); |
| gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0); |
| // Note that no divisor is set here, which implies that it's 0 |
| |
| gl.vertexAttrib2fv(offsetLoc, [0.0, 0.0]); |
| } |
| vaoext.bindVertexArrayOES(null); |
| |
| debug(""); |
| debug("Ensure that Vertex Array Objects retain attrib divisors"); |
| |
| vaoext.bindVertexArrayOES(vao1); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| gl.drawArrays(gl.TRIANGLES, 0, 12); |
| // If the divisor is properly managed by the VAO a single red quad will be drawn |
| wtu.checkCanvas(gl, [255, 0, 0, 255], "entire canvas should be red"); |
| |
| vaoext.bindVertexArrayOES(vao2); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| gl.drawArrays(gl.TRIANGLES, 0, 12); |
| // If the divisor is properly managed by the VAO a red and blue quad will be drawn. |
| wtu.checkCanvasRects(gl, [ |
| wtu.makeCheckRect(0, 0, canvas.width * 0.5, canvas.height, [255, 0, 0, 255], "left half of canvas should be red", 1), |
| wtu.makeCheckRect(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height, [0, 0, 255, 255], "right half of canvas should be blue", 1) |
| ]); |
| |
| vaoext.bindVertexArrayOES(null); |
| } |
| |
| function runANGLECorruptionTest() |
| { |
| debug("") |
| debug("Testing to ensure that rendering isn't corrupt due to an ANGLE bug"); |
| // See: https://code.google.com/p/angleproject/issues/detail?id=467 |
| |
| setupCanvas(); |
| |
| var tolerance = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher |
| var instanceCount = 10; // Must be higher than 6 |
| var iteration = 0; |
| var totalIterations = 10; |
| |
| var offsets = new Float32Array([ |
| 0.0, 0.0, |
| 0.2, 0.0, |
| 0.4, 0.0, |
| 0.6, 0.0, |
| 0.8, 0.0, |
| 1.0, 0.0, |
| 1.2, 0.0, |
| 1.4, 0.0, |
| 1.6, 0.0, |
| 1.8, 0.0, |
| ]); |
| var offsetBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, offsets.byteLength * 2, gl.STATIC_DRAW); |
| gl.bufferSubData(gl.ARRAY_BUFFER, 0, offsets); |
| gl.enableVertexAttribArray(offsetLoc); |
| gl.vertexAttribPointer(offsetLoc, 2, gl.FLOAT, false, 0, 0); |
| ext.vertexAttribDivisorANGLE(offsetLoc, 1); |
| |
| var colors = new Float32Array([ |
| 1.0, 0.0, 0.0, 1.0, |
| 1.0, 1.0, 0.0, 1.0, |
| 0.0, 1.0, 0.0, 1.0, |
| 0.0, 1.0, 1.0, 1.0, |
| 0.0, 0.0, 1.0, 1.0, |
| 1.0, 0.0, 1.0, 1.0, |
| 1.0, 0.0, 0.0, 1.0, |
| 1.0, 1.0, 0.0, 1.0, |
| 0.0, 1.0, 0.0, 1.0, |
| 0.0, 1.0, 1.0, 1.0, |
| ]); |
| var colorBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, colors.byteLength * 2, gl.STATIC_DRAW); |
| gl.bufferSubData(gl.ARRAY_BUFFER, 0, colors); |
| gl.enableVertexAttribArray(colorLoc); |
| gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0); |
| ext.vertexAttribDivisorANGLE(colorLoc, 1); |
| |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| wtu.setupUnitQuad(gl, 0); |
| |
| function cycleAndTest() { |
| // Update the instanced data buffers outside the accessed range. |
| // This, plus rendering more instances than vertices, triggers the bug. |
| var nullData = new Float32Array(offsets.length); |
| gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer); |
| gl.bufferSubData(gl.ARRAY_BUFFER, offsets.byteLength, nullData); |
| |
| nullData = new Float32Array(colors.length); |
| gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); |
| gl.bufferSubData(gl.ARRAY_BUFFER, colors.byteLength, nullData); |
| |
| ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount); |
| |
| // Make sure each color was drawn correctly |
| var i; |
| var passed = true; |
| for (i = 0; i < instanceCount; ++i) { |
| var w = canvas.width / instanceCount; |
| var x = w * i; |
| var color = [colors[(i*4)] * 255, colors[(i*4)+1] * 255, colors[(i*4)+2] * 255, 255] |
| |
| wtu.checkCanvasRectColor( |
| gl, x, 0, w, canvas.height, color, tolerance, |
| function() {}, |
| function() { |
| passed = false; |
| }, debug); |
| } |
| |
| if (passed) { |
| testPassed("Passed test " + iteration + " of " + totalIterations); |
| if (iteration < totalIterations) { |
| ++iteration; |
| setTimeout(cycleAndTest, 0); |
| } else { |
| finishTest(); |
| } |
| } else { |
| testFailed("Failed test " + iteration + " of " + totalIterations); |
| finishTest(); |
| } |
| } |
| |
| cycleAndTest(); |
| } |
| </script> |
| </body> |
| </html> |