Title: [221932] trunk
Revision
221932
Author
d...@apple.com
Date
2017-09-12 12:28:29 -0700 (Tue, 12 Sep 2017)

Log Message

[WebGL] accelerated texImage2D for video doesn't respect flipY
https://bugs.webkit.org/show_bug.cgi?id=176491
<rdar://problem/33833511>

Reviewed by Jer Noble.

(Take 2 - this was rolled out due to a test failure, but the following
commit will fix that)

Source/WebCore:

Previously, if UNPACK_FLIP_Y_WEBGL was set to true, we'd either fall
back to software or fail to upload texture data. Fix this by intercepting
the texImage2D call, checking the orientation of the video, and running
a small shader program to flip it if necessary.

While there, implement UNPACK_PREMULTIPLY_ALPHA_WEBGL as well, although
none of our media decoders support video with alpha, so unfortunately
this will have no visible change.

Tests: fast/canvas/webgl/texImage2D-video-flipY-false.html
       fast/canvas/webgl/texImage2D-video-flipY-true.html

* platform/cocoa/CoreVideoSoftLink.cpp: Add link to CVOpenGL(ES)TextureGetCleanTexCoords,
which is used to check the orientation of the source video.
* platform/cocoa/CoreVideoSoftLink.h:

* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::copyVideoTextureToPlatformTexture): We can
now handle flipped or premultiplied requests.
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::copyVideoTextureToPlatformTexture): Ditto.

* platform/graphics/cv/VideoTextureCopierCV.cpp:
(WebCore::VideoTextureCopierCV::VideoTextureCopierCV): Rename readFramebuffer to
simply framebuffer.
(WebCore::VideoTextureCopierCV::~VideoTextureCopierCV): Delete the program and buffer
if they were created.
(WebCore::VideoTextureCopierCV::initializeContextObjects): Sets up the shader program
and the vertex buffer for drawing. Also records the location of the uniforms.
(WebCore::VideoTextureCopierCV::copyVideoTextureToPlatformTexture): Create a new
framebuffer object, and render the video texture into that framebuffer using a
shader that can flip the coordinates.
(WebCore::VideoTextureCopierCV::GC3DStateSaver::GC3DStateSaver): Helper to restore
the state of the user's GraphicsContext3D while we're intercepting calls.
(WebCore::VideoTextureCopierCV::GC3DStateSaver::~GC3DStateSaver):
* platform/graphics/cv/VideoTextureCopierCV.h:

* platform/graphics/GraphicsContext3D.h: Add two new entry points, for direct shader
compilation and attribute access. This avoids going through ANGLE.
* platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp:
(WebCore::GraphicsContext3D::compileShader):
(WebCore::GraphicsContext3D::compileShaderDirect):
(WebCore::GraphicsContext3D::getAttribLocationDirect):

LayoutTests:

Test that exercises UNPACK_FLIP_Y_WEBGL for video on the accelerated
path.

* fast/canvas/webgl/resources/orientation-flipped.mp4: Added.
* fast/canvas/webgl/resources/orientation-normal.mp4: Added.
* fast/canvas/webgl/texImage2D-video-flipY-false-expected.txt: Added.
* fast/canvas/webgl/texImage2D-video-flipY-false.html: Added.
* fast/canvas/webgl/texImage2D-video-flipY-true-expected.txt: Added.
* fast/canvas/webgl/texImage2D-video-flipY-true.html: Added.
* platform/ios/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (221931 => 221932)


--- trunk/LayoutTests/ChangeLog	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/LayoutTests/ChangeLog	2017-09-12 19:28:29 UTC (rev 221932)
@@ -1,3 +1,25 @@
+2017-09-12  Dean Jackson  <d...@apple.com>
+
+        [WebGL] accelerated texImage2D for video doesn't respect flipY
+        https://bugs.webkit.org/show_bug.cgi?id=176491
+        <rdar://problem/33833511>
+
+        Reviewed by Jer Noble.
+
+        (Take 2 - this was rolled out due to a test failure, but the following
+        commit will fix that)
+
+        Test that exercises UNPACK_FLIP_Y_WEBGL for video on the accelerated
+        path.
+
+        * fast/canvas/webgl/resources/orientation-flipped.mp4: Added.
+        * fast/canvas/webgl/resources/orientation-normal.mp4: Added.
+        * fast/canvas/webgl/texImage2D-video-flipY-false-expected.txt: Added.
+        * fast/canvas/webgl/texImage2D-video-flipY-false.html: Added.
+        * fast/canvas/webgl/texImage2D-video-flipY-true-expected.txt: Added.
+        * fast/canvas/webgl/texImage2D-video-flipY-true.html: Added.
+        * platform/ios/TestExpectations:
+
 2017-09-12  Carlos Garcia Campos  <cgar...@igalia.com>
 
         Remove duplicated test results from LayoutTest platform directories

Added: trunk/LayoutTests/fast/canvas/webgl/resources/orientation-flipped.mp4


(Binary files differ)
Index: trunk/LayoutTests/fast/canvas/webgl/resources/orientation-flipped.mp4 =================================================================== --- trunk/LayoutTests/fast/canvas/webgl/resources/orientation-flipped.mp4 2017-09-12 19:19:45 UTC (rev 221931) +++ trunk/LayoutTests/fast/canvas/webgl/resources/orientation-flipped.mp4 2017-09-12 19:28:29 UTC (rev 221932) Property changes on: trunk/LayoutTests/fast/canvas/webgl/resources/orientation-flipped.mp4 ___________________________________________________________________

Added: svn:mime-type

+application/octet-stream \ No newline at end of property

Added: trunk/LayoutTests/fast/canvas/webgl/resources/orientation-normal.mp4


(Binary files differ)
Index: trunk/LayoutTests/fast/canvas/webgl/resources/orientation-normal.mp4 =================================================================== --- trunk/LayoutTests/fast/canvas/webgl/resources/orientation-normal.mp4 2017-09-12 19:19:45 UTC (rev 221931) +++ trunk/LayoutTests/fast/canvas/webgl/resources/orientation-normal.mp4 2017-09-12 19:28:29 UTC (rev 221932) Property changes on: trunk/LayoutTests/fast/canvas/webgl/resources/orientation-normal.mp4 ___________________________________________________________________

Added: svn:mime-type

+application/octet-stream \ No newline at end of property

Added: trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-false-expected.txt (0 => 221932)


--- trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-false-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-false-expected.txt	2017-09-12 19:28:29 UTC (rev 221932)
@@ -0,0 +1,6 @@
+Setting video src.
+Video can play.
+Checking the canvas pixels.
+PASS: Bottom edge is red.
+PASS: Top edge is blue.
+
Property changes on: trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-false-expected.txt
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/plain \ No newline at end of property

