WebGL 2 Conformance: primitive restart and draw_primitive_restart WebGL2 sample
authorjustin_fan@apple.com <justin_fan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Sep 2018 00:24:52 +0000 (00:24 +0000)
committerjustin_fan@apple.com <justin_fan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Sep 2018 00:24:52 +0000 (00:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189625
<rdar://problem/42882620>

Reviewed by Dean Jackson.

Source/WebCore:

Ref test: webgl/webgl2-primitive-restart.html.

Implement support for Primitive Restart Fixed Index as expected
by the WebGL 2 specifications.

* html/canvas/WebGL2RenderingContext.cpp:
(WebCore::WebGL2RenderingContext::validateIndexArrayConservative):
* html/canvas/WebGLRenderingContextBase.h:
(WebCore::WebGLRenderingContextBase::getLastIndex): Template that must be defined in header.
* html/canvas/WebGLRenderingContextBase.cpp:
(WebCore::WebGLRenderingContextBase::validateIndexArrayPrecise):
* platform/graphics/GraphicsContext3D.h:
* platform/graphics/cocoa/GraphicsContext3DCocoa.mm:
(WebCore::GraphicsContext3D::GraphicsContext3D):
* platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp:
(WebCore::GraphicsContext3D::primitiveRestartIndex):

LayoutTests:

Implement support for Primitive Restart Fixed Index as expected
by the WebGL 2 specifications.

* TestExpectations: Skip some flaky tests between different Mac machines under 2.0.0.
* webgl/webgl2-primitive-restart.html: Canary ref test to be run as part of LayoutTests suite.
* webgl/webgl2-primitive-restart-expected.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236490 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/webgl/webgl2-primitive-restart-expected.html [new file with mode: 0644]
LayoutTests/webgl/webgl2-primitive-restart.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/html/canvas/WebGL2RenderingContext.cpp
Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
Source/WebCore/html/canvas/WebGLRenderingContextBase.h
Source/WebCore/platform/graphics/GraphicsContext3D.h
Source/WebCore/platform/graphics/cocoa/GraphicsContext3DCocoa.mm
Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp

index 63073db..2de12dd 100644 (file)
@@ -1,3 +1,18 @@
+2018-09-25  Justin Fan  <justin_fan@apple.com>
+
+        WebGL 2 Conformance: primitive restart and draw_primitive_restart WebGL2 sample
+        https://bugs.webkit.org/show_bug.cgi?id=189625
+        <rdar://problem/42882620>
+
+        Reviewed by Dean Jackson.
+
+        Implement support for Primitive Restart Fixed Index as expected 
+        by the WebGL 2 specifications. 
+
+        * TestExpectations: Skip some flaky tests between different Mac machines under 2.0.0. 
+        * webgl/webgl2-primitive-restart.html: Canary ref test to be run as part of LayoutTests suite.
+        * webgl/webgl2-primitive-restart-expected.html:
+
 2018-09-25  Chris Dumez  <cdumez@apple.com>
 
         Unreviewed, rolling out r236420 and r236458.
index 857ad70..f29ecb6 100644 (file)
@@ -965,13 +965,15 @@ webkit.org/b/139639 [ Debug ] cssom/non-subpixel-scroll-top-left-values.html [ S
 
 webkit.org/b/139640 [ Debug ] webgl/1.0.2/conformance/glsl/misc/shader-uniform-packing-restrictions.html [ Slow ]
 
-webkit.org/b/189641 webgl/2.0.0/conformance/buffers/buffer-uninitialized.html [ Failure ]
-webkit.org/b/189641 webgl/2.0.0/conformance/extensions/webgl-draw-buffers.html [ Failure Slow ]
-webkit.org/b/189641 webgl/2.0.0/conformance/renderbuffers/feedback-loop.html [ Failure ] 
-webkit.org/b/189641 webgl/2.0.0/conformance/rendering/clipping-wide-points.html [ Failure ] 
-webkit.org/b/189641 webgl/2.0.0/conformance/textures/misc/copy-tex-image-2d-formats.html [ Failure ] 
-webkit.org/b/189641 webgl/2.0.0/conformance2/state/gl-object-get-calls.html [ Failure Slow ]
-webkit.org/b/189641 webgl/2.0.0/conformance2/textures/misc/tex-3d-size-limit.html [ Failure ]
+# These tests are generating inconsistent results between my machine (AMD) and test bots (INTEL)
+webkit.org/b/189641 webgl/2.0.0/conformance/buffers/buffer-uninitialized.html [ Skip ]
+webkit.org/b/189641 webgl/2.0.0/conformance/extensions/webgl-draw-buffers.html [ Skip ]
+webkit.org/b/189641 webgl/2.0.0/conformance/renderbuffers/feedback-loop.html [ Skip ] 
+webkit.org/b/189641 webgl/2.0.0/conformance/rendering/clipping-wide-points.html [ Skip ] 
+webkit.org/b/189641 webgl/2.0.0/conformance/textures/misc/copy-tex-image-2d-formats.html [ Skip ] 
+webkit.org/b/189641 webgl/2.0.0/conformance2/state/gl-object-get-calls.html [ Skip ]
+webkit.org/b/189641 webgl/2.0.0/conformance2/textures/misc/tex-3d-size-limit.html [ Skip ]
+
 webkit.org/b/189641 webgl/2.0.0/conformance2/rendering/blitframebuffer-filter-outofbounds.html [ Slow ]
 
 [ Debug ] fast/workers/worker-cloneport.html [ Slow ]
diff --git a/LayoutTests/webgl/webgl2-primitive-restart-expected.html b/LayoutTests/webgl/webgl2-primitive-restart-expected.html
new file mode 100644 (file)
index 0000000..d984174
--- /dev/null
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <title>WebGL 2 Samples - draw_primitive_restart</title>
+    <meta charset="utf-8">
+    <link rel="stylesheet" href="2.0.0/resources/webgl_test_files/resources/js-test-style.css">
+    <script src="2.0.0/resources/webgl_test_files/js/js-test-pre.js"></script>
+    <script src="2.0.0/resources/webgl_test_files/js/webgl-test-utils.js"></script>
+</head>
+
+<body>
+    <div id="info">WebGL 2 Samples - draw_primitive_restart</div>
+    <div id="console"></div>
+
+    <script id="vs" type="x-shader/x-vertex">#version 300 es
+        precision highp float;
+        precision highp int;
+
+        layout(location = 0) in vec2 pos;
+
+        void main()
+        {
+            gl_Position = vec4(pos, 0.0, 1.0);
+        }
+    </script>
+
+    <script id="fs" type="x-shader/x-fragment">#version 300 es
+        precision highp float;
+        precision highp int;
+
+        out vec4 color;
+
+        void main()
+        {
+            color = vec4(1.0, 0.5, 0.0, 1.0);
+        }
+    </script>
+
+    <script>
+    (function () {
+        'use strict';
+        var wtu = WebGLTestUtils;
+
+        // -- Init Canvas
+        var canvas = document.createElement('canvas');
+        canvas.width = 200;
+        canvas.height = canvas.width;
+        document.body.appendChild(canvas);
+
+        // -- Init WebGL Context
+        var gl = canvas.getContext('webgl2', { antialias: false });
+        var isWebGL2 = !!gl;
+        if (!isWebGL2) {
+            testFailed("WebGL 2 context does not exist");
+            return;
+        }
+
+        testPassed("WebGL 2 context exists");
+
+        // -- Init Program
+        var program = wtu.setupProgram(gl, ["vs", "fs"]);
+        gl.useProgram(program);
+
+        // -- Init Buffer
+        var vertices = new Float32Array([
+            -1.0, -1.0,
+            -1.0,  1.0,
+             1.0, -1.0,
+             1.0,  1.0
+        ]);
+
+        var vertexPosBuffer = gl.createBuffer();
+        gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
+        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+        gl.bindBuffer(gl.ARRAY_BUFFER, null);
+
+        var num_vertices = 6;
+        var indices = new Uint16Array([
+            0, 1, 2, 2, 3, 1
+        ]);
+
+        var vertexElementBuffer = gl.createBuffer();
+        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexElementBuffer);
+        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
+        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+
+        // -- Init Vertex Array
+        var vertexArray = gl.createVertexArray();
+        gl.bindVertexArray(vertexArray);
+
+        var vertexPosLocation = 0;
+        gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
+        gl.enableVertexAttribArray(vertexPosLocation);
+        gl.vertexAttribPointer(vertexPosLocation, 2, gl.FLOAT, false, 0, 0);
+        gl.bindBuffer(gl.ARRAY_BUFFER, null);
+        
+        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexElementBuffer);
+
+        gl.bindVertexArray(null);
+
+        // -- Render
+        gl.clearColor(0.0, 0.0, 0.0, 1.0);
+        gl.clear(gl.COLOR_BUFFER_BIT);
+
+        gl.bindVertexArray(vertexArray);
+
+        gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+
+        // -- Delete WebGL resources
+        gl.deleteBuffer(vertexPosBuffer);
+        gl.deleteBuffer(vertexElementBuffer);
+        gl.deleteProgram(program);
+        gl.deleteVertexArray(vertexArray);
+    })();
+    </script>
+</body>
+</html>
diff --git a/LayoutTests/webgl/webgl2-primitive-restart.html b/LayoutTests/webgl/webgl2-primitive-restart.html
new file mode 100644 (file)
index 0000000..b6ed821
--- /dev/null
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <title>WebGL 2 Samples - draw_primitive_restart</title>
+    <meta charset="utf-8">
+    <link rel="stylesheet" href="2.0.0/resources/webgl_test_files/resources/js-test-style.css">
+    <script src="2.0.0/resources/webgl_test_files/js/js-test-pre.js"></script>
+    <script src="2.0.0/resources/webgl_test_files/js/webgl-test-utils.js"></script>
+</head>
+
+<body>
+    <div id="info">WebGL 2 Samples - draw_primitive_restart</div>
+    <div id="console"></div>
+
+    <script id="vs" type="x-shader/x-vertex">#version 300 es
+        precision highp float;
+        precision highp int;
+
+        layout(location = 0) in vec2 pos;
+
+        void main()
+        {
+            gl_Position = vec4(pos, 0.0, 1.0);
+        }
+    </script>
+
+    <script id="fs" type="x-shader/x-fragment">#version 300 es
+        precision highp float;
+        precision highp int;
+
+        out vec4 color;
+
+        void main()
+        {
+            color = vec4(1.0, 0.5, 0.0, 1.0);
+        }
+    </script>
+
+    <script>
+    (function () {
+        'use strict';
+        var wtu = WebGLTestUtils;
+
+        // -- Init Canvas
+        var canvas = document.createElement('canvas');
+        canvas.width = 200;
+        canvas.height = canvas.width;
+        document.body.appendChild(canvas);
+
+        // -- Init WebGL Context
+        var gl = canvas.getContext('webgl2', { antialias: false });
+        var isWebGL2 = !!gl;
+        if (!isWebGL2) {
+            testFailed("WebGL 2 context does not exist");
+            return;
+        }
+
+        testPassed("WebGL 2 context exists");
+
+        // -- Init Program
+        var program = wtu.setupProgram(gl, ["vs", "fs"]);
+        gl.useProgram(program);
+
+        // -- Init Buffer
+        var vertices = new Float32Array([
+            -1.0, -1.0,
+            -1.0,  1.0,
+             1.0, -1.0,
+             1.0,  1.0
+        ]);
+
+        var vertexPosBuffer = gl.createBuffer();
+        gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
+        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+        gl.bindBuffer(gl.ARRAY_BUFFER, null);
+        
+        // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.18
+        // WebGL 2.0 behaves as though PRIMITIVE_RESTART_FIXED_INDEX were always enabled. 
+        var MAX_UNSIGNED_SHORT = 65535;
+        var num_vertices = 7;
+        var indices = new Uint16Array([
+            0, 1, 2, MAX_UNSIGNED_SHORT, 2, 3, 1
+        ]);
+
+        var vertexElementBuffer = gl.createBuffer();
+        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexElementBuffer);
+        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
+        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+
+        // -- Init Vertex Array
+        var vertexArray = gl.createVertexArray();
+        gl.bindVertexArray(vertexArray);
+
+        var vertexPosLocation = 0;
+        gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
+        gl.enableVertexAttribArray(vertexPosLocation);
+        gl.vertexAttribPointer(vertexPosLocation, 2, gl.FLOAT, false, 0, 0);
+        gl.bindBuffer(gl.ARRAY_BUFFER, null);
+        
+        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexElementBuffer);
+
+        gl.bindVertexArray(null);
+
+        // -- Render
+        gl.clearColor(0.0, 0.0, 0.0, 1.0);
+        gl.clear(gl.COLOR_BUFFER_BIT);
+
+        gl.bindVertexArray(vertexArray);
+
+        gl.drawElements(gl.TRIANGLE_STRIP, 7, gl.UNSIGNED_SHORT, 0);
+
+        // -- Delete WebGL resources
+        gl.deleteBuffer(vertexPosBuffer);
+        gl.deleteBuffer(vertexElementBuffer);
+        gl.deleteProgram(program);
+        gl.deleteVertexArray(vertexArray);
+    })();
+    </script>
+</body>
+</html>
index 6607ebb..57c7553 100644 (file)
@@ -1,3 +1,28 @@
+2018-09-25  Justin Fan  <justin_fan@apple.com>
+
+        WebGL 2 Conformance: primitive restart and draw_primitive_restart WebGL2 sample
+        https://bugs.webkit.org/show_bug.cgi?id=189625
+        <rdar://problem/42882620>
+
+        Reviewed by Dean Jackson.
+
+        Ref test: webgl/webgl2-primitive-restart.html.
+
+        Implement support for Primitive Restart Fixed Index as expected 
+        by the WebGL 2 specifications. 
+
+        * html/canvas/WebGL2RenderingContext.cpp:
+        (WebCore::WebGL2RenderingContext::validateIndexArrayConservative):
+        * html/canvas/WebGLRenderingContextBase.h:
+        (WebCore::WebGLRenderingContextBase::getLastIndex): Template that must be defined in header.
+        * html/canvas/WebGLRenderingContextBase.cpp:
+        (WebCore::WebGLRenderingContextBase::validateIndexArrayPrecise):
+        * platform/graphics/GraphicsContext3D.h:
+        * platform/graphics/cocoa/GraphicsContext3DCocoa.mm:
+        (WebCore::GraphicsContext3D::GraphicsContext3D):
+        * platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp:
+        (WebCore::GraphicsContext3D::primitiveRestartIndex):
+
 2018-09-25  John Wilander  <wilander@apple.com>
 
         Change from HAVE(CFNETWORK_STORAGE_PARTITIONING) to ENABLE(RESOURCE_LOAD_STATISTICS)
