Source/WebCore: [WebGL] Implement ANGLE_instanced_arrays
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Jan 2014 23:47:24 +0000 (23:47 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Jan 2014 23:47:24 +0000 (23:47 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@162565 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/canvas/webgl/angle-instanced-arrays-expected.txt [new file with mode: 0644]
LayoutTests/fast/canvas/webgl/angle-instanced-arrays.html [new file with mode: 0644]
LayoutTests/fast/canvas/webgl/resources/webgl-test-utils.js
LayoutTests/platform/efl/TestExpectations
LayoutTests/platform/mac-mountainlion/fast/canvas/webgl/angle-instanced-arrays-expected.txt [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources.cpp
Source/WebCore/DerivedSources.make
Source/WebCore/GNUmakefile.list.am
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSWebGLRenderingContextCustom.cpp
Source/WebCore/html/canvas/ANGLEInstancedArrays.cpp [new file with mode: 0644]
Source/WebCore/html/canvas/ANGLEInstancedArrays.h [new file with mode: 0644]
Source/WebCore/html/canvas/ANGLEInstancedArrays.idl [new file with mode: 0644]
Source/WebCore/html/canvas/WebGLExtension.h
Source/WebCore/html/canvas/WebGLRenderingContext.cpp
Source/WebCore/html/canvas/WebGLRenderingContext.h
Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.cpp
Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.h
Source/WebCore/platform/graphics/GraphicsContext3D.h
Source/WebCore/platform/graphics/ios/GraphicsContext3DIOS.h
Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm
Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp

index 32c3722..e2c2e1e 100644 (file)
@@ -1,3 +1,23 @@
+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.
diff --git a/LayoutTests/fast/canvas/webgl/angle-instanced-arrays-expected.txt b/LayoutTests/fast/canvas/webgl/angle-instanced-arrays-expected.txt
new file mode 100644 (file)
index 0000000..9461279
--- /dev/null
@@ -0,0 +1,84 @@
+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
+
diff --git a/LayoutTests/fast/canvas/webgl/angle-instanced-arrays.html b/LayoutTests/fast/canvas/webgl/angle-instanced-arrays.html
new file mode 100644 (file)
index 0000000..24aa5f2
--- /dev/null
@@ -0,0 +1,297 @@
+<!--
+/*
+** 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>
index 40cbbe9..90644df 100644 (file)
@@ -361,6 +361,125 @@ var setupQuad = function (
 };
 
 /**
+ * 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.
  * @param {!WebGLTexture} tex The texture to fill.
@@ -475,6 +594,128 @@ var drawIndexedQuad = function(gl, gridRes, opt_color) {
 };
 
 /**
+ * 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)
+    return true;
+
+  if ('WebGL2RenderingContext' in window && ctx instanceof WebGL2RenderingContext)
+    return true;
+
+  return false;
+};
+
+/**
+ * Checks that a portion of a canvas is 1 color.
+ * @param {!WebGLRenderingContext|CanvasRenderingContext2D} gl The
+ *         WebGLRenderingContext or 2D context to use.
+ * @param {number} x left corner of region to check.
+ * @param {number} y bottom corner of region to check in case of checking from
+ *        a GL context or top corner in case of checking from a 2D context.
+ * @param {number} width width of region to check.
+ * @param {number} height width of region to check.
+ * @param {!Array.<number>} color The color expected. A 4 element array where
+ *        each element is in the range 0 to 255.
+ * @param {number} opt_errorRange Optional. Acceptable error in
+ *        color checking. 0 by default.
+ * @param {!function()} sameFn Function to call if all pixels
+ *        are the same as color.
+ * @param {!function()} differentFn Function to call if a pixel
+ *        is different than color
+ * @param {!function()} logFn Function to call for logging.
+ */
+var checkCanvasRectColor = function(gl, x, y, width, height, color, opt_errorRange, sameFn, differentFn, logFn) {
+  if (isWebGLContext(gl) && !gl.getParameter(gl.FRAMEBUFFER_BINDING)) {
+    // We're reading the backbuffer so clip.
+    var xr = clipToRange(x, width, 0, gl.canvas.width);
+    var yr = clipToRange(y, height, 0, gl.canvas.height);
+    if (!xr.extent || !yr.extent) {
+      logFn("checking rect: effective width or heigh is zero");
+      sameFn();
+      return;
+    }
+    x = xr.value;
+    y = yr.value;
+    width = xr.extent;
+    height = yr.extent;
+  }
+  var errorRange = opt_errorRange || 0;
+  if (!errorRange.length) {
+    errorRange = [errorRange, errorRange, errorRange, errorRange]
+  }
+  var buf;
+  if (isWebGLContext(gl)) {
+    buf = new Uint8Array(width * height * 4);
+    gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+  } else {
+    buf = gl.getImageData(x, y, width, height).data;
+  }
+  for (var i = 0; i < width * height; ++i) {
+    var offset = i * 4;
+    for (var j = 0; j < color.length; ++j) {
+      if (Math.abs(buf[offset + j] - color[j]) > errorRange[j]) {
+        differentFn();
+        var was = buf[offset + 0].toString();
+        for (j = 1; j < color.length; ++j) {
+          was += "," + buf[offset + j];
+        }
+        logFn('at (' + (x + (i % width)) + ', ' + (y + Math.floor(i / width)) +
+              ') expected: ' + color + ' was ' + was);
+        return;
+      }
+    }
+  }
+  sameFn();
+};
+
+/**
  * Checks that a portion of a canvas is 1 color.
  * @param {!WebGLContext} gl The WebGLContext to use.
  * @param {number} x left corner of region to check.
@@ -506,6 +747,9 @@ var checkCanvasRect = function(gl, x, y, width, height, color, msg, errorRange)
       }
     }
   }
+  if (!msg) {
+      msg = "Color was " + color;
+  }
   testPassed(msg);
 };
 
@@ -1331,11 +1575,13 @@ var waitForComposite = function(gl, callback) {
 
 return {
   cancelAnimFrame: cancelAnimFrame,
+  clipToRange: clipToRange,
   create3DContext: create3DContext,
   create3DContextWithWrapperThatThrowsOnGLError:
-    create3DContextWithWrapperThatThrowsOnGLError,
+  create3DContextWithWrapperThatThrowsOnGLError,
   checkCanvas: checkCanvas,
   checkCanvasRect: checkCanvasRect,
+  checkCanvasRectColor: checkCanvasRectColor,
   createColoredTexture: createColoredTexture,
   drawQuad: drawQuad,
   drawIndexedQuad: drawIndexedQuad,
@@ -1369,6 +1615,8 @@ return {
   setupColorQuad: setupColorQuad,
   setupProgram: setupProgram,
   setupQuad: setupQuad,
+  setupIndexedQuad: setupIndexedQuad,
+  setupIndexedQuadWithOptions: setupIndexedQuadWithOptions,
   setupSimpleTextureFragmentShader: setupSimpleTextureFragmentShader,
   setupSimpleTextureProgram: setupSimpleTextureProgram,
   setupSimpleTextureVertexShader: setupSimpleTextureVertexShader,
index 8051409..93dfe98 100644 (file)
@@ -1681,6 +1681,9 @@ webgl/conformance/ogles/GL/sin/sin_001_to_006.html [ Failure ]
 webgl/conformance/ogles/GL/vec3/vec3_001_to_008.html [ Failure ]
 webgl/conformance/textures/texture-attachment-formats.html [ Failure ]
 
+# ANGLE_instanced_arrays not implemented on efl
+fast/canvas/webgl/angle-instanced-arrays.html [ Skip ]
+
 # Text rendering is overflowing region
 webkit.org/b/122511 fast/regions/selection/selecting-text-ignoring-region-horiz-bt.html [ ImageOnlyFailure ]
 webkit.org/b/122511 fast/regions/selection/selecting-text-ignoring-region-vert-lr.html [ ImageOnlyFailure ]
diff --git a/LayoutTests/platform/mac-mountainlion/fast/canvas/webgl/angle-instanced-arrays-expected.txt b/LayoutTests/platform/mac-mountainlion/fast/canvas/webgl/angle-instanced-arrays-expected.txt
new file mode 100644 (file)
index 0000000..57e16c0
--- /dev/null
@@ -0,0 +1,16 @@
+CONSOLE MESSAGE: WebGL: INVALID_ENUM: getVertexAttrib: invalid parameter name
+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 No ANGLE_instanced_arrays support -- this is legal
+PASS ANGLE_instanced_arrays not listed as supported and getExtension failed -- this is legal
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
index 76e165a..1644b7c 100644 (file)
@@ -496,6 +496,7 @@ set(WebCore_IDL_FILES
     html/ValidityState.idl
     html/VoidCallback.idl
 
+    html/canvas/ANGLEInstancedArrays.idl
     html/canvas/CanvasGradient.idl
     html/canvas/CanvasPattern.idl
     html/canvas/CanvasProxy.idl
@@ -1492,6 +1493,7 @@ set(WebCore_SOURCES
     html/ValidationMessage.cpp
     html/WeekInputType.cpp
 
+    html/canvas/ANGLEInstancedArrays.cpp
     html/canvas/CanvasContextAttributes.cpp
     html/canvas/CanvasGradient.cpp
     html/canvas/CanvasPathMethods.cpp
@@ -2664,6 +2666,7 @@ if (ENABLE_WEBGL)
     add_definitions(-DWTF_USE_3D_GRAPHICS=1)
 
     list(APPEND WebCore_SOURCES
+        html/canvas/ANGLEInstancedArrays.cpp
         html/canvas/EXTDrawBuffers.cpp
         html/canvas/EXTTextureFilterAnisotropic.cpp
         html/canvas/OESElementIndexUint.cpp
@@ -2700,6 +2703,7 @@ if (ENABLE_WEBGL)
         html/canvas/WebGLVertexArrayObjectOES.cpp
     )
     list(APPEND WebCore_IDL_FILES
+        html/canvas/ANGLEInstancedArrays.idl
         html/canvas/EXTDrawBuffers.idl
         html/canvas/EXTTextureFilterAnisotropic.idl
         html/canvas/OESElementIndexUint.idl
index d033887..7ba4e03 100644 (file)
@@ -1,3 +1,77 @@
+2014-01-22  Dean Jackson  <dino@apple.com>
+
+        [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.
+
 2014-01-22  Zalan Bujtas  <zalan@apple.com>
 
         [CSS Shapes] shape-inside rectangle layout can fail
index 657268b..a2d53d6 100644 (file)
@@ -27,6 +27,9 @@
 
 #include "HTMLElementFactory.cpp"
 #include "HTMLEntityTable.cpp"
+#if ENABLE(WEBGL)
+#include "JSANGLEInstancedArrays.cpp"
+#endif
 #include "JSAbstractWorker.cpp"
 #include "JSAttr.cpp"
 #include "JSBarProp.cpp"
index 382b47b..4f894aa 100644 (file)
@@ -408,6 +408,7 @@ BINDING_IDLS = \
     $(WebCore)/html/TimeRanges.idl \
     $(WebCore)/html/ValidityState.idl \
     $(WebCore)/html/VoidCallback.idl \
+    $(WebCore)/html/canvas/ANGLEInstancedArrays.idl \
     $(WebCore)/html/canvas/CanvasGradient.idl \
     $(WebCore)/html/canvas/CanvasPattern.idl \
     $(WebCore)/html/canvas/CanvasProxy.idl \
index 9e2c98e..03a1c7a 100644 (file)
@@ -28,6 +28,8 @@ webcore_built_sources += \
        DerivedSources/WebCore/InspectorWebFrontendDispatchers.h \
        DerivedSources/WebCore/InspectorWebTypeBuilders.cpp \
        DerivedSources/WebCore/InspectorWebTypeBuilders.h \
+       DerivedSources/WebCore/JSANGLEInstancedArrays.cpp \
+       DerivedSources/WebCore/JSANGLEInstancedArrays.h \
        DerivedSources/WebCore/JSAbstractWorker.cpp \
        DerivedSources/WebCore/JSAbstractWorker.h \
        DerivedSources/WebCore/JSAllAudioCapabilities.cpp \
@@ -1506,6 +1508,7 @@ dom_binding_idls += \
        $(WebCore)/html/TimeRanges.idl \
        $(WebCore)/html/ValidityState.idl \
        $(WebCore)/html/VoidCallback.idl \
+       $(WebCore)/html/canvas/ANGLEInstancedArrays.idl \
        $(WebCore)/html/canvas/CanvasGradient.idl \
        $(WebCore)/html/canvas/CanvasPattern.idl \
        $(WebCore)/html/canvas/CanvasProxy.idl \
@@ -3240,6 +3243,8 @@ webcore_sources += \
        Source/WebCore/html/BaseTextInputType.h \
        Source/WebCore/html/ButtonInputType.cpp \
        Source/WebCore/html/ButtonInputType.h \
+       Source/WebCore/html/canvas/ANGLEInstancedArrays.cpp \
+       Source/WebCore/html/canvas/ANGLEInstancedArrays.h \
        Source/WebCore/html/canvas/CanvasContextAttributes.cpp \
        Source/WebCore/html/canvas/CanvasContextAttributes.h \
        Source/WebCore/html/canvas/CanvasGradient.cpp \
index eff952a..a5b4b9d 100644 (file)
     </ClCompile>
     <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\CSSPropertyNames.cpp" />
     <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\CSSValueKeywords.cpp" />
+    <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSANGLEInstancedArrays.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSEXTDrawBuffers.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
       <ForcedIncludeFiles Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">ICUVersion.h</ForcedIncludeFiles>
       <ForcedIncludeFiles Condition="'$(Configuration)|$(Platform)'=='Production|x64'">ICUVersion.h</ForcedIncludeFiles>
     </ClCompile>
+    <ClCompile Include="..\html\canvas\ANGLEInstancedArrays.cpp" />
     <ClCompile Include="..\html\canvas\CanvasContextAttributes.cpp" />
     <ClCompile Include="..\html\canvas\CanvasPathMethods.cpp" />
     <ClCompile Include="..\html\canvas\EXTDrawBuffers.cpp" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\XMLViewerCSS.h" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\XMLViewerJS.h" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\XPathGrammar.h" />
+    <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSANGLEInstancedArrays.h" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSEXTDrawBuffers.h" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSEXTTextureFilterAnisotropic.h" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSOESElementIndexUint.h" />
     <ClInclude Include="..\ForwardingHeaders\runtime\WeakGCMap.h" />
     <ClInclude Include="..\ForwardingHeaders\runtime\WriteBarrier.h" />
     <ClInclude Include="..\ForwardingHeaders\yarr\YarrJIT.h" />
+    <ClInclude Include="..\html\canvas\ANGLEInstancedArrays.h" />
     <ClInclude Include="..\html\canvas\CanvasContextAttributes.h" />
     <ClInclude Include="..\html\canvas\CanvasPathMethods.h" />
     <ClInclude Include="..\html\canvas\EXTDrawBuffers.h" />
index 8e98950..eb20603 100644 (file)
     <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSWebGLVertexArrayObjectOES.cpp">
       <Filter>DerivedSources</Filter>
     </ClCompile>
+    <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSANGLEInstancedArrays.cpp">
+      <Filter>DerivedSources</Filter>
+    </ClCompile>
     <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSEXTDrawBuffers.cpp">
       <Filter>DerivedSources</Filter>
     </ClCompile>
     <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSOESVertexArrayObject.cpp">
       <Filter>DerivedSources</Filter>
     </ClCompile>
+    <ClCompile Include="..\html\canvas\ANGLEInstancedArrays.cpp">
+      <Filter>html\canvas</Filter>
+    </ClCompile>
     <ClCompile Include="..\html\canvas\WebGLBuffer.cpp">
       <Filter>html\canvas</Filter>
     </ClCompile>
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSOESVertexArrayObject.h">
       <Filter>DerivedSources</Filter>
     </ClInclude>
+    <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources\JSANGLEInstancedArrays.h">
+      <Filter>DerivedSources</Filter>
+    </ClInclude>
+    <ClInclude Include="..\html\canvas\ANGLEInstancedArrays.h">
+      <Filter>html\canvas</Filter>
+    </ClInclude>
     <ClInclude Include="..\html\canvas\WebGLActiveInfo.h">
       <Filter>html\canvas</Filter>
     </ClInclude>
index d6f931e..d8b28a7 100644 (file)
                319AE063142D6B24006563A1 /* StyleFilterData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 319AE061142D6B24006563A1 /* StyleFilterData.cpp */; };
                319AE064142D6B24006563A1 /* StyleFilterData.h in Headers */ = {isa = PBXBuildFile; fileRef = 319AE062142D6B24006563A1 /* StyleFilterData.h */; settings = {ATTRIBUTES = (Private, ); }; };
                319FBD5F15D2F464009640A6 /* CachedImageClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 319FBD5D15D2F444009640A6 /* CachedImageClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               31A795C61888BADC00382F90 /* JSANGLEInstancedArrays.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 31A795C41888BAD100382F90 /* JSANGLEInstancedArrays.cpp */; };
+               31A795C71888BCB200382F90 /* ANGLEInstancedArrays.h in Headers */ = {isa = PBXBuildFile; fileRef = 31A795C21888B72400382F90 /* ANGLEInstancedArrays.h */; };
+               31A795C81888BCB500382F90 /* ANGLEInstancedArrays.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 31A795C11888B72400382F90 /* ANGLEInstancedArrays.cpp */; };
                31AB5000122878A2001A7DB0 /* GraphicsContext3DIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 31AB4FFF122878A2001A7DB0 /* GraphicsContext3DIOS.h */; };
                31C0FF210E4CEB6E007D6FE5 /* WebKitAnimationEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 31C0FF1B0E4CEB6E007D6FE5 /* WebKitAnimationEvent.cpp */; };
                31C0FF220E4CEB6E007D6FE5 /* WebKitAnimationEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 31C0FF1C0E4CEB6E007D6FE5 /* WebKitAnimationEvent.h */; };
                319AE061142D6B24006563A1 /* StyleFilterData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StyleFilterData.cpp; path = style/StyleFilterData.cpp; sourceTree = "<group>"; };
                319AE062142D6B24006563A1 /* StyleFilterData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StyleFilterData.h; path = style/StyleFilterData.h; sourceTree = "<group>"; };
                319FBD5D15D2F444009640A6 /* CachedImageClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedImageClient.h; sourceTree = "<group>"; };
+               31A795C11888B72400382F90 /* ANGLEInstancedArrays.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ANGLEInstancedArrays.cpp; path = canvas/ANGLEInstancedArrays.cpp; sourceTree = "<group>"; };
+               31A795C21888B72400382F90 /* ANGLEInstancedArrays.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANGLEInstancedArrays.h; path = canvas/ANGLEInstancedArrays.h; sourceTree = "<group>"; };
+               31A795C31888B72400382F90 /* ANGLEInstancedArrays.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ANGLEInstancedArrays.idl; path = canvas/ANGLEInstancedArrays.idl; sourceTree = "<group>"; };
+               31A795C41888BAD100382F90 /* JSANGLEInstancedArrays.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSANGLEInstancedArrays.cpp; sourceTree = "<group>"; };
+               31A795C51888BAD100382F90 /* JSANGLEInstancedArrays.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSANGLEInstancedArrays.h; sourceTree = "<group>"; };
                31AB4FFF122878A2001A7DB0 /* GraphicsContext3DIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphicsContext3DIOS.h; sourceTree = "<group>"; };
                31C0FF1B0E4CEB6E007D6FE5 /* WebKitAnimationEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebKitAnimationEvent.cpp; sourceTree = "<group>"; };
                31C0FF1C0E4CEB6E007D6FE5 /* WebKitAnimationEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitAnimationEvent.h; sourceTree = "<group>"; };
                49484FAE102CF01E00187DD3 /* canvas */ = {
                        isa = PBXGroup;
                        children = (
+                               31A795C11888B72400382F90 /* ANGLEInstancedArrays.cpp */,
+                               31A795C21888B72400382F90 /* ANGLEInstancedArrays.h */,
+                               31A795C31888B72400382F90 /* ANGLEInstancedArrays.idl */,
                                6E4E91A710F7FB3100A2779C /* CanvasContextAttributes.cpp */,
                                6E4E91A810F7FB3100A2779C /* CanvasContextAttributes.h */,
                                49484FB3102CF23C00187DD3 /* CanvasGradient.cpp */,
                A83B79080CCAFF2B000B0825 /* HTML */ = {
                        isa = PBXGroup;
                        children = (
+                               31A795C41888BAD100382F90 /* JSANGLEInstancedArrays.cpp */,
+                               31A795C51888BAD100382F90 /* JSANGLEInstancedArrays.h */,
                                BE8EF03E171C8FF9009B48C3 /* JSAudioTrack.cpp */,
                                BE8EF03F171C8FF9009B48C3 /* JSAudioTrack.h */,
                                BE8EF040171C8FF9009B48C3 /* JSAudioTrackList.cpp */,
                                498391520F1E76B400C23782 /* DOMWebKitCSSMatrixInternal.h in Headers */,
                                8AD0A59614C88358000D83C5 /* DOMWebKitCSSRegionRule.h in Headers */,
                                8AD0A59814C88358000D83C5 /* DOMWebKitCSSRegionRuleInternal.h in Headers */,
+                               31A795C71888BCB200382F90 /* ANGLEInstancedArrays.h in Headers */,
                                31611E610E1C4E1400F6A579 /* DOMWebKitCSSTransformValue.h in Headers */,
                                31611E630E1C4E1400F6A579 /* DOMWebKitCSSTransformValueInternal.h in Headers */,
                                3F2B33EB165AF15600E3987C /* DOMWebKitCSSViewportRule.h in Headers */,
                                9393E604151A9A1800066F06 /* StyleCachedImageSet.cpp in Sources */,
                                5038BE2F1472AD230095E0D1 /* StyleCachedShader.cpp in Sources */,
                                50E18CD816F9285800C65486 /* StyleCustomFilterProgram.cpp in Sources */,
+                               31A795C81888BCB500382F90 /* ANGLEInstancedArrays.cpp in Sources */,
                                A5840E24187B8AC200843B10 /* PageInjectedScriptHost.cpp in Sources */,
                                50E18CD916F9285800C65486 /* StyleCustomFilterProgramCache.cpp in Sources */,
                                A8C4A7FE09D563270003AC8D /* StyledElement.cpp in Sources */,
                                AAF5B7B71524B6C50004CB49 /* WebSocketFrame.cpp in Sources */,
                                97AABD2614FA09D5007457AE /* WebSocketHandshake.cpp in Sources */,
                                0F580FA41496939100FB5BD8 /* WebTiledBackingLayer.mm in Sources */,
+                               31A795C61888BADC00382F90 /* JSANGLEInstancedArrays.cpp in Sources */,
                                CD82030B1395AB6A00F956C6 /* WebVideoFullscreenController.mm in Sources */,
                                CD82030D1395AB6A00F956C6 /* WebVideoFullscreenHUDWindowController.mm in Sources */,
                                F12171F516A8CED2000053CA /* WebVTTElement.cpp in Sources */,
index 0e81d75..9e390fc 100644 (file)
 
 #include "JSWebGLRenderingContext.h"
 
+#include "ANGLEInstancedArrays.h"
 #include "EXTDrawBuffers.h"
 #include "EXTTextureFilterAnisotropic.h"
 #include "ExceptionCode.h"
 #include "HTMLCanvasElement.h"
 #include "HTMLImageElement.h"
+#include "JSANGLEInstancedArrays.h"
 #include "JSEXTDrawBuffers.h"
 #include "JSEXTTextureFilterAnisotropic.h"
 #include "JSHTMLCanvasElement.h"
@@ -233,6 +235,8 @@ static JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, WebGLExten
         return toJS(exec, globalObject, static_cast<WebGLCompressedTextureS3TC*>(extension));
     case WebGLExtension::WebGLDepthTextureName:
         return toJS(exec, globalObject, static_cast<WebGLDepthTexture*>(extension));
+    case WebGLExtension::ANGLEInstancedArraysName:
+        return toJS(exec, globalObject, static_cast<ANGLEInstancedArrays*>(extension));
     }
     ASSERT_NOT_REACHED();
     return jsNull();
diff --git a/Source/WebCore/html/canvas/ANGLEInstancedArrays.cpp b/Source/WebCore/html/canvas/ANGLEInstancedArrays.cpp
new file mode 100644 (file)
index 0000000..f56c2ca
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEBGL)
+#include "ANGLEInstancedArrays.h"
+
+namespace WebCore {
+
+ANGLEInstancedArrays::ANGLEInstancedArrays(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+}
+
+ANGLEInstancedArrays::~ANGLEInstancedArrays()
+{
+}
+
+WebGLExtension::ExtensionName ANGLEInstancedArrays::getName() const
+{
+    return ANGLEInstancedArraysName;
+}
+
+OwnPtr<ANGLEInstancedArrays> ANGLEInstancedArrays::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new ANGLEInstancedArrays(context));
+}
+
+bool ANGLEInstancedArrays::supported(WebGLRenderingContext*)
+{
+#if PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+    return true;
+#else
+    return false;
+#endif
+}
+
+void ANGLEInstancedArrays::drawArraysInstancedANGLE(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
+{
+    if (m_context->isContextLost())
+        return;
+    m_context->drawArraysInstanced(mode, first, count, primcount);
+}
+
+void ANGLEInstancedArrays::drawElementsInstancedANGLE(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount)
+{
+    if (m_context->isContextLost())
+        return;
+    m_context->drawElementsInstanced(mode, count, type, offset, primcount);
+}
+
+void ANGLEInstancedArrays::vertexAttribDivisorANGLE(GC3Duint index, GC3Duint divisor)
+{
+    if (m_context->isContextLost())
+        return;
+    m_context->vertexAttribDivisor(index, divisor);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGL)
diff --git a/Source/WebCore/html/canvas/ANGLEInstancedArrays.h b/Source/WebCore/html/canvas/ANGLEInstancedArrays.h
new file mode 100644 (file)
index 0000000..622aa80
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANGLEInstancedArrays_h
+#define ANGLEInstancedArrays_h
+
+#include "WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebGLRenderingContext;
+
+class ANGLEInstancedArrays : public WebGLExtension {
+public:
+    static OwnPtr<ANGLEInstancedArrays> create(WebGLRenderingContext*);
+    virtual ~ANGLEInstancedArrays();
+    virtual ExtensionName getName() const;
+
+    static bool supported(WebGLRenderingContext*);
+
+    void drawArraysInstancedANGLE(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount);
+    void drawElementsInstancedANGLE(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount);
+    void vertexAttribDivisorANGLE(GC3Duint index, GC3Duint divisor);
+
+private:
+    ANGLEInstancedArrays(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // ANGLEInstancedArrays_h
diff --git a/Source/WebCore/html/canvas/ANGLEInstancedArrays.idl b/Source/WebCore/html/canvas/ANGLEInstancedArrays.idl
new file mode 100644 (file)
index 0000000..95d7ebd
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+    NoInterfaceObject,
+    Conditional=WEBGL,
+    GenerateIsReachable=ImplWebGLRenderingContext,
+] interface ANGLEInstancedArrays {
+    const GLenum VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
+
+    [StrictTypeChecking] void drawArraysInstancedANGLE(unsigned long mode, long first, long count, long primcount);
+    [StrictTypeChecking] void drawElementsInstancedANGLE(unsigned long mode, long count, unsigned long type, long long offset, long primcount);
+    [StrictTypeChecking] void vertexAttribDivisorANGLE(unsigned long index, unsigned long divisor);
+};
index 1d5df5c..e9100db 100644 (file)
@@ -51,6 +51,7 @@ public:
         OESElementIndexUintName,
         WebGLCompressedTextureATCName,
         WebGLCompressedTexturePVRTCName,
+        ANGLEInstancedArraysName,
     };
 
     void ref() { m_context->ref(); }
index ee9f434..d908b4e 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "WebGLRenderingContext.h"
 
+#include "ANGLEInstancedArrays.h"
 #include "CachedImage.h"
 #include "DOMWindow.h"
 #include "EXTDrawBuffers.h"
@@ -1886,7 +1887,7 @@ bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum
     return numElementsRequired > 0;
 }
 
-bool WebGLRenderingContext::validateVertexAttributes(unsigned numElementsRequired)
+bool WebGLRenderingContext::validateVertexAttributes(unsigned elementCount, unsigned primitiveCount)
 {
     if (!m_currentProgram)
         return false;
@@ -1897,17 +1898,20 @@ bool WebGLRenderingContext::validateVertexAttributes(unsigned numElementsRequire
             return false;
     }
 
-    if (numElementsRequired <= 0)
+    if (elementCount <= 0)
         return true;
 
-    // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
-    unsigned smallestNumElements = UINT_MAX;
+
+    // Look in each consumed vertex attrib (by the current program).
+    bool sawNonInstancedAttrib = false;
+    bool sawEnabledAttrib = false;
     int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
     for (int i = 0; i < numActiveAttribLocations; ++i) {
         int loc = m_currentProgram->getActiveAttribLocation(i);
         if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
             const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
             if (state.enabled) {
+                sawEnabledAttrib = true;
                 // Avoid off-by-one errors in numElements computation.
                 // For the last element, we will only touch the data for the
                 // element and nothing beyond it.
@@ -1916,16 +1920,18 @@ bool WebGLRenderingContext::validateVertexAttributes(unsigned numElementsRequire
                 ASSERT(state.stride > 0);
                 if (bytesRemaining >= state.bytesPerElement)
                     numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
-                if (numElements < smallestNumElements)
-                    smallestNumElements = numElements;
+                if (!state.divisor)
+                    sawNonInstancedAttrib = true;
+                if ((!state.divisor && elementCount > numElements) || (state.divisor && primitiveCount > numElements))
+                    return false;
             }
         }
     }
 
-    if (smallestNumElements == INT_MAX)
-        smallestNumElements = 0;
+    if (!sawNonInstancedAttrib && sawEnabledAttrib)
+        return false;
 
-    return numElementsRequired <= smallestNumElements;
+    return true;
 }
 
 bool WebGLRenderingContext::validateWebGLObject(const char* functionName, WebGLObject* object)
@@ -1941,24 +1947,27 @@ bool WebGLRenderingContext::validateWebGLObject(const char* functionName, WebGLO
     return true;
 }
 
-void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
+bool WebGLRenderingContext::validateDrawArrays(const char* functionName, GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
 {
-    UNUSED_PARAM(ec);
-
-    if (isContextLost() || !validateDrawMode("drawArrays", mode))
-        return;
+    if (isContextLost() || !validateDrawMode(functionName, mode))
+        return false;
 
-    if (!validateStencilSettings("drawArrays"))
-        return;
+    if (!validateStencilSettings(functionName))
+        return false;
 
     if (first < 0 || count < 0) {
-        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawArrays", "first or count < 0");
-        return;
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "first or count < 0");
+        return false;
     }
 
     if (!count) {
         cleanupAfterGraphicsCall(true);
-        return;
+        return false;
+    }
+
+    if (primcount < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
+        return false;
     }
 
     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
@@ -1966,23 +1975,34 @@ void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei c
         Checked<GC3Dint, RecordOverflow> checkedFirst(first);
         Checked<GC3Dint, RecordOverflow> checkedCount(count);
         Checked<GC3Dint, RecordOverflow> checkedSum = checkedFirst + checkedCount;
-        if (checkedSum.hasOverflowed() || !validateVertexAttributes(checkedSum.unsafeGet())) {
-            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attempt to access out of bounds arrays");
-            return;
+        Checked<GC3Dint, RecordOverflow> checkedPrimCount(primcount);
+        if (checkedSum.hasOverflowed() || checkedPrimCount.hasOverflowed() || !validateVertexAttributes(checkedSum.unsafeGet(), checkedPrimCount.unsafeGet())) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
+            return false;
         }
     } else {
         if (!validateVertexAttributes(0)) {
-            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attribs not setup correctly");
-            return;
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
+            return false;
         }
     }
 
     const char* reason = "framebuffer incomplete";
     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
-        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawArrays", reason);
-        return;
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
+        return false;
     }
 