Added: trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-false.html (0 => 221932)


--- trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-false.html	                        (rev 0)
+++ trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-false.html	2017-09-12 19:28:29 UTC (rev 221932)
@@ -0,0 +1,209 @@
+<style>
+canvas {
+    width: 300px;
+    height: 300px;
+}
+</style>
+</head>
+<script id="vertexShaderSource" type="text/glsl">
+attribute vec4 a_position;
+varying vec2 v_texturePosition;
+
+void main() {
+    v_texturePosition = vec2((a_position.x + 1.0) / 2.0, (a_position.y + 1.0) / 2.0);
+    gl_Position = a_position;
+}
+</script>
+<script id="fragmentShaderSource" type="text/glsl">
+precision mediump float;
+
+varying vec2 v_texturePosition;
+
+uniform sampler2D texture;
+
+void main() {
+  gl_FragColor = texture2D(texture, v_texturePosition);
+}
+</script>
+<script>
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+const width = 300;
+const height = 300;
+let canvas;
+let gl;
+let animationFrame = null;
+let tested = false;
+let drawFunction = null;
+let video;
+
+function output(msg) {
+    const div = document.getElementById("output");
+    div.innerHTML += `${msg}<br>`;
+}
+
+function isMostlyRed(buffer, x, y) {
+    let offset = (y * width + x) * 4;
+    return buffer[offset] > 240 && buffer[offset+1] < 20 && buffer[offset+2] < 20 && buffer[offset+3] > 240;
+}
+
+function isMostlyBlue(buffer, x, y) {
+    let offset = (y * width + x) * 4;
+    return buffer[offset] < 20 && buffer[offset+1] < 20 && buffer[offset+2] > 240 && buffer[offset+3] > 240;
+}
+
+function runTest() {
+    output("Checking the canvas pixels.");
+
+    drawFunction();
+    let pixels = new Uint8Array(width * height * 4);
+    gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+
+    if (isMostlyRed(pixels, 2, 2))
+        output("PASS: Bottom edge is red.");
+    else
+        output("FAIL: Bottom edge is not red.");
+
+    if (isMostlyBlue(pixels, 2, height - 2))
+        output("PASS: Top edge is blue.");
+    else
+        output("FAIL: Top edge is not blue.");
+
+    cancelAnimationFrame(animationFrame);
+    video.pause();
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function init() {
+
+    canvas = document.querySelector("canvas");
+    canvas.width = width;
+    canvas.height = height;
+
+    gl = canvas.getContext("webgl");
+
+    gl.clearColor(0, 0, 0, 1);
+
+    let vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(vertexShader, document.getElementById("vertexShaderSource").textContent);
+    gl.compileShader(vertexShader);
+    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
+        console.error("Vertex Shader failed to compile.");
+        console.log(gl.getShaderInfoLog(vertexShader));
+        return;
+    }
+
+    let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(fragmentShader, document.getElementById("fragmentShaderSource").textContent);
+    gl.compileShader(fragmentShader);
+    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
+        console.error("Fragment Shader failed to compile.");
+        console.log(gl.getShaderInfoLog(fragmentShader));
+        return;
+    }
+
+    let program = gl.createProgram();
+    gl.attachShader(program, vertexShader);
+    gl.attachShader(program, fragmentShader);
+    gl.linkProgram(program);
+
+    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+        console.error("Unable to link shaders into program.");
+        return;
+    }
+
+    gl.useProgram(program);
+    let textureUniform = gl.getUniformLocation(program, "texture");
+    let positionAttribute = gl.getAttribLocation(program, "a_position");
+    gl.enableVertexAttribArray(positionAttribute);
+
+    let vertices = new Float32Array([
+       -1, -1,
+       1, -1,
+       1, 1,
+       1, 1,
+       -1, 1,
+       -1, -1
+    ]);
+
+    let buffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+
+    let updateTexture = function (texture, data) {
+        gl.bindTexture(gl.TEXTURE_2D, texture);
+        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
+        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+        gl.bindTexture(gl.TEXTURE_2D, null);
+    }
+
+    let texture = gl.createTexture();
+
+    video = document.createElement("video");
+    video.loop = true;
+    video.playsInline = true;
+
+    video.addEventListener("canplay", function () {
+        output("Video can play.");
+    }, false);
+
+    video.addEventListener("timeupdate", function () {
+        // If we've just started, jump forward to 3 seconds. If we've played a bit after
+        // that, check the pixels.
+        if (video.currentTime < 1) {
+            video.currentTime = 3;
+            return;
+        } else if (video.currentTime > 3.1) {
+            if (!tested)
+                runTest();
+            tested = true;
+        }
+    }, false);
+
+    /* Since the texImage2D call isn't flipping in Y, we'll load a
+       video that is already flipped. */
+    output("Setting video src.");
+    video.src = ""
+    video.load();
+    video.play();
+
+    drawFunction = function () {
+        gl.clear(gl.COLOR_BUFFER_BIT);
+
+        if (video.currentTime > 0) {
+            updateTexture(texture, video);
+        }
+
+        gl.activeTexture(gl.TEXTURE0);
+        gl.bindTexture(gl.TEXTURE_2D, texture);
+        gl.uniform1i(textureUniform, 0);
+
+        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+        gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0);
+
+        gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+        animationFrame = requestAnimationFrame(drawFunction);
+    };
+
+    drawFunction();
+}
+
+window.addEventListener("load", init, false);
+</script>
+<body>
+    <canvas></canvas>
+    <div id="output">
+    </div>
+</body>
\ No newline at end of file
Property changes on: trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-false.html
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/html \ No newline at end of property

Added: trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-true-expected.txt (0 => 221932)


--- trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-true-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-true-expected.txt	2017-09-12 19:28:29 UTC (rev 221932)
@@ -0,0 +1,6 @@
+Setting video src.
+Video can play.
+Checking the canvas pixels.
+PASS: Bottom edge is red.
+PASS: Top edge is blue.
+
Property changes on: trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-true-expected.txt
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/plain \ No newline at end of property

Added: trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-true.html (0 => 221932)


--- trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-true.html	                        (rev 0)
+++ trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-true.html	2017-09-12 19:28:29 UTC (rev 221932)
@@ -0,0 +1,207 @@
+<style>
+canvas {
+    width: 300px;
+    height: 300px;
+}
+</style>
+</head>
+<script id="vertexShaderSource" type="text/glsl">
+attribute vec4 a_position;
+varying vec2 v_texturePosition;
+
+void main() {
+    v_texturePosition = vec2((a_position.x + 1.0) / 2.0, (a_position.y + 1.0) / 2.0);
+    gl_Position = a_position;
+}
+</script>
+<script id="fragmentShaderSource" type="text/glsl">
+precision mediump float;
+
+varying vec2 v_texturePosition;
+
+uniform sampler2D texture;
+
+void main() {
+  gl_FragColor = texture2D(texture, v_texturePosition);
+}
+</script>
+<script>
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+const width = 300;
+const height = 300;
+let canvas;
+let gl;
+let animationFrame = null;
+let tested = false;
+let drawFunction = null;
+let video;
+
+function output(msg) {
+    const div = document.getElementById("output");
+    div.innerHTML += `${msg}<br>`;
+}
+
+function isMostlyRed(buffer, x, y) {
+    let offset = (y * width + x) * 4;
+    return buffer[offset] > 240 && buffer[offset+1] < 20 && buffer[offset+2] < 20 && buffer[offset+3] > 240;
+}
+
+function isMostlyBlue(buffer, x, y) {
+    let offset = (y * width + x) * 4;
+    return buffer[offset] < 20 && buffer[offset+1] < 20 && buffer[offset+2] > 240 && buffer[offset+3] > 240;
+}
+
+function runTest() {
+    output("Checking the canvas pixels.");
+
+    drawFunction();
+    let pixels = new Uint8Array(width * height * 4);
+    gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+
+    if (isMostlyRed(pixels, 2, 2))
+        output("PASS: Bottom edge is red.");
+    else
+        output("FAIL: Bottom edge is not red.");
+
+    if (isMostlyBlue(pixels, 2, height - 2))
+        output("PASS: Top edge is blue.");
+    else
+        output("FAIL: Top edge is not blue.");
+
+    cancelAnimationFrame(animationFrame);
+    video.pause();
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function init() {
+
+    canvas = document.querySelector("canvas");
+    canvas.width = width;
+    canvas.height = height;
+
+    gl = canvas.getContext("webgl");
+
+    gl.clearColor(0, 0, 0, 1);
+
+    let vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(vertexShader, document.getElementById("vertexShaderSource").textContent);
+    gl.compileShader(vertexShader);
+    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
+        console.error("Vertex Shader failed to compile.");
+        console.log(gl.getShaderInfoLog(vertexShader));
+        return;
+    }
+
+    let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(fragmentShader, document.getElementById("fragmentShaderSource").textContent);
+    gl.compileShader(fragmentShader);
+    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
+        console.error("Fragment Shader failed to compile.");
+        console.log(gl.getShaderInfoLog(fragmentShader));
+        return;
+    }
+
+    let program = gl.createProgram();
+    gl.attachShader(program, vertexShader);
+    gl.attachShader(program, fragmentShader);
+    gl.linkProgram(program);
+
+    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+        console.error("Unable to link shaders into program.");
+        return;
+    }
+
+    gl.useProgram(program);
+    let textureUniform = gl.getUniformLocation(program, "texture");
+    let positionAttribute = gl.getAttribLocation(program, "a_position");
+    gl.enableVertexAttribArray(positionAttribute);
+
+    let vertices = new Float32Array([
+       -1, -1,
+       1, -1,
+       1, 1,
+       1, 1,
+       -1, 1,
+       -1, -1
+    ]);
+
+    let buffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+
+    let updateTexture = function (texture, data) {
+        gl.bindTexture(gl.TEXTURE_2D, texture);
+        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
+        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+        gl.bindTexture(gl.TEXTURE_2D, null);
+    }
+
+    let texture = gl.createTexture();
+
+    video = document.createElement("video");
+    video.loop = true;
+    video.playsInline = true;
+
+    video.addEventListener("canplay", function () {
+        output("Video can play.");
+    }, false);
+
+    video.addEventListener("timeupdate", function () {
+        // If we've just started, jump forward to 3 seconds. If we've played a bit after
+        // that, check the pixels.
+        if (video.currentTime < 1) {
+            video.currentTime = 3;
+            return;
+        } else if (video.currentTime > 3.1) {
+            if (!tested)
+                runTest();
+            tested = true;
+        }
+    }, false);
+
+    output("Setting video src.");
+    video.src = ""
+    video.load();
+    video.play();
+
+    drawFunction = function () {
+        gl.clear(gl.COLOR_BUFFER_BIT);
+
+        if (video.currentTime > 0) {
+            updateTexture(texture, video);
+        }
+
+        gl.activeTexture(gl.TEXTURE0);
+        gl.bindTexture(gl.TEXTURE_2D, texture);
+        gl.uniform1i(textureUniform, 0);
+
+        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+        gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0);
+
+        gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+        animationFrame = requestAnimationFrame(drawFunction);
+    };
+
+    drawFunction();
+}
+
+window.addEventListener("load", init, false);
+</script>
+<body>
+    <canvas></canvas>
+    <div id="output">
+    </div>
+</body>
\ No newline at end of file
Property changes on: trunk/LayoutTests/fast/canvas/webgl/texImage2D-video-flipY-true.html
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/html \ No newline at end of property

Modified: trunk/LayoutTests/platform/ios/TestExpectations (221931 => 221932)


--- trunk/LayoutTests/platform/ios/TestExpectations	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/LayoutTests/platform/ios/TestExpectations	2017-09-12 19:28:29 UTC (rev 221932)
@@ -2865,6 +2865,9 @@
 webgl/1.0.2/conformance/rendering/multisample-corruption.html [ Skip ]
 webgl/1.0.2/conformance/uniforms/out-of-bounds-uniform-array-access.html [ Skip ]
 
+fast/canvas/webgl/texImage2D-video-flipY-false.html [ Skip ]
+fast/canvas/webgl/texImage2D-video-flipY-true.html [ Skip ]
+
 webkit.org/b/174120 http/tests/loading/resourceLoadStatistics/user-interaction-in-cross-origin-sub-frame.html [ Skip ]
 
 webkit.org/b/175273 imported/w3c/web-platform-tests/html/browsers/windows/noreferrer-window-name.html [ Failure ]

Modified: trunk/Source/WebCore/ChangeLog (221931 => 221932)