index 3523477..35475fc 100644 (file)
@@ -2020,26 +2020,15 @@ bool WebGL2RenderingContext::validateIndexArrayConservative(GC3Denum type, unsig
     if (!maxIndex) {
         // Compute the maximum index in the entire buffer for the given type of index.
         switch (type) {
-        case GraphicsContext3D::UNSIGNED_BYTE: {
-            const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
-            for (GC3Dsizeiptr i = 0; i < numElements; i++)
-                maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast<unsigned>(p[i])) : static_cast<unsigned>(p[i]);
+        case GraphicsContext3D::UNSIGNED_BYTE:
+            maxIndex = getMaxIndex<GC3Dubyte>(buffer, 0, numElements);
             break;
-        }
-        case GraphicsContext3D::UNSIGNED_SHORT: {
-            numElements /= sizeof(GC3Dushort);
-            const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
-            for (GC3Dsizeiptr i = 0; i < numElements; i++)
-                maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast<unsigned>(p[i])) : static_cast<unsigned>(p[i]);
+        case GraphicsContext3D::UNSIGNED_SHORT:
+            maxIndex = getMaxIndex<GC3Dushort>(buffer, 0, numElements / sizeof(GC3Dushort));
             break;
-        }
-        case GraphicsContext3D::UNSIGNED_INT: {
-            numElements /= sizeof(GC3Duint);
-            const GC3Duint* p = static_cast<const GC3Duint*>(buffer->data());
-            for (GC3Dsizeiptr i = 0; i < numElements; i++)
-                maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast<unsigned>(p[i])) : static_cast<unsigned>(p[i]);
+        case GraphicsContext3D::UNSIGNED_INT:
+            maxIndex = getMaxIndex<GC3Duint>(buffer, 0, numElements / sizeof(GC3Duint));
             break;
-        }
         default:
             return false;
         }