+    return true;
+}
+
+void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+
+    if (!validateDrawArrays("drawArrays", mode, first, count, 0))
+        return;
+
     clearIfComposited();
 
     bool vertexAttrib0Simulated = false;
@@ -1998,15 +2018,13 @@ void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei c
     cleanupAfterGraphicsCall(true);
 }
 
-void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode& ec)
+bool WebGLRenderingContext::validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements)
 {
-    UNUSED_PARAM(ec);
-
-    if (isContextLost() || !validateDrawMode("drawElements", mode))
-        return;
+    if (isContextLost() || !validateDrawMode(functionName, mode))
+        return false;
 
-    if (!validateStencilSettings("drawElements"))
-        return;
+    if (!validateStencilSettings(functionName))
+        return false;
 
     switch (type) {
     case GraphicsContext3D::UNSIGNED_BYTE:
@@ -2015,55 +2033,66 @@ void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denu
     case GraphicsContext3D::UNSIGNED_INT:
         if (m_oesElementIndexUint)
             break;
-        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "drawElements", "invalid type");
-        return;
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
+        return false;
     default:
-        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "drawElements", "invalid type");
-        return;
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
+        return false;
     }
 
     if (count < 0 || offset < 0) {
-        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawElements", "count or offset < 0");
-        return;
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "count or offset < 0");
+        return false;
     }
 
     if (!count) {
         cleanupAfterGraphicsCall(true);
-        return;
+        return false;
     }
 
     if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