--- trunk/Source/WebCore/ChangeLog	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/Source/WebCore/ChangeLog	2017-09-12 19:28:29 UTC (rev 221932)
@@ -1,3 +1,58 @@
+2017-09-12  Dean Jackson  <d...@apple.com>
+
+        [WebGL] accelerated texImage2D for video doesn't respect flipY
+        https://bugs.webkit.org/show_bug.cgi?id=176491
+        <rdar://problem/33833511>
+
+        Reviewed by Jer Noble.
+
+        (Take 2 - this was rolled out due to a test failure, but the following
+        commit will fix that)
+
+        Previously, if UNPACK_FLIP_Y_WEBGL was set to true, we'd either fall
+        back to software or fail to upload texture data. Fix this by intercepting
+        the texImage2D call, checking the orientation of the video, and running
+        a small shader program to flip it if necessary.
+
+        While there, implement UNPACK_PREMULTIPLY_ALPHA_WEBGL as well, although
+        none of our media decoders support video with alpha, so unfortunately
+        this will have no visible change.
+
+        Tests: fast/canvas/webgl/texImage2D-video-flipY-false.html
+               fast/canvas/webgl/texImage2D-video-flipY-true.html
+
+        * platform/cocoa/CoreVideoSoftLink.cpp: Add link to CVOpenGL(ES)TextureGetCleanTexCoords,
+        which is used to check the orientation of the source video.
+        * platform/cocoa/CoreVideoSoftLink.h:
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::copyVideoTextureToPlatformTexture): We can
+        now handle flipped or premultiplied requests.
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::copyVideoTextureToPlatformTexture): Ditto.
+
+        * platform/graphics/cv/VideoTextureCopierCV.cpp:
+        (WebCore::VideoTextureCopierCV::VideoTextureCopierCV): Rename readFramebuffer to
+        simply framebuffer.
+        (WebCore::VideoTextureCopierCV::~VideoTextureCopierCV): Delete the program and buffer
+        if they were created.
+        (WebCore::VideoTextureCopierCV::initializeContextObjects): Sets up the shader program
+        and the vertex buffer for drawing. Also records the location of the uniforms.
+        (WebCore::VideoTextureCopierCV::copyVideoTextureToPlatformTexture): Create a new
+        framebuffer object, and render the video texture into that framebuffer using a
+        shader that can flip the coordinates.
+        (WebCore::VideoTextureCopierCV::GC3DStateSaver::GC3DStateSaver): Helper to restore
+        the state of the user's GraphicsContext3D while we're intercepting calls.
+        (WebCore::VideoTextureCopierCV::GC3DStateSaver::~GC3DStateSaver):
+        * platform/graphics/cv/VideoTextureCopierCV.h:
+
+        * platform/graphics/GraphicsContext3D.h: Add two new entry points, for direct shader
+        compilation and attribute access. This avoids going through ANGLE.
+        * platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp:
+        (WebCore::GraphicsContext3D::compileShader):
+        (WebCore::GraphicsContext3D::compileShaderDirect):
+        (WebCore::GraphicsContext3D::getAttribLocationDirect):
+
 2017-09-12  Manuel Rego Casasnovas  <r...@igalia.com>
 
         [css-grid] Stretching auto tracks should be done as part of the track sizing algorithm

Modified: trunk/Source/WebCore/platform/cocoa/CoreVideoSoftLink.cpp (221931 => 221932)


--- trunk/Source/WebCore/platform/cocoa/CoreVideoSoftLink.cpp	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/Source/WebCore/platform/cocoa/CoreVideoSoftLink.cpp	2017-09-12 19:28:29 UTC (rev 221932)
@@ -61,6 +61,7 @@
 SOFT_LINK_FUNCTION_FOR_SOURCE(WebCore, CoreVideo, CVOpenGLESTextureGetName, GLuint, (CVOpenGLESTextureRef image), (image))
 SOFT_LINK_FUNCTION_FOR_SOURCE(WebCore, CoreVideo, CVPixelBufferCreate, CVReturn, (CFAllocatorRef allocator, size_t width, size_t height, OSType pixelFormatType, CFDictionaryRef pixelBufferAttributes, CVPixelBufferRef *pixelBufferOut), (allocator, width, height, pixelFormatType, pixelBufferAttributes, pixelBufferOut))
 SOFT_LINK_FUNCTION_FOR_SOURCE(WebCore, CoreVideo, CVPixelBufferCreateWithBytes, CVReturn, (CFAllocatorRef allocator, size_t width, size_t height, OSType pixelFormatType, void* data, size_t bytesPerRow, void (*releaseCallback)(void*, const void*), void* releasePointer, CFDictionaryRef pixelBufferAttributes, CVPixelBufferRef *pixelBufferOut), (allocator, width, height, pixelFormatType, data, bytesPerRow, releaseCallback, releasePointer, pixelBufferAttributes, pixelBufferOut))
+SOFT_LINK_FUNCTION_FOR_SOURCE(WebCore, CoreVideo, CVOpenGLESTextureGetCleanTexCoords, void, (CVOpenGLESTextureRef image, GLfloat lowerLeft[2], GLfloat lowerRight[2], GLfloat upperLeft[2], GLfloat upperRight[2]), (image, lowerLeft, lowerRight, upperLeft, upperRight))
 #else
 SOFT_LINK_FUNCTION_FOR_SOURCE(WebCore, CoreVideo, CVOpenGLTextureCacheCreate, CVReturn, (CFAllocatorRef allocator, CFDictionaryRef cacheAttributes, CGLContextObj cglContext, CGLPixelFormatObj cglPixelFormat, CFDictionaryRef textureAttributes, CVOpenGLTextureCacheRef* cacheOut), (allocator, cacheAttributes, cglContext, cglPixelFormat, textureAttributes, cacheOut))
 SOFT_LINK_FUNCTION_FOR_SOURCE(WebCore, CoreVideo, CVOpenGLTextureCacheCreateTextureFromImage, CVReturn, (CFAllocatorRef allocator, CVOpenGLTextureCacheRef textureCache, CVImageBufferRef sourceImage, CFDictionaryRef attributes, CVOpenGLTextureRef* textureOut), (allocator, textureCache, sourceImage, attributes, textureOut))
@@ -67,5 +68,6 @@
 SOFT_LINK_FUNCTION_FOR_SOURCE(WebCore, CoreVideo, CVOpenGLTextureCacheFlush, void, (CVOpenGLTextureCacheRef textureCache, CVOptionFlags options), (textureCache, options))
 SOFT_LINK_FUNCTION_FOR_SOURCE(WebCore, CoreVideo, CVOpenGLTextureGetTarget, GLenum, (CVOpenGLTextureRef image), (image))
 SOFT_LINK_FUNCTION_FOR_SOURCE(WebCore, CoreVideo, CVOpenGLTextureGetName, GLuint, (CVOpenGLTextureRef image), (image))
+SOFT_LINK_FUNCTION_FOR_SOURCE(WebCore, CoreVideo, CVOpenGLTextureGetCleanTexCoords, void, (CVOpenGLTextureRef image, GLfloat lowerLeft[2], GLfloat lowerRight[2], GLfloat upperLeft[2], GLfloat upperRight[2]), (image, lowerLeft, lowerRight, upperLeft, upperRight))
 SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, CoreVideo, kCVPixelBufferIOSurfaceOpenGLFBOCompatibilityKey, CFStringRef)
 #endif

