Commit 81d4ed94 authored by dino@apple.com's avatar dino@apple.com

Source/WebCore: [WebGL] Implement ANGLE_instanced_arrays

https://bugs.webkit.org/show_bug.cgi?id=127257

Reviewed by Brent Fulgham.

Implement the instanced drawing WebGL extension,
ANGLE_instanced_arrays. This is currently Mac-only,
but should be portable to other platforms if their
OpenGL exposes the functions. It's also done in a way
that will make exposing it to WebGL2 simple.

Test: fast/canvas/webgl/angle-instanced-arrays.html

* CMakeLists.txt:
* DerivedSources.cpp:
* DerivedSources.make:
* GNUmakefile.list.am:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.vcxproj/WebCore.vcxproj.filters:
* WebCore.xcodeproj/project.pbxproj:
Add the new files to all the build systems.

* bindings/js/JSWebGLRenderingContextCustom.cpp:
(WebCore::toJS): Link JS side to C++ side.

* html/canvas/ANGLEInstancedArrays.cpp: Added.
(WebCore::ANGLEInstancedArrays::ANGLEInstancedArrays):
* html/canvas/ANGLEInstancedArrays.h: Added.
* html/canvas/ANGLEInstancedArrays.idl: Added.
New boilerplate files that expose the extension methods.

* html/canvas/WebGLExtension.h: New extension enum.

* html/canvas/WebGLRenderingContext.cpp:
(WebCore::WebGLRenderingContext::validateVertexAttributes): Add an optional
parameter representing the number of instance primitives we are asked
to draw. Use that for the draw count if looking at an instanced attribute.
Also make sure we see at least one non-instanced attribute.
(WebCore::WebGLRenderingContext::validateDrawArrays): Update this so it could
be used from either drawArrays or drawArraysInstanced.
(WebCore::WebGLRenderingContext::drawArrays):
(WebCore::WebGLRenderingContext::validateDrawElements): Same here, now can be
used by the instanced and non-instanced versions.
(WebCore::WebGLRenderingContext::drawElements):
(WebCore::WebGLRenderingContext::getExtension): Create and return the new extension.
(WebCore::WebGLRenderingContext::getSupportedExtensions): Add new extension to the list.
(WebCore::WebGLRenderingContext::getVertexAttrib): Intercept a query to the divisor
attribute and return the value we kept in the state.
(WebCore::WebGLRenderingContext::drawArraysInstanced): Call the GC3D method.
(WebCore::WebGLRenderingContext::drawElementsInstanced): Ditto.
(WebCore::WebGLRenderingContext::vertexAttribDivisor): Ditto.

* html/canvas/WebGLRenderingContext.h: Define the new methods and parameters.

* html/canvas/WebGLVertexArrayObjectOES.cpp:
(WebCore::WebGLVertexArrayObjectOES::setVertexAttribDivisor): Keep a record of the
divisor if we set it.
* html/canvas/WebGLVertexArrayObjectOES.h:
(WebCore::WebGLVertexArrayObjectOES::VertexAttribState::VertexAttribState):

* platform/graphics/GraphicsContext3D.h: New enum.
* platform/graphics/mac/GraphicsContext3DMac.mm:
(WebCore::GraphicsContext3D::drawArraysInstanced): The actual calls into OpenGL.
(WebCore::GraphicsContext3D::drawElementsInstanced): Ditto.
(WebCore::GraphicsContext3D::vertexAttribDivisor): Ditto.

* platform/graphics/opengl/GraphicsContext3DOpenGL.cpp: Empty implementations
for non-mac platforms.

* platform/graphics/ios/GraphicsContext3DIOS.h: Define the iOS names for the
functions.

LayoutTests: Implement ANGLE_instanced_arrays
https://bugs.webkit.org/show_bug.cgi?id=127257

Reviewed by Brent Fulgham.

Copied a slightly modified version of the Khronos instanced
arrays test (mostly modified due to the fact this comes from
an in-progress update to the test suite).

