From 42535df165ac1e02d83e159e925ca22f84ae7321 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen <miikka.heikkinen@theqtcompany.com> Date: Wed, 22 Apr 2015 16:19:06 +0300 Subject: [PATCH] Add preserveDrawingBuffer support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I232893c201b45a6e2164c05b99c3c8170068376d Task-number: QTBUG-45589 Reviewed-by: Tomi Korpipää <tomi.korpipaa@theqtcompany.com> Reviewed-by: Pasi Keränen <pasi.keranen@digia.com> --- src/imports/qtcanvas3d/canvas3d.cpp | 15 +- .../qmltest/canvas3d/tst_render_preserve.js | 153 ++++++++++++++++++ .../qmltest/canvas3d/tst_render_preserve.qml | 141 ++++++++++++++++ 3 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qmltest/canvas3d/tst_render_preserve.js create mode 100644 tests/auto/qmltest/canvas3d/tst_render_preserve.qml diff --git a/src/imports/qtcanvas3d/canvas3d.cpp b/src/imports/qtcanvas3d/canvas3d.cpp index bd1ff56..e47a20c 100644 --- a/src/imports/qtcanvas3d/canvas3d.cpp +++ b/src/imports/qtcanvas3d/canvas3d.cpp @@ -243,7 +243,6 @@ QJSValue Canvas::getContext(const QString &type, const QVariantMap &options) // Ensure ignored attributes are left to their default state m_contextAttribs.setPremultipliedAlpha(false); - m_contextAttribs.setPreserveDrawingBuffer(false); m_contextAttribs.setPreferLowPowerToHighPerformance(false); m_contextAttribs.setFailIfMajorPerformanceCaveat(false); } @@ -846,6 +845,20 @@ void Canvas::renderNext() << m_displayFbo->texture() << " from FBO:" << m_displayFbo->handle(); + if (m_contextAttribs.preserveDrawingBuffer()) { + // Copy the content of display fbo to the render fbo + GLint texBinding2D; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &texBinding2D); + + m_displayFbo->bind(); + glBindTexture(GL_TEXTURE_2D, m_renderFbo->texture()); + + glCopyTexImage2D(GL_TEXTURE_2D, 0, m_displayFbo->format().internalTextureFormat(), + 0, 0, m_fboSize.width(), m_fboSize.height(), 0); + + glBindTexture(GL_TEXTURE_2D, texBinding2D); + } + // FBO ids and texture id's have been generated, we can now free the old display FBO delete m_oldDisplayFbo; m_oldDisplayFbo = 0; diff --git a/tests/auto/qmltest/canvas3d/tst_render_preserve.js b/tests/auto/qmltest/canvas3d/tst_render_preserve.js new file mode 100644 index 0000000..f2cbe44 --- /dev/null +++ b/tests/auto/qmltest/canvas3d/tst_render_preserve.js @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCanvas3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +var gl; + +var colorBuffer; + +var vertexPositionAttribute; +var vertexColorAttribute; + +var vertexBuffer; + +function initializeGL(canvas) { + gl = canvas.getContext("", {preserveDrawingBuffer:true}); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + var pixelRatio = canvas.devicePixelRatio; + gl.viewport(0, 0, pixelRatio * canvas.width, pixelRatio * canvas.height); + + initShaders(); + initBuffers(); +} + +function paintGL() { + gl.clearColor(1.0, 0.0, 0.0, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawArrays(gl.TRIANGLES, 0, 3); +} + +function checkPixel(x, y) { + var pixels = new Uint8Array(4); + gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + return pixels; +} + +function setColor(r, g, b, a) { + gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); + var colors = [r / 255.0, g / 255.0, b / 255.0, a / 255.0]; + var generatedColors = []; + for (var i = 0; i < 4; i++) + generatedColors = generatedColors.concat(colors); + gl.bufferData(gl.ARRAY_BUFFER, + new Float32Array(generatedColors), + gl.STATIC_DRAW); + gl.enableVertexAttribArray(vertexColorAttribute); + gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0); +} + +function initBuffers() +{ + vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, new Float32Array( + [-1.0, -1.0, + 1.0, -1.0, + -1.0, 1.0 + ]), + gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vertexPositionAttribute); + + colorBuffer = gl.createBuffer(); + setColor(0.0, 0.0, 255.0, 255.0); +} + +function initShaders() +{ + var vertexShader = getShader( + gl, + "attribute highp vec2 aVertexPosition; \ + attribute mediump vec4 aVertexColor; \ + varying mediump vec4 vColor; \ + void main(void) { \ + gl_Position = vec4(aVertexPosition, 0.0, 1.0); \ + vColor = aVertexColor; \ + }", + gl.VERTEX_SHADER); + var fragmentShader = getShader( + gl, + "varying mediump vec4 vColor; \ + void main(void) { \ + gl_FragColor = vColor; \ + }", + gl.FRAGMENT_SHADER); + + var shaderProgram = gl.createProgram(); + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + gl.deleteShader(vertexShader); + gl.deleteShader(fragmentShader); + + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + console.log("Could not initialize shaders"); + console.log(gl.getProgramInfoLog(shaderProgram)); + } + + gl.useProgram(shaderProgram); + + vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); + gl.enableVertexAttribArray(vertexPositionAttribute); + vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor"); + gl.enableVertexAttribArray(vertexColorAttribute); +} + +function getShader(gl, str, type) { + var shader = gl.createShader(type); + gl.shaderSource(shader, str); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.log("JS:Shader compile failed"); + console.log(gl.getShaderInfoLog(shader)); + return null; + } + + return shader; +} diff --git a/tests/auto/qmltest/canvas3d/tst_render_preserve.qml b/tests/auto/qmltest/canvas3d/tst_render_preserve.qml new file mode 100644 index 0000000..5a1c257 --- /dev/null +++ b/tests/auto/qmltest/canvas3d/tst_render_preserve.qml @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCanvas3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtCanvas3D 1.0 +import QtTest 1.0 + +import "tst_render_preserve.js" as Content + +Item { + id: top + height: 300 + width: 300 + + property int xpos: 0 + property int ypos: 0 + property var pixels + property int red: -1 + property int green: -1 + property int blue: -1 + property int alpha: -1 + property bool paintDone: true + property bool checkDone: true + property bool initDone: false + + Canvas3D { + id: render_preserve + property bool textureLoaded: false + anchors.fill: parent + onInitializeGL: { + Content.initializeGL(this) + initDone = true + } + onPaintGL: { + if (!paintDone) { + Content.paintGL() + paintDone = true + } + + if (!checkDone) { + pixels = Content.checkPixel(xpos, ypos) + red = pixels[0] + green = pixels[1] + blue = pixels[2] + alpha = pixels[3] + delete pixels + checkDone = true + } + } + } + + TestCase { + name: "Canvas3D_render_preserve" + when: windowShown + + function test_render_1_preserve() { + tryCompare(top, "initDone", true) + Content.setColor(0x00, 0x00, 0xff, 0xff) + // Draw the frame exactly once. That way one of the framebuffers has our scene and + // the other is default empty. + paintDone = false; + tryCompare(top, "paintDone", true) + + // We cannot control if we are reading from the first or second framebuffer, since we + // cannot actually reliably sync with the render loop. We work around this issue + // by doing the pixel checks multiple times. That way at least one of the checks + // is likely to target the framebuffer we didn't draw our frame to, and therefore + // fails if the preserve is not working. + for (var i = 0; i < 10; i++) { + // Check color in the left side (part of the triangle) + xpos = 75 + ypos = 150 + checkDone = false + tryCompare(top, "checkDone", true) + compare(top.red, 0x00) + compare(top.green, 0x00) + compare(top.blue, 0xff) + compare(top.alpha, 0xff) + + // Check color in the right part of the screen, which is cleared with red + xpos = 225 + ypos = 150 + checkDone = false + tryCompare(top, "checkDone", true) + compare(top.red, 0xff) + compare(top.green, 0x00) + compare(top.blue, 0x00) + compare(top.alpha, 0xff) + } + + Content.setColor(0x00, 0xcc, 0x00, 0xff) + paintDone = false; + tryCompare(top, "paintDone", true) + + for (var j = 0; j < 10; j++) { + // Check color in the left side (part of the triangle) + xpos = 75 + ypos = 150 + checkDone = false + tryCompare(top, "checkDone", true) + compare(top.red, 0x00) + compare(top.green, 0xcc) + compare(top.blue, 0x00) + compare(top.alpha, 0xff) + } + } + } +} -- GitLab