Modified: trunk/Source/WebCore/platform/cocoa/CoreVideoSoftLink.h (221931 => 221932)


--- trunk/Source/WebCore/platform/cocoa/CoreVideoSoftLink.h	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/Source/WebCore/platform/cocoa/CoreVideoSoftLink.h	2017-09-12 19:28:29 UTC (rev 221932)
@@ -86,6 +86,8 @@
 #define CVPixelBufferCreate softLink_CoreVideo_CVPixelBufferCreate
 SOFT_LINK_FUNCTION_FOR_HEADER(WebCore, CoreVideo, CVPixelBufferCreateWithBytes, CVReturn, (CFAllocatorRef allocator, size_t width, size_t height, OSType pixelFormatType, void* data, size_t bytesPerRow, void (*releaseCallback)(void*, const void*), void* releasePointer, CFDictionaryRef pixelBufferAttributes, CVPixelBufferRef *pixelBufferOut), (allocator, width, height, pixelFormatType, data, bytesPerRow, releaseCallback, releasePointer, pixelBufferAttributes, pixelBufferOut))
 #define CVPixelBufferCreateWithBytes softLink_CoreVideo_CVPixelBufferCreateWithBytes
+SOFT_LINK_FUNCTION_FOR_HEADER(WebCore, CoreVideo, CVOpenGLESTextureGetCleanTexCoords, void, (CVOpenGLESTextureRef image, GLfloat lowerLeft[2], GLfloat lowerRight[2], GLfloat upperLeft[2], GLfloat upperRight[2]), (image, lowerLeft, lowerRight, upperLeft, upperRight))
+#define CVOpenGLESTextureGetCleanTexCoords softLink_CoreVideo_CVOpenGLESTextureGetCleanTexCoords
 
 SOFT_LINK_CONSTANT_FOR_HEADER(WebCore, CoreVideo, kCVPixelBufferCGBitmapContextCompatibilityKey, CFStringRef)
 #define kCVPixelBufferCGBitmapContextCompatibilityKey get_CoreVideo_kCVPixelBufferCGBitmapContextCompatibilityKey()
@@ -104,6 +106,8 @@
 #define CVOpenGLTextureGetTarget softLink_CoreVideo_CVOpenGLTextureGetTarget
 SOFT_LINK_FUNCTION_FOR_HEADER(WebCore, CoreVideo, CVOpenGLTextureGetName, GLuint, (CVOpenGLTextureRef image), (image))
 #define CVOpenGLTextureGetName softLink_CoreVideo_CVOpenGLTextureGetName
+SOFT_LINK_FUNCTION_FOR_HEADER(WebCore, CoreVideo, CVOpenGLTextureGetCleanTexCoords, void, (CVOpenGLTextureRef image, GLfloat lowerLeft[2], GLfloat lowerRight[2], GLfloat upperLeft[2], GLfloat upperRight[2]), (image, lowerLeft, lowerRight, upperLeft, upperRight))
+#define CVOpenGLTextureGetCleanTexCoords softLink_CoreVideo_CVOpenGLTextureGetCleanTexCoords
 
 SOFT_LINK_CONSTANT_FOR_HEADER(WebCore, CoreVideo, kCVPixelBufferIOSurfaceOpenGLFBOCompatibilityKey, CFStringRef)
 #define kCVPixelBufferIOSurfaceOpenGLFBOCompatibilityKey get_CoreVideo_kCVPixelBufferIOSurfaceOpenGLFBOCompatibilityKey()

Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext3D.h (221931 => 221932)


--- trunk/Source/WebCore/platform/graphics/GraphicsContext3D.h	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext3D.h	2017-09-12 19:28:29 UTC (rev 221932)
@@ -764,6 +764,12 @@
     // Equivalent to ::glTexImage2D(). Allows pixels==0 with no allocation.
     void texImage2DDirect(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels);
 
