From 9f234899f5e2cbd51ee21b183370017099bc1226 Mon Sep 17 00:00:00 2001
From: Miikka Heikkinen <miikka.heikkinen@theqtcompany.com>
Date: Wed, 22 Apr 2015 11:52:36 +0300
Subject: [PATCH] Fix readPixels to work with custom framebuffer.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

ReadPixels always read from renderFbo if context had antialiasing
specified.

Also added buffer initialization to zero so pixels that fall outside
the framebuffer contain correct value.

Change-Id: I58b9fda18bc56a64346f83ccda575c758e9eaac5
Reviewed-by: Tomi Korpipää <tomi.korpipaa@theqtcompany.com>
Reviewed-by: Pasi Keränen <pasi.keranen@digia.com>
---
 src/imports/qtcanvas3d/context3d.cpp          |  7 ++-
 .../canvas3d/tst_render_checkresult.js        | 35 +++++++++--
 .../canvas3d/tst_render_checkresult.qml       | 63 ++++++++++++++++++-
 3 files changed, 98 insertions(+), 7 deletions(-)

diff --git a/src/imports/qtcanvas3d/context3d.cpp b/src/imports/qtcanvas3d/context3d.cpp
index 38e0487..52777a5 100644
--- a/src/imports/qtcanvas3d/context3d.cpp
+++ b/src/imports/qtcanvas3d/context3d.cpp
@@ -5214,16 +5214,19 @@ void CanvasContext::readPixels(int x, int y, long width, long height, glEnums fo
         return;
     }
 
+    // Zero out the buffer (WebGL conformance requires pixels outside the framebuffer to be 0)
+    memset(bufferPtr, 0, width * height * 4);
+
     // Check if the buffer is antialiased. If it is, we need to blit to the final buffer before
     // reading the value.
-    if (m_contextAttributes.antialias()) {
+    if (m_contextAttributes.antialias() && !m_currentFramebuffer) {
         GLuint readFbo = m_canvas->resolveMSAAFbo();
         glBindFramebuffer(GL_FRAMEBUFFER, readFbo);
     }
 
     glReadPixels(x, y, width, height, format, type, bufferPtr);
 
-    if (m_contextAttributes.antialias())
+    if (m_contextAttributes.antialias() && !m_currentFramebuffer)
         m_canvas->bindCurrentRenderTarget();
 
     logAllGLErrors(__FUNCTION__);
diff --git a/tests/auto/qmltest/canvas3d/tst_render_checkresult.js b/tests/auto/qmltest/canvas3d/tst_render_checkresult.js
index 0eac410..94f2395 100644
--- a/tests/auto/qmltest/canvas3d/tst_render_checkresult.js
+++ b/tests/auto/qmltest/canvas3d/tst_render_checkresult.js
@@ -52,13 +52,13 @@ var textureCoordAttribute;
 var vertexColorAttribute;
 
 var colorFlagUniform;
+var customFbo;
 
 function initializeGL(canvas) {
     gl = canvas.getContext("");
     gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
     var pixelRatio = canvas.devicePixelRatio;
     gl.viewport(0, 0, pixelRatio * canvas.width, pixelRatio * canvas.height);
-    gl.clearColor(1.0, 0.0, 0.0, 1.0);
 
     initShaders();
     initBuffers();
@@ -73,14 +73,29 @@ function initializeGL(canvas) {
 }
 
 function paintGL() {
+    gl.clearColor(1.0, 0.0, 0, 1.0);
     gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
     gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
 }
 
-function paintGL(x, y) {
-    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+function paintGL(x, y, separateFbo) {
+    if (separateFbo) {
+        gl.bindFramebuffer(gl.FRAMEBUFFER, customFbo);
+        gl.clearColor(0.0, 1.0, 0.0, 1.0);
+        gl.clear(gl.COLOR_BUFFER_BIT);
+    } else {
+        gl.clearColor(1.0, 0.0, 0, 1.0);
+        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+    }
+
     gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
-    return checkPixel(x, y);
+
+    var pixels = checkPixel(x, y);
+
+    if (separateFbo)
+        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+    return pixels;
 }
 
 function checkPixel(x, y) {
@@ -172,6 +187,18 @@ function initBuffers()
                   new Uint16Array([0, 1, 2,
                                    0, 2, 3]),
                   gl.STATIC_DRAW);
+
+    // Custom framebuffer
+    customFbo = gl.createFramebuffer();
+    gl.bindFramebuffer(gl.FRAMEBUFFER, customFbo);
+    var texture = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, texture);
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.canvas.width, gl.canvas.height, 0, gl.RGBA,
+                  gl.UNSIGNED_BYTE, null);
+    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+
+    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
 }
 
 function initShaders()