-        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "no ELEMENT_ARRAY_BUFFER bound");
-        return;
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound");
+        return false;
     }
 
-    unsigned numElements = 0;
     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
         // Ensure we have a valid rendering state
         if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
-            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "request out of bounds for current ELEMENT_ARRAY_BUFFER");
-            return;
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "request out of bounds for current ELEMENT_ARRAY_BUFFER");
+            return false;
         }
         if (!count)
-            return;
+            return false;
         if (!validateIndexArrayConservative(type, numElements) || !validateVertexAttributes(numElements)) {
             if (!validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements) || !validateVertexAttributes(numElements)) {
-                synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attempt to access out of bounds arrays");
-                return;
+                synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
+                return false;
             }
         }
     } else {
         if (!validateVertexAttributes(0)) {
-            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attribs not setup correctly");
-            return;
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
+            return false;
         }
     }
 
     const char* reason = "framebuffer incomplete";
     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
-        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawElements", reason);
-        return;
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
+        return false;
     }
+
+    return true;
+}
+
+void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+
+    unsigned numElements = 0;
+    if (!validateDrawElements("drawElements", mode, count, type, offset, numElements))
+        return;
+
     clearIfComposited();
 
     bool vertexAttrib0Simulated = false;
@@ -2477,6 +2506,13 @@ WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
         }
         return m_extDrawBuffers.get();
     }