+    // Get an attribute location without checking the name -> mangledname mapping.
+    int getAttribLocationDirect(Platform3DObject program, const String& name);
+
+    // Compile a shader without going through ANGLE.
+    void compileShaderDirect(Platform3DObject);
+
     // Helper to texImage2D with pixel==0 case: pixels are initialized to 0.
     // Return true if no GL error is synthesized.
     // By default, alignment is 4, the OpenGL default setting.

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (221931 => 221932)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm	2017-09-12 19:28:29 UTC (rev 221932)
@@ -2465,9 +2465,6 @@
 
 bool MediaPlayerPrivateAVFoundationObjC::copyVideoTextureToPlatformTexture(GraphicsContext3D* context, Platform3DObject outputTexture, GC3Denum outputTarget, GC3Dint level, GC3Denum internalFormat, GC3Denum format, GC3Denum type, bool premultiplyAlpha, bool flipY)
 {
-    if (flipY || premultiplyAlpha)
-        return false;
-
     ASSERT(context);
 
     if (!m_openGLVideoOutput)

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm (221931 => 221932)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm	2017-09-12 19:28:29 UTC (rev 221932)
@@ -599,9 +599,6 @@
 
 bool MediaPlayerPrivateMediaSourceAVFObjC::copyVideoTextureToPlatformTexture(GraphicsContext3D* context, Platform3DObject outputTexture, GC3Denum outputTarget, GC3Dint level, GC3Denum internalFormat, GC3Denum format, GC3Denum type, bool premultiplyAlpha, bool flipY)
 {
-    if (flipY || premultiplyAlpha)
-        return false;
-
     // We have been asked to paint into a WebGL canvas, so take that as a signal to create
     // a decompression session, even if that means the native video can't also be displayed
     // in page.

Modified: trunk/Source/WebCore/platform/graphics/cv/VideoTextureCopierCV.cpp (221931 => 221932)


--- trunk/Source/WebCore/platform/graphics/cv/VideoTextureCopierCV.cpp	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/Source/WebCore/platform/graphics/cv/VideoTextureCopierCV.cpp	2017-09-12 19:28:29 UTC (rev 221932)
@@ -28,6 +28,7 @@
 
 #include "Logging.h"
 #include <wtf/NeverDestroyed.h>
+#include <wtf/text/StringBuilder.h>
 
 #if PLATFORM(IOS)
 #include <OpenGLES/ES3/glext.h>
@@ -39,13 +40,17 @@
 
 VideoTextureCopierCV::VideoTextureCopierCV(GraphicsContext3D& context)
     : m_context(context)
-    , m_readFramebuffer(context.createFramebuffer())
+    , m_framebuffer(context.createFramebuffer())
 {
 }
 
 VideoTextureCopierCV::~VideoTextureCopierCV()
 {
-    m_context->deleteFramebuffer(m_readFramebuffer);
+    if (m_vertexBuffer)
+        m_context->deleteProgram(m_vertexBuffer);
+    if (m_program)
+        m_context->deleteProgram(m_program);
+    m_context->deleteFramebuffer(m_framebuffer);
 }
 
 #if !LOG_DISABLED
@@ -152,61 +157,211 @@
 
 #endif
 
-bool VideoTextureCopierCV::copyVideoTextureToPlatformTexture(TextureType inputTexture, size_t width, size_t height, Platform3DObject outputTexture, GC3Denum outputTarget, GC3Dint level, GC3Denum internalFormat, GC3Denum format, GC3Denum type, bool premultiplyAlpha, bool flipY)
+bool VideoTextureCopierCV::initializeContextObjects()
 {
-    if (flipY || premultiplyAlpha)
+    StringBuilder vertexShaderSource;
+    vertexShaderSource.appendLiteral("attribute vec4 a_position;\n");
+    vertexShaderSource.appendLiteral("uniform int u_flipY;\n");
+    vertexShaderSource.appendLiteral("varying vec2 v_texturePosition;\n");
+    vertexShaderSource.appendLiteral("void main() {\n");
+    vertexShaderSource.appendLiteral("    v_texturePosition = vec2((a_position.x + 1.0) / 2.0, (a_position.y + 1.0) / 2.0);\n");
+    vertexShaderSource.appendLiteral("    if (u_flipY == 1) {\n");
+    vertexShaderSource.appendLiteral("        v_texturePosition.y = 1.0 - v_texturePosition.y;\n");
+    vertexShaderSource.appendLiteral("    }\n");
+    vertexShaderSource.appendLiteral("    gl_Position = a_position;\n");
+    vertexShaderSource.appendLiteral("}\n");
+
+    Platform3DObject vertexShader = m_context->createShader(GraphicsContext3D::VERTEX_SHADER);
+    m_context->shaderSource(vertexShader, vertexShaderSource.toString());
+    m_context->compileShaderDirect(vertexShader);
+
+    GC3Dint value = 0;
+    m_context->getShaderiv(vertexShader, GraphicsContext3D::COMPILE_STATUS, &value);
+    if (!value) {
+        LOG(WebGL, "VideoTextureCopierCV::copyVideoTextureToPlatformTexture(%p) - Vertex shader failed to compile.", this);
+        m_context->deleteShader(vertexShader);
         return false;
+    }
 
-    if (!inputTexture)
+    StringBuilder fragmentShaderSource;
+
+#if PLATFORM(IOS)
+    fragmentShaderSource.appendLiteral("precision mediump float;\n");
+    fragmentShaderSource.appendLiteral("uniform sampler2D u_texture;\n");
+#else
+    fragmentShaderSource.appendLiteral("uniform sampler2DRect u_texture;\n");
+#endif
+    fragmentShaderSource.appendLiteral("varying vec2 v_texturePosition;\n");
+    fragmentShaderSource.appendLiteral("uniform int u_premultiply;\n");
+    fragmentShaderSource.appendLiteral("uniform vec2 u_textureDimensions;\n");
+    fragmentShaderSource.appendLiteral("void main() {\n");
+    fragmentShaderSource.appendLiteral("    vec2 texPos = vec2(v_texturePosition.x * u_textureDimensions.x, v_texturePosition.y * u_textureDimensions.y);\n");
+#if PLATFORM(IOS)
+    fragmentShaderSource.appendLiteral("    vec4 color = texture2D(u_texture, texPos);\n");
+#else
+    fragmentShaderSource.appendLiteral("    vec4 color = texture2DRect(u_texture, texPos);\n");
+#endif
+    fragmentShaderSource.appendLiteral("    if (u_premultiply == 1) {\n");
+    fragmentShaderSource.appendLiteral("        gl_FragColor = vec4(color.r * color.a, color.g * color.a, color.b * color.a, color.a);\n");
+    fragmentShaderSource.appendLiteral("    } else {\n");
+    fragmentShaderSource.appendLiteral("        gl_FragColor = color;\n");
+    fragmentShaderSource.appendLiteral("    }\n");
+    fragmentShaderSource.appendLiteral("}\n");
+
+    Platform3DObject fragmentShader = m_context->createShader(GraphicsContext3D::FRAGMENT_SHADER);
+    m_context->shaderSource(fragmentShader, fragmentShaderSource.toString());
+    m_context->compileShaderDirect(fragmentShader);
+
+    m_context->getShaderiv(fragmentShader, GraphicsContext3D::COMPILE_STATUS, &value);
+    if (!value) {
+        LOG(WebGL, "VideoTextureCopierCV::copyVideoTextureToPlatformTexture(%p) - Fragment shader failed to compile.", this);
+        m_context->deleteShader(vertexShader);
+        m_context->deleteShader(fragmentShader);
         return false;
+    }
 
+    m_program = m_context->createProgram();
+    m_context->attachShader(m_program, vertexShader);
+    m_context->attachShader(m_program, fragmentShader);
+    m_context->linkProgram(m_program);
+
+    m_context->getProgramiv(m_program, GraphicsContext3D::LINK_STATUS, &value);
+    if (!value) {
+        LOG(WebGL, "VideoTextureCopierCV::copyVideoTextureToPlatformTexture(%p) - Program failed to link.", this);
+        m_context->deleteShader(vertexShader);
+        m_context->deleteShader(fragmentShader);
+        m_context->deleteProgram(m_program);
+        m_program = 0;
+        return false;
+    }
+
+    m_textureUniformLocation = m_context->getUniformLocation(m_program, ASCIILiteral("u_texture"));
+    m_textureDimensionsUniformLocation = m_context->getUniformLocation(m_program, ASCIILiteral("u_textureDimensions"));
+    m_flipYUniformLocation = m_context->getUniformLocation(m_program, ASCIILiteral("u_flipY"));
+    m_premultiplyUniformLocation = m_context->getUniformLocation(m_program, ASCIILiteral("u_premultiply"));
+    m_positionAttributeLocation = m_context->getAttribLocationDirect(m_program, ASCIILiteral("a_position"));
+
+    m_context->detachShader(m_program, vertexShader);
+    m_context->detachShader(m_program, fragmentShader);
+    m_context->deleteShader(vertexShader);
+    m_context->deleteShader(fragmentShader);
+
+    LOG(WebGL, "Uniform and Attribute locations: u_texture = %d, u_textureDimensions = %d, u_flipY = %d, u_premultiply = %d, a_position = %d", m_textureUniformLocation, m_textureDimensionsUniformLocation, m_flipYUniformLocation, m_premultiplyUniformLocation, m_positionAttributeLocation);
+    m_context->enableVertexAttribArray(m_positionAttributeLocation);
+
+    m_vertexBuffer = m_context->createBuffer();
+    float vertices[12] = { -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1 };
+
+    m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexBuffer);
+    m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, sizeof(float) * 12, vertices, GraphicsContext3D::STATIC_DRAW);
+
+    return true;
+}
+
+bool VideoTextureCopierCV::copyVideoTextureToPlatformTexture(TextureType inputVideoTexture, size_t width, size_t height, Platform3DObject outputTexture, GC3Denum outputTarget, GC3Dint level, GC3Denum internalFormat, GC3Denum format, GC3Denum type, bool premultiplyAlpha, bool flipY)
+{
+    if (!inputVideoTexture)
+        return false;
+
+    GC3DStateSaver stateSaver(&m_context.get());
+
+    if (!m_program) {
+        if (!initializeContextObjects()) {
+            LOG(WebGL, "VideoTextureCopierCV::copyVideoTextureToPlatformTexture(%p) - Unable to initialize OpenGL context objects.", this);
+            return false;
+        }
+    }
+
+    GLfloat lowerLeft[2] = { 0, 0 };
+    GLfloat lowerRight[2] = { 0, 0 };
+    GLfloat upperRight[2] = { 0, 0 };
+    GLfloat upperLeft[2] = { 0, 0 };
 #if PLATFORM(IOS)
-    Platform3DObject videoTextureName = CVOpenGLESTextureGetName(inputTexture);
-    GC3Denum videoTextureTarget = CVOpenGLESTextureGetTarget(inputTexture);
+    Platform3DObject videoTextureName = CVOpenGLESTextureGetName(inputVideoTexture);
+    GC3Denum videoTextureTarget = CVOpenGLESTextureGetTarget(inputVideoTexture);
+    CVOpenGLESTextureGetCleanTexCoords(inputVideoTexture, lowerLeft, lowerRight, upperRight, upperLeft);
 #else
-    Platform3DObject videoTextureName = CVOpenGLTextureGetName(inputTexture);
-    GC3Denum videoTextureTarget = CVOpenGLTextureGetTarget(inputTexture);
+    Platform3DObject videoTextureName = CVOpenGLTextureGetName(inputVideoTexture);
+    GC3Denum videoTextureTarget = CVOpenGLTextureGetTarget(inputVideoTexture);
+    CVOpenGLTextureGetCleanTexCoords(inputVideoTexture, lowerLeft, lowerRight, upperRight, upperLeft);
 #endif
 
-    LOG(Media, "VideoTextureCopierCV::copyVideoTextureToPlatformTexture(%p) - internalFormat: %s, format: %s, type: %s", this, enumToStringMap()[internalFormat], enumToStringMap()[format], enumToStringMap()[type]);
+    LOG(WebGL, "VideoTextureCopierCV::copyVideoTextureToPlatformTexture(%p) - internalFormat: %s, format: %s, type: %s flipY: %s, premultiplyAlpha: %s", this, enumToStringMap()[internalFormat], enumToStringMap()[format], enumToStringMap()[type], flipY ? "true" : "false", premultiplyAlpha ? "true" : "false");
 
-    // Save the origial bound texture & framebuffer names so we can re-bind them after copying the video texture.
-    GC3Dint boundTexture = 0;
-    GC3Dint boundReadFramebuffer = 0;
-    m_context->getIntegerv(GraphicsContext3D::TEXTURE_BINDING_2D, &boundTexture);
-    m_context->getIntegerv(GraphicsContext3D::READ_FRAMEBUFFER_BINDING, &boundReadFramebuffer);
+    m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_framebuffer);
+    
+    // Allocate memory for the output texture.
+    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, outputTexture);
+    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
+    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
+    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
+    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
+    m_context->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, level, internalFormat, width, height, 0, format, type, nullptr);
 