diff --git a/tests/auto/qmltest/canvas3d/tst_render_checkresult.qml b/tests/auto/qmltest/canvas3d/tst_render_checkresult.qml
index 350d2fd..935d1f7 100644
--- a/tests/auto/qmltest/canvas3d/tst_render_checkresult.qml
+++ b/tests/auto/qmltest/canvas3d/tst_render_checkresult.qml
@@ -54,6 +54,7 @@ Item {
     property int blue: -1
     property int alpha: -1
     property bool renderOk: false
+    property bool separateFbo: false
 
     Canvas3D {
         id: render_check_result
@@ -62,7 +63,7 @@ Item {
         onInitializeGL: Content.initializeGL(this)
         onPaintGL: {
             if (checkResult) {
-                pixels = Content.paintGL(xpos, ypos)
+                pixels = Content.paintGL(xpos, ypos, separateFbo)
                 red = pixels[0]
                 green = pixels[1]
                 blue = pixels[2]
@@ -89,6 +90,7 @@ Item {
             ypos = 150
             checkResult = true
             renderOk = false
+            separateFbo = false
             waitForRendering(render_check_result)
             tryCompare(top, "renderOk", true)
             tryCompare(top, "red", 0x00)
@@ -123,6 +125,7 @@ Item {
             ypos = 150
             checkResult = true
             renderOk = false
+            separateFbo = false
             waitForRendering(render_check_result)
             tryCompare(top, "renderOk", true)
             tryCompare(render_check_result, "textureLoaded", true, 10000)
@@ -144,6 +147,7 @@ Item {
             ypos = 150
             checkResult = true
             renderOk = false
+            separateFbo = false
             waitForRendering(render_check_result)
             tryCompare(top, "renderOk", true)
             tryCompare(top, "red", 0x22)
@@ -154,5 +158,62 @@ Item {
 
             waitForRendering(render_check_result)
         }
+
+        function test_render_4_checkresult() {
+            // Render to separate FBO.
+            waitForRendering(render_check_result)
+            Content.setColor(0x40, 0x60, 0x80, 0xff)
+
+            // Check color in the center of the square
+            xpos = 150
+            ypos = 150
+            checkResult = true
+            renderOk = false
+            separateFbo = true
+            waitForRendering(render_check_result)
+            tryCompare(top, "renderOk", true)
+            tryCompare(top, "red", 0x40)
+            tryCompare(top, "green", 0x60)
+            tryCompare(top, "blue", 0x80)
+            tryCompare(top, "alpha", 0xff)
+            checkResult = false
+
+            waitForRendering(render_check_result)
+
+            // Check color in the corner of the screen, which is cleared with green
+            xpos = 0
+            ypos = 0
+            checkResult = true
+            renderOk = false
+            waitForRendering(render_check_result)
+            tryCompare(top, "renderOk", true)
+            tryCompare(top, "red", 0x00)
+            tryCompare(top, "green", 0xff)
+            tryCompare(top, "blue", 0x00)
+            tryCompare(top, "alpha", 0xff)
+            checkResult = false
+
+            waitForRendering(render_check_result)
+        }
+
+        function test_render_5_checkresult() {
+            // Check that pixels outside framebuffer are zero
+            waitForRendering(render_check_result)
+            Content.setColor(0x22, 0x99, 0xff, 0x80)
+            xpos = 9999
+            ypos = 9999
+            checkResult = true
+            renderOk = false
+            separateFbo = false
+            waitForRendering(render_check_result)
+            tryCompare(top, "renderOk", true)
+            tryCompare(top, "red", 0x0)
+            tryCompare(top, "green", 0x0)
+            tryCompare(top, "blue", 0x0)
+            tryCompare(top, "alpha", 0x0)
+            checkResult = false
+
+            waitForRendering(render_check_result)
+        }
     }
 }
-- 
GitLab