index 882858c..8574fce 100644 (file)
@@ -2007,7 +2007,7 @@ bool WebGLRenderingContextBase::validateElementArraySize(GC3Dsizei count, GC3Den
 bool WebGLRenderingContextBase::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, unsigned& numElementsRequired)
 {
     ASSERT(count >= 0 && offset >= 0);
-    unsigned lastIndex = 0;
+    unsigned maxIndex = 0;
     
     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
 
@@ -2019,41 +2019,24 @@ bool WebGLRenderingContextBase::validateIndexArrayPrecise(GC3Dsizei count, GC3De
         return true;
     }
 
-    if (!elementArrayBuffer->elementArrayBuffer())
+    auto buffer = elementArrayBuffer->elementArrayBuffer();
+    if (!buffer)
         return false;
 
-    unsigned long uoffset = offset;
-    unsigned long n = count;
-
-    if (type == GraphicsContext3D::UNSIGNED_INT) {
-        // Make uoffset an element offset.
-        uoffset /= sizeof(GC3Duint);
-        const GC3Duint* p = static_cast<const GC3Duint*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
-        while (n-- > 0) {
-            if (*p > lastIndex)
-                lastIndex = *p;
-            ++p;
-        }
-    } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
-        // Make uoffset an element offset.
-        uoffset /= sizeof(GC3Dushort);
-        const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
-        while (n-- > 0) {
-            if (*p > lastIndex)
-                lastIndex = *p;
-            ++p;
-        }
-    } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
-        const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
-        while (n-- > 0) {
-            if (*p > lastIndex)
-                lastIndex = *p;
-            ++p;
-        }
+    switch (type) {
+    case GraphicsContext3D::UNSIGNED_INT:
+        maxIndex = getMaxIndex<GC3Duint>(buffer, offset, count);
+        break;
+    case GraphicsContext3D::UNSIGNED_SHORT:
+        maxIndex = getMaxIndex<GC3Dushort>(buffer, offset, count);
+        break;
+    case GraphicsContext3D::UNSIGNED_BYTE:
+        maxIndex = getMaxIndex<GC3Dubyte>(buffer, offset, count);
+        break;
     }
 