+    if (equalIgnoringCase(name, "ANGLE_instanced_arrays") && ANGLEInstancedArrays::supported(this)) {
+        if (!m_angleInstancedArrays) {
+            m_context->getExtensions()->ensureEnabled("GL_ANGLE_instanced_arrays");
+            m_angleInstancedArrays = ANGLEInstancedArrays::create(this);
+        }
+        return m_angleInstancedArrays.get();
+    }
     if (allowPrivilegedExtensions()) {
         if (equalIgnoringCase(name, "WEBGL_debug_renderer_info")) {
             if (!m_webglDebugRendererInfo)
@@ -2998,6 +3034,8 @@ Vector<String> WebGLRenderingContext::getSupportedExtensions()
         result.append("WEBGL_depth_texture");
     if (supportsDrawBuffers())
         result.append("EXT_draw_buffers");
+    if (ANGLEInstancedArrays::supported(this))
+        result.append("ANGLE_instanced_arrays");
 
     if (allowPrivilegedExtensions()) {
         if (m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source"))
@@ -3210,14 +3248,22 @@ PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGL
 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
 {
     UNUSED_PARAM(ec);
+
     if (isContextLost())
         return WebGLGetInfo();
+
     WebGLStateRestorer(this, false);
+
     if (index >= m_maxVertexAttribs) {
         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getVertexAttrib", "index out of range");
         return WebGLGetInfo();
     }
+
     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
+
+    if (m_angleInstancedArrays && pname == GraphicsContext3D::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE)
+        return WebGLGetInfo(state.divisor);
+
     switch (pname) {
     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
         if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
@@ -6102,6 +6148,86 @@ bool WebGLRenderingContext::supportsDrawBuffers()
     return m_drawBuffersSupported;
 }
 
+void WebGLRenderingContext::drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
+{
+    if (!validateDrawArrays("drawArraysInstanced", mode, first, count, primcount))
+        return;
+
+    if (primcount < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawArraysInstanced", "primcount < 0");
+        return;
+    }
+
+    if (!primcount) {
+        cleanupAfterGraphicsCall(true);
+        return;
+    }
+
+    clearIfComposited();
+
+    bool vertexAttrib0Simulated = false;
+    if (!isGLES2Compliant())
+        vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness("drawArraysInstanced", true);
+    UNUSED_PARAM(primcount);
+    m_context->drawArraysInstanced(mode, first, count, primcount);
+    if (!isGLES2Compliant() && vertexAttrib0Simulated)
+        restoreStatesAfterVertexAttrib0Simulation();
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness("drawArraysInstanced", false);
+    cleanupAfterGraphicsCall(true);
+}
+
+void WebGLRenderingContext::drawElementsInstanced(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount)
+{
+    unsigned numElements = 0;
+    if (!validateDrawElements("drawElementsInstanced", mode, count, type, offset, numElements))
+        return;
+
+    if (primcount < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawElementsInstanced", "primcount < 0");
+        return;
+    }
+
+    if (!primcount) {
+        cleanupAfterGraphicsCall(true);
+        return;
+    }
+
+    clearIfComposited();
+
+    bool vertexAttrib0Simulated = false;
+    if (!isGLES2Compliant()) {
+        if (!numElements)
+            validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements);
+        vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
+    }
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness("drawElementsInstanced", true);
+    m_context->drawElementsInstanced(mode, count, type, static_cast<GC3Dintptr>(offset), primcount);
+    if (!isGLES2Compliant() && vertexAttrib0Simulated)
+        restoreStatesAfterVertexAttrib0Simulation();
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness("drawElementsInstanced", false);
+    cleanupAfterGraphicsCall(true);
+}
+
+void WebGLRenderingContext::vertexAttribDivisor(GC3Duint index, GC3Duint divisor)
+{
+    if (isContextLost())
+        return;
+
+    if (index >= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "vertexAttribDivisor", "index out of range");
+        return;
+    }
+
+    m_boundVertexArrayObject->setVertexAttribDivisor(index, divisor);
+    m_context->vertexAttribDivisor(index, divisor);
+}
+
+
 } // namespace WebCore
 
 #endif // ENABLE(WEBGL)
index 38628c0..d4ba54b 100644 (file)
@@ -41,6 +41,7 @@
 
 namespace WebCore {
 
+class ANGLEInstancedArrays;
 class EXTDrawBuffers;
 class EXTTextureFilterAnisotropic;
 class HTMLImageElement;
@@ -323,6 +324,11 @@ public:
     
     unsigned getMaxVertexAttribs() const { return m_maxVertexAttribs; }
 
+    // ANGLE_instanced_arrays extension functions.
+    void drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount);
+    void drawElementsInstanced(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount);
+    void vertexAttribDivisor(GC3Duint index, GC3Duint divisor);
+
 private:
     friend class EXTDrawBuffers;
     friend class WebGLFramebuffer;
@@ -378,11 +384,13 @@ private:
 
     // Precise but slow index validation -- only done if conservative checks fail
     bool validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, unsigned& numElementsRequired);
-    // If numElements <= 0, we only check if each enabled vertex attribute is bound to a buffer.
-    bool validateVertexAttributes(unsigned numElements);
+    bool validateVertexAttributes(unsigned elementCount, unsigned primitiveCount = 0);
 
     bool validateWebGLObject(const char*, WebGLObject*);
 
+    bool validateDrawArrays(const char* functionName, GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount);
+    bool validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements);
+
     // Adds a compressed texture format.
     void addCompressedTextureFormat(GC3Denum);
 