+    m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, outputTexture, level);
+    GC3Denum status = m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER);
+    if (status != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+        LOG(WebGL, "VideoTextureCopierCV::copyVideoTextureToPlatformTexture(%p) - Unable to create framebuffer for outputTexture.", this);
+        return false;
+    }
+
+    m_context->useProgram(m_program);
+    m_context->viewport(0, 0, width, height);
+
+    // Bind and set up the texture for the video source.
+    m_context->activeTexture(GraphicsContext3D::TEXTURE0);
     m_context->bindTexture(videoTextureTarget, videoTextureName);
-    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
-    m_context->texParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
-    m_context->texParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
+    m_context->texParameteri(videoTextureTarget, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
+    m_context->texParameteri(videoTextureTarget, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
+    m_context->texParameteri(videoTextureTarget, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
+    m_context->texParameteri(videoTextureTarget, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
 
-    // Make that framebuffer the read source from which drawing commands will read voxels.
-    m_context->bindFramebuffer(GraphicsContext3D::READ_FRAMEBUFFER, m_readFramebuffer);
+    // Configure the drawing parameters.
+    m_context->uniform1i(m_textureUniformLocation, 0);
+#if PLATFORM(IOS)
+    m_context->uniform2f(m_textureDimensionsUniformLocation, 1, 1);
+#else
+    m_context->uniform2f(m_textureDimensionsUniformLocation, width, height);
+#endif
 
-    // Allocate uninitialized memory for the output texture.
-    m_context->bindTexture(outputTarget, outputTexture);
-    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
-    m_context->texParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
-    m_context->texParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
-    m_context->texImage2DDirect(outputTarget, level, internalFormat, width, height, 0, format, type, nullptr);
+    if (lowerLeft[1] < upperRight[1])
+        flipY = !flipY;
 
-    // Attach the video texture to the framebuffer.
-    m_context->framebufferTexture2D(GraphicsContext3D::READ_FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, videoTextureTarget, videoTextureName, level);
+    m_context->uniform1i(m_flipYUniformLocation, flipY);
+    m_context->uniform1i(m_premultiplyUniformLocation, premultiplyAlpha);
 
-    GC3Denum status = m_context->checkFramebufferStatus(GraphicsContext3D::READ_FRAMEBUFFER);
-    if (status != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
-        return false;
+    // Do the actual drawing.
+    m_context->enableVertexAttribArray(m_positionAttributeLocation);
+    m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexBuffer);
+    m_context->vertexAttribPointer(m_positionAttributeLocation, 2, GraphicsContext3D::FLOAT, false, 0, 0);
+    m_context->drawArrays(GraphicsContext3D::TRIANGLES, 0, 6);
 
-    // Copy texture from the read framebuffer (and thus the video texture) to the output texture.
-    m_context->copyTexImage2D(outputTarget, level, internalFormat, 0, 0, width, height, 0);
+    // Clean-up.
+    m_context->bindTexture(videoTextureTarget, 0);
+    m_context->bindTexture(outputTarget, outputTexture);
 
-    // Restore the previous texture and framebuffer bindings.
-    m_context->bindTexture(outputTarget, boundTexture);
-    m_context->bindFramebuffer(GraphicsContext3D::READ_FRAMEBUFFER, boundReadFramebuffer);
+    return true;
+}
 
-    return !m_context->getError();
+VideoTextureCopierCV::GC3DStateSaver::GC3DStateSaver(GraphicsContext3D* context)
+    : m_context(context)
+{
+    ASSERT(context);
+    m_context->getIntegerv(GraphicsContext3D::TEXTURE_BINDING_2D, &m_texture);
+    m_context->getIntegerv(GraphicsContext3D::FRAMEBUFFER_BINDING, &m_framebuffer);
+    m_context->getIntegerv(GraphicsContext3D::CURRENT_PROGRAM, &m_program);
+    m_context->getIntegerv(GraphicsContext3D::ARRAY_BUFFER_BINDING, &m_arrayBuffer);
+    m_context->getIntegerv(GraphicsContext3D::VIEWPORT, m_viewport);
 }
 
+VideoTextureCopierCV::GC3DStateSaver::~GC3DStateSaver()
+{
+    m_context->bindTexture(GraphicsContext3D::TEXTURE_BINDING_2D, m_texture);
+    m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_framebuffer);
+    m_context->useProgram(m_program);
+    m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_arrayBuffer);
+    m_context->viewport(m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]);
+}
 
