Title: [208313] trunk
Revision
208313
Author
mmaxfi...@apple.com
Date
2016-11-02 17:05:12 -0700 (Wed, 02 Nov 2016)

Log Message

[iOS] [WebGL] Multisample resolve step may operate on stale data
https://bugs.webkit.org/show_bug.cgi?id=164347

Reviewed by Dean Jackson.

Source/WebCore:

When antialiasing is enabled, WebKit internally creates a multisampled FBO
and uses that as the target of all the drawing commands. Then, just before
we actually put the image on the glass, we perform a “resolve” step which
averages all the samples to create the final image. However, it appears
that this resolve step only waits for commands to complete which were
already submitted to the hardware. OpenGL is allowed (indeed, expected) to
batch up drawing commands in main memory so it can submit them to the
hardware in fewer batches, but this means that the hardware may not know
about all the commands that the application submitted. Because of this,
the data the resolve step saw is the result of only some of the previous
draw calls - not all of them.

This doesn’t occur on macOS because we have a different code path there
for performing the resolve step. On iOS 9 and below, WebKit didn’t
implement multisampling in WebGL at all, which explains why this only
occurs on iOS 10.

Luckily, the OpenGL command glFlush() is exactly designed to submit any
pending commands to the hardware.

Test: fast/canvas/webgl/multisample-resolve-consistency.html

* platform/graphics/opengl/GraphicsContext3DOpenGL.cpp:
(WebCore::GraphicsContext3D::resolveMultisamplingIfNecessary):

LayoutTests:

Issue many draw calls into a multisampled context, and then use glReadPixels()
to make sure that all the commands completed.

* fast/canvas/webgl/multisample-resolve-consistency-expected.txt: Added.
* fast/canvas/webgl/multisample-resolve-consistency.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (208312 => 208313)


--- trunk/LayoutTests/ChangeLog	2016-11-02 23:30:16 UTC (rev 208312)
+++ trunk/LayoutTests/ChangeLog	2016-11-03 00:05:12 UTC (rev 208313)
@@ -1,3 +1,16 @@
+2016-11-02  Myles C. Maxfield  <mmaxfi...@apple.com>
+
+        [iOS] [WebGL] Multisample resolve step may operate on stale data
+        https://bugs.webkit.org/show_bug.cgi?id=164347
+
+        Reviewed by Dean Jackson.
+
+        Issue many draw calls into a multisampled context, and then use glReadPixels()
+        to make sure that all the commands completed.
+
+        * fast/canvas/webgl/multisample-resolve-consistency-expected.txt: Added.
+        * fast/canvas/webgl/multisample-resolve-consistency.html: Added.
+
 2016-11-01  Sam Weinig  <s...@webkit.org>
 
         [WebIDL] Move interfaces and typed arrays over to JSDOMConvert

Added: trunk/LayoutTests/fast/canvas/webgl/multisample-resolve-consistency-expected.txt (0 => 208313)


--- trunk/LayoutTests/fast/canvas/webgl/multisample-resolve-consistency-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/canvas/webgl/multisample-resolve-consistency-expected.txt	2016-11-03 00:05:12 UTC (rev 208313)
@@ -0,0 +1,8 @@
+ Checks that multisample resolve has no timing issues
+PASS gl.getContextAttributes().antialias is true
+PASS gl.getError() is gl.NO_ERROR
+PASS gl.getError() is gl.NO_ERROR
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/canvas/webgl/multisample-resolve-consistency.html (0 => 208313)