@@ -540,6 +548,7 @@ private:
     OwnPtr<WebGLCompressedTexturePVRTC> m_webglCompressedTexturePVRTC;
     OwnPtr<WebGLCompressedTextureS3TC> m_webglCompressedTextureS3TC;
     OwnPtr<WebGLDepthTexture> m_webglDepthTexture;
+    OwnPtr<ANGLEInstancedArrays> m_angleInstancedArrays;
 
     // Helpers for getParameter and others
     WebGLGetInfo getBooleanParameter(GC3Denum);
index a98d092..ce18a9f 100644 (file)
@@ -143,6 +143,12 @@ void WebGLVertexArrayObjectOES::unbindBuffer(PassRefPtr<WebGLBuffer> buffer)
     }
 }
 
+void WebGLVertexArrayObjectOES::setVertexAttribDivisor(GC3Duint index, GC3Duint divisor)
+{
+    VertexAttribState& state = m_vertexAttribState[index];
+    state.divisor = divisor;
+}
+
 }
 
 #endif // ENABLE(WEBGL)
index 9ad4902..8853ff9 100644 (file)
@@ -55,6 +55,7 @@ public:
             , stride(16)
             , originalStride(0)
             , offset(0)
+            , divisor(0)
         {
         }
         
@@ -70,6 +71,7 @@ public:
         GC3Dsizei stride;
         GC3Dsizei originalStride;
         GC3Dintptr offset;