* fast/canvas/webgl/angle-instanced-arrays-expected.txt: Added.
* fast/canvas/webgl/angle-instanced-arrays.html: Added.
* fast/canvas/webgl/resources/webgl-test-utils.js:
(WebGLTestUtils): Added some new functions that were missing, and
some output to a checkColor test.
* platform/efl/TestExpectations: Skip this for EFL.
* platform/mac-mountainlion/fast/canvas/webgl/angle-instanced-arrays-expected.txt: Not
supported on Mountain Lion.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@162565 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent aaddc8bd
2014-01-22 Dean Jackson <dino@apple.com>
Implement ANGLE_instanced_arrays
https://bugs.webkit.org/show_bug.cgi?id=127257
Reviewed by Brent Fulgham.
Copied a slightly modified version of the Khronos instanced
arrays test (mostly modified due to the fact this comes from
an in-progress update to the test suite).
* fast/canvas/webgl/angle-instanced-arrays-expected.txt: Added.
* fast/canvas/webgl/angle-instanced-arrays.html: Added.
* fast/canvas/webgl/resources/webgl-test-utils.js:
(WebGLTestUtils): Added some new functions that were missing, and
some output to a checkColor test.
* platform/efl/TestExpectations: Skip this for EFL.
* platform/mac-mountainlion/fast/canvas/webgl/angle-instanced-arrays-expected.txt: Not
supported on Mountain Lion.
2014-01-22 Zalan Bujtas <zalan@apple.com>
Unreviewed Apple Windows port gardering after r162553.
CONSOLE MESSAGE: WebGL: INVALID_ENUM: getVertexAttrib: invalid parameter name
CONSOLE MESSAGE: WebGL: INVALID_VALUE: vertexAttribDivisor: index out of range
CONSOLE MESSAGE: WebGL: INVALID_VALUE: drawArraysInstanced: primcount < 0
CONSOLE MESSAGE: WebGL: INVALID_VALUE: drawArraysInstanced: first or count < 0
CONSOLE MESSAGE: WebGL: INVALID_OPERATION: drawArraysInstanced: attempt to access out of bounds arrays
CONSOLE MESSAGE: WebGL: INVALID_ENUM: drawArraysInstanced: invalid draw mode
CONSOLE MESSAGE: WebGL: INVALID_ENUM: drawArraysInstanced: invalid draw mode
CONSOLE MESSAGE: WebGL: INVALID_ENUM: drawArraysInstanced: invalid draw mode
CONSOLE MESSAGE: WebGL: INVALID_VALUE: drawElementsInstanced: primcount < 0
CONSOLE MESSAGE: WebGL: INVALID_VALUE: drawElementsInstanced: count or offset < 0
CONSOLE MESSAGE: WebGL: INVALID_OPERATION: drawElementsInstanced: attempt to access out of bounds arrays
CONSOLE MESSAGE: WebGL: INVALID_ENUM: drawElementsInstanced: invalid draw mode
CONSOLE MESSAGE: WebGL: INVALID_ENUM: drawElementsInstanced: invalid draw mode
CONSOLE MESSAGE: WebGL: INVALID_ENUM: drawElementsInstanced: invalid draw mode
This test verifies the functionality of the ANGLE_instanced_arrays extension, if it is available.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS WebGL context exists
Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension disabled
PASS getError was expected value: INVALID_ENUM : VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE should not be queryable if extension is disabled
PASS Successfully enabled ANGLE_instanced_arrays extension
PASS ANGLE_instanced_arrays listed as supported and getExtension succeeded
Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension enabled
PASS ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE is 0x88FE
PASS Vertex attribute 0 must has a default divisor of 0
PASS Vertex attribute 1 must has a default divisor of 0
PASS Vertex attribute 2 must has a default divisor of 0
PASS Vertex attribute 3 must has a default divisor of 0
PASS Vertex attribute 4 must has a default divisor of 0
PASS Vertex attribute 5 must has a default divisor of 0
PASS Vertex attribute 6 must has a default divisor of 0
PASS Vertex attribute 7 must has a default divisor of 0
PASS Vertex attribute 8 must has a default divisor of 0
PASS Vertex attribute 9 must has a default divisor of 0
PASS Vertex attribute 10 must has a default divisor of 0
PASS Vertex attribute 11 must has a default divisor of 0
PASS Vertex attribute 12 must has a default divisor of 0
PASS Vertex attribute 13 must has a default divisor of 0
PASS Vertex attribute 14 must has a default divisor of 0
PASS Vertex attribute 15 must has a default divisor of 0
PASS getError was expected value: INVALID_VALUE : vertexAttribDivisorANGLE index set greater than or equal to MAX_VERTEX_ATTRIBS should be an invalid value
PASS getError was expected value: NO_ERROR : vertexAttribDivisorANGLE index set less than MAX_VERTEX_ATTRIBS should succeed
PASS Set value of VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE matches expecation
Testing that getExtension() returns the same object each time
PASS gl.getExtension("ANGLE_instanced_arrays").myProperty is 2
Testing various draws for valid built-in function behavior
Testing drawArraysInstancedANGLE
PASS Color was 255,0,0,255
PASS Color was 0,255,0,255
PASS Color was 0,0,255,255
PASS Color was 255,255,0,255
PASS getError was expected value: INVALID_VALUE : drawArraysInstancedANGLE cannot have a primcount less than 0
PASS getError was expected value: INVALID_VALUE : drawArraysInstancedANGLE cannot have a count less than 0
PASS getError was expected value: INVALID_OPERATION : There must be at least one vertex attribute with a divisor of zero when calling drawArraysInstancedANGLE
PASS getError was expected value: NO_ERROR : drawArraysInstancedANGLE with POINTS should succeed
PASS getError was expected value: NO_ERROR : drawArraysInstancedANGLE with LINES should succeed
PASS getError was expected value: NO_ERROR : drawArraysInstancedANGLE with LINE_LIST should return succeed
PASS getError was expected value: NO_ERROR : drawArraysInstancedANGLE with TRIANGLE_LIST should succeed
PASS getError was expected value: INVALID_ENUM : drawArraysInstancedANGLE with QUAD_STRIP should return INVALID_ENUM
PASS getError was expected value: INVALID_ENUM : drawArraysInstancedANGLE with QUADS should return INVALID_ENUM
PASS getError was expected value: INVALID_ENUM : drawArraysInstancedANGLE with POLYGON should return INVALID_ENUM
Testing drawElementsInstancedANGLE
PASS Color was 255,0,0,255
PASS Color was 0,255,0,255
PASS Color was 0,0,255,255
PASS Color was 255,255,0,255
PASS getError was expected value: INVALID_VALUE : drawElementsInstancedANGLE cannot have a primcount less than 0
PASS getError was expected value: INVALID_VALUE : drawElementsInstancedANGLE cannot have a count less than 0
PASS getError was expected value: INVALID_OPERATION : There must be at least one vertex attribute with a divisor of zero when calling drawElementsInstancedANGLE
PASS getError was expected value: NO_ERROR : drawElementsInstancedANGLE with UNSIGNED_BYTE should succeed
PASS getError was expected value: NO_ERROR : drawElementsInstancedANGLE with POINTS should succeed
PASS getError was expected value: NO_ERROR : drawElementsInstancedANGLE with LINES should succeed
PASS getError was expected value: NO_ERROR : drawElementsInstancedANGLE with LINE_LIST should return succeed
PASS getError was expected value: NO_ERROR : drawElementsInstancedANGLE with TRIANGLE_LIST should succeed
PASS getError was expected value: INVALID_ENUM : drawElementsInstancedANGLE with QUAD_STRIP should return INVALID_ENUM
PASS getError was expected value: INVALID_ENUM : drawElementsInstancedANGLE with QUADS should return INVALID_ENUM
PASS getError was expected value: INVALID_ENUM : drawElementsInstancedANGLE with POLYGON should return INVALID_ENUM
PASS successfullyParsed is true
TEST COMPLETE
<!--
/*
** 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>
<script src="resources/desktop-gl-constants.js" type="text/javascript"></script>
<script src="../../../resources/js-test-pre.js"></script>
<script src="resources/webgl-test.js"> </script>
<script src="resources/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>
"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 positionLoc = 0;
var offsetLoc = 2;
var colorLoc = 3;
var program;
if (!gl) {
testFailed("WebGL context does not exist");
} 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);
} else {
testPassed("Successfully enabled ANGLE_instanced_arrays extension");
runSupportedTest(true);
runDivisorTestEnabled();
runUniqueObjectTest();
setupCanvas();
runOutputTests();
finishTest();
}
}
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);
}
}
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]);
}
function runOutputTests() {
var e = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher
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);
// Draw 1: Draw Non-indexed instances
debug("Testing drawArraysInstancedANGLE");
gl.clear(gl.COLOR_BUFFER_BIT);
wtu.setupUnitQuad(gl, 0);
// 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");
// Draw 2: Draw indexed instances
debug("Testing drawElementsInstancedANGLE");
gl.clear(gl.COLOR_BUFFER_BIT);
wtu.setupIndexedQuad(gl, 1, 0);
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");
}
function runUniqueObjectTest()
{
debug("Testing that getExtension() returns the same object each time");
gl.getExtension("ANGLE_instanced_arrays").myProperty = 2;
gc();
shouldBe('gl.getExtension("ANGLE_instanced_arrays").myProperty', '2');
}
debug("");
var successfullyParsed = true;
</script>
<script src="../../../resources/js-test-post.js"></script>
</body>
</html>
......@@ -360,6 +360,125 @@ var setupQuad = function (
return objects;
};
/**
* Creates a unit quad with only positions of a given resolution.
* @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
* @param {number} gridRes The resolution of the mesh grid,
* expressed in the number of quads across and down.
* @param {number} opt_positionLocation The attrib location for position.
*/
var setupIndexedQuad = function (
gl, gridRes, opt_positionLocation, opt_flipOddTriangles) {
return setupIndexedQuadWithOptions(gl,
{ gridRes: gridRes,
positionLocation: opt_positionLocation,
flipOddTriangles: opt_flipOddTriangles
});
};
/**
* Creates a quad with various options.
* @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
* @param {!Object) options The options. See below.
* @return {!Array.<WebGLBuffer>} The created buffers.
* [positions, <colors>, indices]
*
* Options:
* gridRes: number of quads across and down grid.
* positionLocation: attrib location for position
* flipOddTriangles: reverse order of vertices of every other
* triangle
* positionOffset: offset added to each vertex
* positionMult: multipier for each vertex
* colorLocation: attrib location for vertex colors. If
* undefined no vertex colors will be created.
*/
var setupIndexedQuadWithOptions = function (gl, options) {
var positionLocation = options.positionLocation || 0;
var objects = [];
var gridRes = options.gridRes || 1;
var positionOffset = options.positionOffset || 0;
var positionMult = options.positionMult || 1;
var vertsAcross = gridRes + 1;
var numVerts = vertsAcross * vertsAcross;
var positions = new Float32Array(numVerts * 3);
var indices = new Uint16Array(6 * gridRes * gridRes);
var poffset = 0;
for (var yy = 0; yy <= gridRes; ++yy) {
for (var xx = 0; xx <= gridRes; ++xx) {
positions[poffset + 0] = (-1 + 2 * xx / gridRes) * positionMult + positionOffset;
positions[poffset + 1] = (-1 + 2 * yy / gridRes) * positionMult + positionOffset;
positions[poffset + 2] = 0;
poffset += 3;
}
}
var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
objects.push(buf);
if (options.colorLocation !== undefined) {
var colors = new Float32Array(numVerts * 4);
for (var yy = 0; yy <= gridRes; ++yy) {
for (var xx = 0; xx <= gridRes; ++xx) {
if (options.color !== undefined) {
colors[poffset + 0] = options.color[0];
colors[poffset + 1] = options.color[1];
colors[poffset + 2] = options.color[2];
colors[poffset + 3] = options.color[3];
} else {
colors[poffset + 0] = xx / gridRes;
colors[poffset + 1] = yy / gridRes;
colors[poffset + 2] = (xx / gridRes) * (yy / gridRes);
colors[poffset + 3] = (yy % 2) * 0.5 + 0.5;
}
poffset += 4;
}
}
var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
gl.enableVertexAttribArray(options.colorLocation);
gl.vertexAttribPointer(options.colorLocation, 4, gl.FLOAT, false, 0, 0);
objects.push(buf);
}
var tbase = 0;
for (var yy = 0; yy < gridRes; ++yy) {
var index = yy * vertsAcross;
for (var xx = 0; xx < gridRes; ++xx) {
indices[tbase + 0] = index + 0;
indices[tbase + 1] = index + 1;
indices[tbase + 2] = index + vertsAcross;
indices[tbase + 3] = index + vertsAcross;
indices[tbase + 4] = index + 1;
indices[tbase + 5] = index + vertsAcross + 1;
if (options.flipOddTriangles) {
indices[tbase + 4] = index + vertsAcross + 1;
indices[tbase + 5] = index + 1;
}
index += 1;
tbase += 6;
}
}
var buf = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buf);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
objects.push(buf);
return objects;
};
/**
* Fills the given texture with a solid color
* @param {!WebGLContext} gl The WebGLContext to use.
......@@ -474,6 +593,128 @@ var drawIndexedQuad = function(gl, gridRes, opt_color) {
gl.drawElements(gl.TRIANGLES, gridRes * 6, gl.UNSIGNED_SHORT, 0);
};
/**
* Draws a previously setupIndexedQuad
* @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
* @param {number} gridRes Resolution of grid.
* @param {!Array.<number>} opt_color The color to fill clear with before
* drawing. A 4 element array where each element is in the range 0 to
* 255. Default [255, 255, 255, 255]
*/
var clearAndDrawIndexedQuad = function(gl, gridRes, opt_color) {
opt_color = opt_color || [255, 255, 255, 255];
gl.clearColor(
opt_color[0] / 255,
opt_color[1] / 255,
opt_color[2] / 255,
opt_color[3] / 255);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
drawIndexedQuad(gl, gridRes);
};
/**
* Clips a range to min, max
* (Eg. clipToRange(-5,7,0,20) would return {value:0,extent:2}
* @param {number} value start of range
* @param {number} extent extent of range
* @param {number} min min.
* @param {number} max max.
* @return {!{value:number,extent:number} The clipped value.
*/
var clipToRange = function(value, extent, min, max) {
if (value < min) {
extent -= min - value;
value = min;
}
var end = value + extent;
if (end > max) {
extent -= end - max;
}
if (extent < 0) {
value = max;
extent = 0;
}
return {value:value, extent: extent};
};
/**
* Determines if the passed context is an instance of a WebGLRenderingContext
* or later variant (like WebGL2RenderingContext)
* @param {CanvasRenderingContext} ctx The context to check.
*/
var isWebGLContext = function(ctx) {
if (ctx instanceof WebGLRenderingContext)