--- trunk/LayoutTests/fast/canvas/webgl/multisample-resolve-consistency.html	                        (rev 0)
+++ trunk/LayoutTests/fast/canvas/webgl/multisample-resolve-consistency.html	2016-11-03 00:05:12 UTC (rev 208313)
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name="viewport" content="width=device-width">
+<script src=""
+<script src="" </script>
+</head>
+<body>
+<canvas id="example" width="400" height="400" style="width: 400px; height: 400px;"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script id="vshader" type="x-shader/x-vertex">
+#ifdef GL_ES
+precision highp float;
+#endif
+attribute vec2 vPosition;
+uniform mat3 world;
+void main()
+{
+    gl_Position = vec4((world * vec3(vPosition, 1)).xy, 0, 1);
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+#ifdef GL_ES
+precision highp float;
+#endif
+void main()
+{
+    gl_FragColor = vec4(0, 1, 0, 1);
+}
+</script>
+
+<script>
+function init()
+{
+    if (window.initNonKhronosFramework)
+        window.initNonKhronosFramework(false);
+
+    debug("Checks that multisample resolve has no timing issues");
+
+    var canvas = document.getElementById("example");
+    gl = initWebGL("example", "vshader", "fshader", [ "vPosition", "index" ], [ 1, 1, 1, 1 ], 1, { antialias: true });
+    shouldBeTrue("gl.getContextAttributes().antialias");
+
+    loc = gl.getUniformLocation(gl.program, "world");
+
+    gl.disable(gl.DEPTH_TEST);
+    gl.disable(gl.BLEND);
+
+    var coordinates = new Float32Array([ 0,1, 1,1, 0,0, 0,0, 1,1, 1,0]);
+
+    vertexObject = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+    gl.bufferData(gl.ARRAY_BUFFER, coordinates, gl.STATIC_DRAW);
+    shouldBe("gl.getError()", "gl.NO_ERROR");
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+    shouldBe("gl.getError()", "gl.NO_ERROR");
+}
+
+function drawQuad(x, y) {
+    gl.uniformMatrix3fv(loc, false, new Float32Array([2 * quadSizeInPixels / canvas.width, 0, 0, 0, 2 * quadSizeInPixels / canvas.height, 0, quadSizeInPixels * x * 2 / canvas.width - 1, quadSizeInPixels * y * 2 / canvas.height - 1, 1]));
+    gl.drawArrays(gl.TRIANGLES, 0, 6);
+	//shouldBe("gl.getError()", "gl.NO_ERROR");
+}
+
+var loc;
+var vertexObject;
+var canvas = document.getElementById("example");
+var data = "" Uint8Array(canvas.width * canvas.height * 4);
+var width;
+var height;
+
+init();
+
+var quadSizeInPixels = 4;
+
+window.jsTestIsAsync = true;
+
+var counter = 0;
+function fillCanvas() {
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+    for (var i = 0; i < canvas.width / quadSizeInPixels; ++i) {
+    	for (var j = 0; j < canvas.height / quadSizeInPixels; ++j) {
+		    drawQuad(i, j);
+    	}
+    }
+    gl.readPixels(0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, data);
+    counter = counter + 1;
+    for (width = 0; width < 1; ++width) {
+    	for (height = 0; height < 1; ++height) {
+    		// Reduce test spam
+    		if (data[4 * (height * canvas.height + width) + 0] != 0)
+	    		shouldBe("0", "data[4 * (height * canvas.height + width) + 0]");
+    		if (data[4 * (height * canvas.height + width) + 1] != 255)
+    			shouldBe("255", "data[4 * (height * canvas.height + width) + 1]");
+    		if (data[4 * (height * canvas.height + width) + 2] != 0)
+    			shouldBe("0", "data[4 * (height * canvas.height + width) + 2]");
+    		if (data[4 * (height * canvas.height + width) + 3] != 255)
+	    		shouldBe("255", "data[4 * (height * canvas.height + width) + 3]");
+    	}
+    }
+    if (counter < 20)
+		window.requestAnimationFrame(fillCanvas);
+	else {
+		finishJSTest();
+    	gl.deleteBuffer(vertexObject);
+	}
+}
+window.requestAnimationFrame(fillCanvas);
+
+
+</script>
+<script src=""
+</body>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (208312 => 208313)


--- trunk/Source/WebCore/ChangeLog	2016-11-02 23:30:16 UTC (rev 208312)
+++ trunk/Source/WebCore/ChangeLog	2016-11-03 00:05:12 UTC (rev 208313)
@@ -1,3 +1,35 @@
+2016-11-02  Myles C. Maxfield  <mmaxfi...@apple.com>
+
+        [iOS] [WebGL] Multisample resolve step may operate on stale data
+        https://bugs.webkit.org/show_bug.cgi?id=164347
+
+        Reviewed by Dean Jackson.
+
+        When antialiasing is enabled, WebKit internally creates a multisampled FBO
+        and uses that as the target of all the drawing commands. Then, just before
+        we actually put the image on the glass, we perform a “resolve” step which
+        averages all the samples to create the final image. However, it appears
+        that this resolve step only waits for commands to complete which were
+        already submitted to the hardware. OpenGL is allowed (indeed, expected) to
+        batch up drawing commands in main memory so it can submit them to the
+        hardware in fewer batches, but this means that the hardware may not know
+        about all the commands that the application submitted. Because of this,
+        the data the resolve step saw is the result of only some of the previous
+        draw calls - not all of them.
+
+        This doesn’t occur on macOS because we have a different code path there
+        for performing the resolve step. On iOS 9 and below, WebKit didn’t
+        implement multisampling in WebGL at all, which explains why this only
+        occurs on iOS 10. 
+
+        Luckily, the OpenGL command glFlush() is exactly designed to submit any
+        pending commands to the hardware.
+
+        Test: fast/canvas/webgl/multisample-resolve-consistency.html
+
+        * platform/graphics/opengl/GraphicsContext3DOpenGL.cpp:
+        (WebCore::GraphicsContext3D::resolveMultisamplingIfNecessary):
+
 2016-11-02  Brady Eidson  <beid...@apple.com>
 
         Give IDBKey(Data) a WTF::Variant overhaul.

Modified: trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp (208312 => 208313)


--- trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp	2016-11-02 23:30:16 UTC (rev 208312)
+++ trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp	2016-11-03 00:05:12 UTC (rev 208313)
@@ -234,6 +234,7 @@
     ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo);
 #if PLATFORM(IOS)
     UNUSED_PARAM(rect);
+    ::glFlush();
     ::glResolveMultisampleFramebufferAPPLE();
     const GLenum discards[] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
     ::glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, discards);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to