+        GC3Duint divisor;
     };
     
     bool isDefaultObject() const { return m_type == VaoTypeDefault; }
@@ -84,6 +86,8 @@ public:
     void setVertexAttribState(GC3Duint, GC3Dsizei, GC3Dint, GC3Denum, GC3Dboolean, GC3Dsizei, GC3Dintptr, PassRefPtr<WebGLBuffer>);
     void unbindBuffer(PassRefPtr<WebGLBuffer>);
 
+    void setVertexAttribDivisor(GC3Duint index, GC3Duint divisor);
+
 private:
     WebGLVertexArrayObjectOES(WebGLRenderingContext*, VaoType);
 
index c4d72a7..705c327 100644 (file)
@@ -425,7 +425,8 @@ public:
         UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241,
         CONTEXT_LOST_WEBGL = 0x9242,
         UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243,
-        BROWSER_DEFAULT_WEBGL = 0x9244
+        BROWSER_DEFAULT_WEBGL = 0x9244,
+        VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE
     };
 
     // Context creation attributes.
@@ -827,6 +828,10 @@ public:
 
     void reshape(int width, int height);
 
+    void drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount);
+    void drawElementsInstanced(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount);
+    void vertexAttribDivisor(GC3Duint index, GC3Duint divisor);
+
 #if PLATFORM(GTK) || PLATFORM(EFL) || USE(CAIRO)
     void paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight,
                        int canvasWidth, int canvasHeight, PlatformContextCairo* context);