+
 }

Modified: trunk/Source/WebCore/platform/graphics/cv/VideoTextureCopierCV.h (221931 => 221932)


--- trunk/Source/WebCore/platform/graphics/cv/VideoTextureCopierCV.h	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/Source/WebCore/platform/graphics/cv/VideoTextureCopierCV.h	2017-09-12 19:28:29 UTC (rev 221932)
@@ -28,7 +28,7 @@
 
 #import "GraphicsContext3D.h"
 
-typedef struct  __CVBuffer* CVImageBufferRef;
+typedef struct __CVBuffer* CVImageBufferRef;
 typedef CVImageBufferRef CVOpenGLTextureRef;
 typedef CVImageBufferRef CVOpenGLESTextureRef;
 
@@ -50,8 +50,31 @@
     GraphicsContext3D& context() { return m_context.get(); }
 
 private:
+    class GC3DStateSaver {
+    public:
+        GC3DStateSaver(GraphicsContext3D*);
+        ~GC3DStateSaver();
+
+    private:
+        GraphicsContext3D* m_context;
+        GC3Dint m_texture { 0 };
+        GC3Dint m_framebuffer { 0 };
+        GC3Dint m_program { 0 };
+        GC3Dint m_arrayBuffer { 0 };
+        GC3Dint m_viewport[4] { 0, 0, 0, 0 };
+    };
+
+    bool initializeContextObjects();
+
     Ref<GraphicsContext3D> m_context;
-    Platform3DObject m_readFramebuffer;
+    Platform3DObject m_framebuffer { 0 };
+    Platform3DObject m_program { 0 };
+    Platform3DObject m_vertexBuffer { 0 };
+    GC3Dint m_textureUniformLocation { -1 };
+    GC3Dint m_textureDimensionsUniformLocation { -1 };
+    GC3Dint m_flipYUniformLocation { -1 };
+    GC3Dint m_premultiplyUniformLocation { -1 };
+    GC3Dint m_positionAttributeLocation { -1 };
 };
 
 }

Modified: trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp (221931 => 221932)


--- trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp	2017-09-12 19:19:45 UTC (rev 221931)
+++ trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp	2017-09-12 19:28:29 UTC (rev 221932)
@@ -666,9 +666,9 @@
     
     ::glCompileShader(shader);
     
-    int GLCompileSuccess;
+    int compileStatus;
     
-    ::glGetShaderiv(shader, COMPILE_STATUS, &GLCompileSuccess);
+    ::glGetShaderiv(shader, COMPILE_STATUS, &compileStatus);
 
     ShaderSourceMap::iterator result = m_shaderSourceMap.find(shader);
     GraphicsContext3D::ShaderSourceEntry& entry = result->value;
@@ -686,12 +686,47 @@
         entry.log = getUnmangledInfoLog(shaders, 1, String(info.get()));
     }
 
-    if (GLCompileSuccess != GL_TRUE) {
+    if (compileStatus != GL_TRUE) {
         entry.isValid = false;
         LOG(WebGL, "Error: shader translator produced a shader that OpenGL would not compile.");
     }
 }
 
+void GraphicsContext3D::compileShaderDirect(Platform3DObject shader)
+{
+    ASSERT(shader);
+    makeContextCurrent();
+
+    HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader);
+
+    if (result == m_shaderSourceMap.end())
+        return;
+
+    ShaderSourceEntry& entry = result->value;
+
+    const CString& shaderSourceCString = entry.source.utf8();
+    const char* shaderSourcePtr = shaderSourceCString.data();
+    int shaderSourceLength = shaderSourceCString.length();
+
+    LOG(WebGL, "--- begin direct shader source ---\n%s\n--- end direct shader source ---\n", shaderSourcePtr);
+
+    ::glShaderSource(shader, 1, &shaderSourcePtr, &shaderSourceLength);
+
+    ::glCompileShader(shader);
+
+    int compileStatus;
+
+    ::glGetShaderiv(shader, COMPILE_STATUS, &compileStatus);
+
+    if (compileStatus == GL_TRUE) {
+        entry.isValid = true;
+        LOG(WebGL, "Direct compilation of shader succeeded.");
+    } else {
+        entry.isValid = false;
+        LOG(WebGL, "Error: direct compilation of shader failed.");
+    }
+}
+
 void GraphicsContext3D::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
 {
     makeContextCurrent();
@@ -1068,6 +1103,16 @@
     return ::glGetAttribLocation(program, mappedName.utf8().data());
 }
 
+int GraphicsContext3D::getAttribLocationDirect(Platform3DObject program, const String& name)
+{
+    if (!program)
+        return -1;
+
+    makeContextCurrent();
+
+    return ::glGetAttribLocation(program, name.utf8().data());
+}
+
 GraphicsContext3DAttributes GraphicsContext3D::getContextAttributes()
 {
     return m_attrs;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to