diff --git a/src/imports/qtcanvas3d/canvas3d.cpp b/src/imports/qtcanvas3d/canvas3d.cpp index bd1ff562e98fc6f44f50f031e1960026afa52131..e47a20c500880536d942f7b15b7d78fc383a040f 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 0000000000000000000000000000000000000000..f2cbe4400bc1d1379c4b1aa127d2ce7b636102cd --- /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 0000000000000000000000000000000000000000..5a1c25737dfa6f2a6c21d17ff2e7150110b470b9 --- /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) + } + } + } +}