-    // Then set the last index in the index array and make sure it is valid.
-    auto checkedNumElementsRequired = checkedAddAndMultiply<unsigned>(lastIndex, 1, 1);
+    // Then set the maxiumum index in the index array and make sure it is valid.
+    auto checkedNumElementsRequired = checkedAddAndMultiply<unsigned>(maxIndex, 1, 1);
     if (!checkedNumElementsRequired)
         return false;
     numElementsRequired = checkedNumElementsRequired.value();
@@ -2305,6 +2288,22 @@ void WebGLRenderingContextBase::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsiz
     markContextChangedAndNotifyCanvasObserver();
 }
 
+#if USE(OPENGL) && ENABLE(WEBGL2)
+static GC3Duint getRestartIndex(GC3Denum type)
+{
+    switch (type) {
+    case GraphicsContext3D::UNSIGNED_BYTE:
+        return std::numeric_limits<GC3Dubyte>::max();
+    case GraphicsContext3D::UNSIGNED_SHORT:
+        return std::numeric_limits<GC3Dushort>::max();
+    case GraphicsContext3D::UNSIGNED_INT:
+        return std::numeric_limits<GC3Duint>::max();
+    }
+
+    return 0;
+}
+#endif
+
 void WebGLRenderingContextBase::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset)
 {
     unsigned numElements = 0;
@@ -2333,6 +2332,11 @@ void WebGLRenderingContextBase::drawElements(GC3Denum mode, GC3Dsizei count, GC3
     if (!isGLES2NPOTStrict())
         usesFallbackTexture = checkTextureCompleteness("drawElements", true);
 
+#if USE(OPENGL) && ENABLE(WEBGL2)
+    if (isWebGL2())
+        m_context->primitiveRestartIndex(getRestartIndex(type));
+#endif
+
     {
         InspectorScopedShaderProgramHighlight scopedHighlight(*this, m_currentProgram.get());
 
@@ -6439,6 +6443,11 @@ void WebGLRenderingContextBase::drawElementsInstanced(GC3Denum mode, GC3Dsizei c
     if (!isGLES2NPOTStrict())
         checkTextureCompleteness("drawElementsInstanced", true);
 
+#if USE(OPENGL) && ENABLE(WEBGL2)
+    if (isWebGL2())
+        m_context->primitiveRestartIndex(getRestartIndex(type));
+#endif
+
     m_context->drawElementsInstanced(mode, count, type, static_cast<GC3Dintptr>(offset), primcount);
 
     if (!isGLES2Compliant() && vertexAttrib0Simulated)
index 08bc4fc..96cc17b 100644 (file)
@@ -43,6 +43,7 @@
 #include "WebGLTexture.h"
 #include "WebGLVertexArrayObjectOES.h"
 #include <JavaScriptCore/ConsoleTypes.h>
+#include <limits>
 #include <memory>
 
 #if ENABLE(WEBGL2)
@@ -834,6 +835,7 @@ protected:
     OffscreenCanvas* offscreenCanvas();
 
     template <typename T> inline std::optional<T> checkedAddAndMultiply(T value, T add, T multiply);
+    template <typename T> unsigned getMaxIndex(const RefPtr<JSC::ArrayBuffer> elementArrayBuffer, GC3Dintptr uoffset, GC3Dsizei n);
 
 private:
     bool validateArrayBufferType(const char* functionName, GC3Denum type, std::optional<JSC::TypedArrayType>);
@@ -858,6 +860,30 @@ inline std::optional<T> WebGLRenderingContextBase::checkedAddAndMultiply(T value
     return checkedResult.unsafeGet();
 }
 
+template<typename T>
+inline unsigned WebGLRenderingContextBase::getMaxIndex(const RefPtr<JSC::ArrayBuffer> elementArrayBuffer, GC3Dintptr uoffset, GC3Dsizei n)
+{
+    unsigned maxIndex = 0;
+    T restartIndex = 0;
+
+#if ENABLE(WEBGL2)
+    // WebGL 2 spec enforces that GL_PRIMITIVE_RESTART_FIXED_INDEX is always enabled, so ignore the restart index.
+    if (isWebGL2())
+        restartIndex = std::numeric_limits<T>::max();
+#endif
+
+    // Make uoffset an element offset.
+    uoffset /= sizeof(T);
+    const T* p = static_cast<const T*>(elementArrayBuffer->data()) + uoffset;
+    while (n-- > 0) {
+        if (*p != restartIndex && *p > maxIndex)
+            maxIndex = *p;
+        ++p;
+    }
+
+    return maxIndex;
+}
+
 } // namespace WebCore
 
 SPECIALIZE_TYPE_TRAITS_CANVASRENDERINGCONTEXT(WebCore::WebGLRenderingContextBase, isWebGL())
index c9ea1df..f45ed3b 100644 (file)
@@ -718,7 +718,9 @@ public:
         TEXTURE_IMMUTABLE_FORMAT = 0x912F,
         MAX_ELEMENT_INDEX = 0x8D6B,
         NUM_SAMPLE_COUNTS = 0x9380,
-        TEXTURE_IMMUTABLE_LEVELS = 0x82DF, 
+        TEXTURE_IMMUTABLE_LEVELS = 0x82DF,
+        PRIMITIVE_RESTART_FIXED_INDEX = 0x8D69,
+        PRIMITIVE_RESTART = 0x8F9D,
 
         // OpenGL ES 3 constants
         MAP_READ_BIT = 0x0001
@@ -1151,6 +1153,10 @@ public:
     RefPtr<ImageData> paintRenderingResultsToImageData();
     bool paintCompositedResultsToCanvas(ImageBuffer*);
 
+#if USE(OPENGL) && ENABLE(WEBGL2)
+    void primitiveRestartIndex(GC3Duint);
+#endif
+
 #if PLATFORM(COCOA)
     bool texImageIOSurface2D(GC3Denum target, GC3Denum internalFormat, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, IOSurfaceRef, GC3Duint plane);
 
index bad445d..caacc4a 100644 (file)
@@ -264,6 +264,9 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3DAttributes attrs, HostWind
     else
         m_contextObj = [[EAGLContext alloc] initWithAPI:api sharegroup:sharedContext->m_contextObj.sharegroup];
     makeContextCurrent();
+
+    if (m_attrs.isWebGL2)
+        ::glEnable(GraphicsContext3D::PRIMITIVE_RESTART_FIXED_INDEX);
 #else
     Vector<CGLPixelFormatAttribute> attribs;
     CGLPixelFormatObj pixelFormatObj = 0;
@@ -347,6 +350,10 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3DAttributes attrs, HostWind
     // Set the current context to the one given to us.
     CGLSetCurrentContext(m_contextObj);
 
+    // WebGL 2 expects ES 3-only PRIMITIVE_RESTART_FIXED_INDEX to be enabled; we must emulate this on non-ES 3 systems.
+    if (m_isForWebGL2)
+        ::glEnable(GraphicsContext3D::PRIMITIVE_RESTART);
+
 #endif // !USE(OPENGL_ES)
     
     validateAttributes();
index 6c9c3f7..f0cd159 100644 (file)
@@ -2070,6 +2070,14 @@ void GraphicsContext3D::vertexAttribDivisor(GC3Duint index, GC3Duint divisor)
     getExtensions().vertexAttribDivisor(index, divisor);
 }
 
+#if USE(OPENGL) && ENABLE(WEBGL2)
+void GraphicsContext3D::primitiveRestartIndex(GC3Duint index)
+{
+    makeContextCurrent();
+    ::glPrimitiveRestartIndex(index);
+}
+#endif
+
 }
 
 #endif // ENABLE(GRAPHICS_CONTEXT_3D)