index 76148da..30acf30 100644 (file)
 #define glRenderbufferStorageEXT glRenderbufferStorage
 #define glRenderbufferStorageMultisampleEXT glRenderbufferStorageMultisampleAPPLE
 
+#define glDrawArraysInstancedARB glDrawArraysInstancedEXT
+#define glDrawElementsInstancedARB glDrawElementsInstancedEXT
+#define glVertexAttribDivisorARB glVertexAttribDivisorEXT
+
 #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0
 #define GL_DEPTH24_STENCIL8_EXT GL_DEPTH24_STENCIL8_OES
 #define GL_DEPTH_ATTACHMENT_EXT  GL_DEPTH_ATTACHMENT
index 4228312..886e637 100644 (file)
@@ -370,6 +370,44 @@ void GraphicsContext3D::setErrorMessageCallback(PassOwnPtr<ErrorMessageCallback>
 {
 }
 
+void GraphicsContext3D::drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
+{
+#if PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+    makeContextCurrent();
+    ::glDrawArraysInstancedARB(mode, first, count, primcount);
+#else
+    UNUSED_PARAM(mode);
+    UNUSED_PARAM(first);
+    UNUSED_PARAM(count);
+    UNUSED_PARAM(primcount);
+#endif
+}
+
+void GraphicsContext3D::drawElementsInstanced(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount)
+{
+#if PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+    makeContextCurrent();
+    ::glDrawElementsInstancedARB(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)), primcount);
+#else
+    UNUSED_PARAM(mode);
+    UNUSED_PARAM(count);
+    UNUSED_PARAM(type);
+    UNUSED_PARAM(offset);
+    UNUSED_PARAM(primcount);
+#endif
+}
+
+void GraphicsContext3D::vertexAttribDivisor(GC3Duint index, GC3Duint divisor)
+{
+#if PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+    makeContextCurrent();
+    ::glVertexAttribDivisorARB(index, divisor);
+#else
+    UNUSED_PARAM(index);
+    UNUSED_PARAM(divisor);
+#endif
+}
+
 }
 
 #endif // USE(3D_GRAPHICS)
index e048418..02e1b9e 100644 (file)
@@ -351,6 +351,31 @@ void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsi
         ::glBindFramebufferEXT(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO);
 }
 
+#if !PLATFORM(MAC)
+void GraphicsContext3D::drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
+{
+    UNUSED_PARAM(mode);
+    UNUSED_PARAM(first);
+    UNUSED_PARAM(count);
+    UNUSED_PARAM(primcount);
+}
+
+void GraphicsContext3D::drawElementsInstanced(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount)
+{
+    UNUSED_PARAM(mode);
+    UNUSED_PARAM(count);
+    UNUSED_PARAM(type);
+    UNUSED_PARAM(offset);
+    UNUSED_PARAM(primcount);
+}
+
+void GraphicsContext3D::vertexAttribDivisor(GC3Duint index, GC3Duint divisor)
+{
+    UNUSED_PARAM(index);
+    UNUSED_PARAM(divisor);
+}
+#endif
+
 }
 
 #endif // USE(3D_GRAPHICS)