aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/quick/quick.pro3
-rw-r--r--examples/quick/rendercontrol/demo.qml198
-rw-r--r--examples/quick/rendercontrol/doc/images/rendercontrol-example.jpgbin0 -> 44196 bytes
-rw-r--r--examples/quick/rendercontrol/doc/src/rendercontrol.qdoc33
-rw-r--r--examples/quick/rendercontrol/main.cpp51
-rw-r--r--examples/quick/rendercontrol/rendercontrol.pro11
-rw-r--r--examples/quick/rendercontrol/rendercontrol.qrc5
-rw-r--r--examples/quick/rendercontrol/window.cpp403
-rw-r--r--examples/quick/rendercontrol/window.h100
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc20
-rw-r--r--src/quick/items/items.pri9
-rw-r--r--src/quick/items/qquickrendercontrol.cpp239
-rw-r--r--src/quick/items/qquickrendercontrol.h84
-rw-r--r--src/quick/items/qquickrendercontrol_p.h68
-rw-r--r--src/quick/items/qquickwindow.cpp18
-rw-r--r--src/quick/items/qquickwindow.h2
-rw-r--r--src/quickwidgets/qquickwidget.cpp27
17 files changed, 1116 insertions, 155 deletions
diff --git a/examples/quick/quick.pro b/examples/quick/quick.pro
index 421f95a162..a412c53a65 100644
--- a/examples/quick/quick.pro
+++ b/examples/quick/quick.pro
@@ -22,7 +22,8 @@ SUBDIRS = quick-accessibility \
imageprovider \
window \
particles \
- demos
+ demos \
+ rendercontrol
# Widget dependent examples
qtHaveModule(widgets) {
diff --git a/examples/quick/rendercontrol/demo.qml b/examples/quick/rendercontrol/demo.qml
new file mode 100644
index 0000000000..e7ede91540
--- /dev/null
+++ b/examples/quick/rendercontrol/demo.qml
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Particles 2.0
+
+Rectangle {
+ id: root
+ color: "green"
+
+ Rectangle {
+ width: 400
+ height: 400
+ anchors.centerIn: parent
+ color: "red"
+ NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; }
+ }
+
+ Text {
+ anchors.centerIn: parent
+ text: "Qt Quick in a texture"
+ font.pointSize: 40
+ color: "cyan"
+ }
+
+ ParticleSystem {
+ id: particles
+ anchors.fill: parent
+
+ ImageParticle {
+ id: smoke
+ system: particles
+ anchors.fill: parent
+ groups: ["A", "B"]
+ source: "qrc:///particleresources/glowdot.png"
+ colorVariation: 0
+ color: "#00111111"
+ }
+ ImageParticle {
+ id: flame
+ anchors.fill: parent
+ system: particles
+ groups: ["C", "D"]
+ source: "qrc:///particleresources/glowdot.png"
+ colorVariation: 0.1
+ color: "#00ff400f"
+ }
+
+ Emitter {
+ id: fire
+ system: particles
+ group: "C"
+
+ y: parent.height
+ width: parent.width
+
+ emitRate: 350
+ lifeSpan: 3500
+
+ acceleration: PointDirection { y: -17; xVariation: 3 }
+ velocity: PointDirection {xVariation: 3}
+
+ size: 24
+ sizeVariation: 8
+ endSize: 4
+ }
+
+ TrailEmitter {
+ id: fireSmoke
+ group: "B"
+ system: particles
+ follow: "C"
+ width: root.width
+ height: root.height - 68
+
+ emitRatePerParticle: 1
+ lifeSpan: 2000
+
+ velocity: PointDirection {y:-17*6; yVariation: -17; xVariation: 3}
+ acceleration: PointDirection {xVariation: 3}
+
+ size: 36
+ sizeVariation: 8
+ endSize: 16
+ }
+
+ TrailEmitter {
+ id: fireballFlame
+ anchors.fill: parent
+ system: particles
+ group: "D"
+ follow: "E"
+
+ emitRatePerParticle: 120
+ lifeSpan: 180
+ emitWidth: TrailEmitter.ParticleSize
+ emitHeight: TrailEmitter.ParticleSize
+ emitShape: EllipseShape{}
+
+ size: 16
+ sizeVariation: 4
+ endSize: 4
+ }
+
+ TrailEmitter {
+ id: fireballSmoke
+ anchors.fill: parent
+ system: particles
+ group: "A"
+ follow: "E"
+
+ emitRatePerParticle: 128
+ lifeSpan: 2400
+ emitWidth: TrailEmitter.ParticleSize
+ emitHeight: TrailEmitter.ParticleSize
+ emitShape: EllipseShape{}
+
+ velocity: PointDirection {yVariation: 16; xVariation: 16}
+ acceleration: PointDirection {y: -16}
+
+ size: 24
+ sizeVariation: 8
+ endSize: 8
+ }
+
+ Emitter {
+ id: balls
+ system: particles
+ group: "E"
+
+ y: parent.height
+ width: parent.width
+
+ emitRate: 2
+ lifeSpan: 7000
+
+ velocity: PointDirection {y:-17*4*2; xVariation: 6*6}
+ acceleration: PointDirection {y: 17*2; xVariation: 6*6}
+
+ size: 8
+ sizeVariation: 4
+ }
+
+ Turbulence { //A bit of turbulence makes the smoke look better
+ anchors.fill: parent
+ groups: ["A","B"]
+ strength: 32
+ system: particles
+ }
+ }
+
+ onWidthChanged: particles.reset()
+ onHeightChanged: particles.reset()
+
+ MouseArea {
+ anchors.fill: parent
+ onPressed: root.color = "gray"
+ onReleased: root.color = "green"
+ }
+}
diff --git a/examples/quick/rendercontrol/doc/images/rendercontrol-example.jpg b/examples/quick/rendercontrol/doc/images/rendercontrol-example.jpg
new file mode 100644
index 0000000000..a899ebe7f5
--- /dev/null
+++ b/examples/quick/rendercontrol/doc/images/rendercontrol-example.jpg
Binary files differ
diff --git a/examples/quick/rendercontrol/doc/src/rendercontrol.qdoc b/examples/quick/rendercontrol/doc/src/rendercontrol.qdoc
new file mode 100644
index 0000000000..f8a9849a8a
--- /dev/null
+++ b/examples/quick/rendercontrol/doc/src/rendercontrol.qdoc
@@ -0,0 +1,33 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \title QQuickRenderControl Example
+ \example rendercontrol
+ \brief Shows how to render a Qt Quick scene into a texture that is then used by a non-Quick based OpenGL renderer
+ \image rendercontrol-example.jpg
+*/
diff --git a/examples/quick/rendercontrol/main.cpp b/examples/quick/rendercontrol/main.cpp
new file mode 100644
index 0000000000..d362278ddf
--- /dev/null
+++ b/examples/quick/rendercontrol/main.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+ Window window;
+ window.resize(1024, 768);
+ window.show();
+ return app.exec();
+}
diff --git a/examples/quick/rendercontrol/rendercontrol.pro b/examples/quick/rendercontrol/rendercontrol.pro
new file mode 100644
index 0000000000..ed25a11c1b
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+QT += quick qml
+
+SOURCES += main.cpp window.cpp
+HEADERS += window.h
+
+RESOURCES += rendercontrol.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/rendercontrol
+INSTALLS += target
diff --git a/examples/quick/rendercontrol/rendercontrol.qrc b/examples/quick/rendercontrol/rendercontrol.qrc
new file mode 100644
index 0000000000..2246eeb842
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/rendercontrol">
+ <file>demo.qml</file>
+ </qresource>
+</RCC>
diff --git a/examples/quick/rendercontrol/window.cpp b/examples/quick/rendercontrol/window.cpp
new file mode 100644
index 0000000000..396e9f8afa
--- /dev/null
+++ b/examples/quick/rendercontrol/window.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include <QOpenGLContext>
+#include <QOpenGLFunctions>
+#include <QOpenGLFramebufferObject>
+#include <QOpenGLShaderProgram>
+#include <QOpenGLVertexArrayObject>
+#include <QOpenGLBuffer>
+#include <QOpenGLVertexArrayObject>
+#include <QOffscreenSurface>
+#include <QQmlEngine>
+#include <QQmlComponent>
+#include <QQuickItem>
+#include <QQuickWindow>
+#include <QQuickRenderControl>
+#include <QCoreApplication>
+
+Window::Window()
+ : m_rootItem(0),
+ m_fbo(0),
+ m_program(0),
+ m_vbo(0),
+ m_quickInitialized(false),
+ m_quickReady(false)
+{
+ setSurfaceType(QSurface::OpenGLSurface);
+
+ QSurfaceFormat format;
+ // Qt Quick may need a depth and stencil buffer. Always make sure these are available.
+ format.setDepthBufferSize(16);
+ format.setStencilBufferSize(8);
+ setFormat(format);
+
+ m_context = new QOpenGLContext;
+ m_context->setFormat(format);
+ m_context->create();
+
+ m_offscreenSurface = new QOffscreenSurface;
+ // Pass m_context->format(), not format. Format does not specify and color buffer
+ // sizes, while the context, that has just been created, reports a format that has
+ // these values filled in. Pass this to the offscreen surface to make sure it will be
+ // compatible with the context's configuration.
+ m_offscreenSurface->setFormat(m_context->format());
+ m_offscreenSurface->create();
+
+ m_renderControl = new QQuickRenderControl(this);
+
+ // Create a QQuickWindow that is associated with out render control. Note that this
+ // window never gets created or shown, meaning that it will never get an underlying
+ // native (platform) window.
+ m_quickWindow = new QQuickWindow(m_renderControl);
+
+ // Create a QML engine.
+ m_qmlEngine = new QQmlEngine;
+ if (!m_qmlEngine->incubationController())
+ m_qmlEngine->setIncubationController(m_quickWindow->incubationController());
+
+ // When Quick says there is a need to render, we will not render immediately. Instead,
+ // a timer with a small interval is used to get better performance.
+ m_updateTimer.setSingleShot(true);
+ m_updateTimer.setInterval(5);
+ connect(&m_updateTimer, &QTimer::timeout, this, &Window::updateQuick);
+
+ // Now hook up the signals. For simplicy we don't differentiate between
+ // renderRequested (only render is needed, no sync) and sceneChanged (polish and sync
+ // is needed too).
+ connect(m_quickWindow, &QQuickWindow::sceneGraphInitialized, this, &Window::createFbo);
+ connect(m_quickWindow, &QQuickWindow::sceneGraphInvalidated, this, &Window::destroyFbo);
+ connect(m_renderControl, &QQuickRenderControl::renderRequested, this, &Window::requestUpdate);
+ connect(m_renderControl, &QQuickRenderControl::sceneChanged, this, &Window::requestUpdate);
+}
+
+Window::~Window()
+{
+ // Make sure the context is current while doing cleanup.
+ m_context->makeCurrent(this);
+
+ // Delete the render control first since it will free the scenegraph resources.
+ // Destroy the QQuickWindow only afterwards.
+ delete m_renderControl;
+
+ delete m_qmlComponent;
+ delete m_quickWindow;
+ delete m_qmlEngine;
+ delete m_fbo;
+ delete m_program;
+ delete m_vbo;
+ delete m_vao;
+
+ m_context->doneCurrent();
+
+ delete m_offscreenSurface;
+ delete m_context;
+}
+
+void Window::createFbo()
+{
+ // The scene graph has been initialized. It is now time to create an FBO and associate
+ // it with the QQuickWindow.
+ m_fbo = new QOpenGLFramebufferObject(size(), QOpenGLFramebufferObject::CombinedDepthStencil);
+ m_quickWindow->setRenderTarget(m_fbo);
+}
+
+void Window::destroyFbo()
+{
+ delete m_fbo;
+ m_fbo = 0;
+}
+
+void Window::requestUpdate()
+{
+ if (!m_updateTimer.isActive())
+ m_updateTimer.start();
+}
+
+void Window::run()
+{
+ disconnect(m_qmlComponent, SIGNAL(statusChanged(QQmlComponent::Status)), this, SLOT(run()));
+
+ if (m_qmlComponent->isError()) {
+ QList<QQmlError> errorList = m_qmlComponent->errors();
+ foreach (const QQmlError &error, errorList)
+ qWarning() << error.url() << error.line() << error;
+ return;
+ }
+
+ QObject *rootObject = m_qmlComponent->create();
+ if (m_qmlComponent->isError()) {
+ QList<QQmlError> errorList = m_qmlComponent->errors();
+ foreach (const QQmlError &error, errorList)
+ qWarning() << error.url() << error.line() << error;
+ return;
+ }
+
+ m_rootItem = qobject_cast<QQuickItem *>(rootObject);
+ if (!m_rootItem) {
+ qWarning("run: Not a QQuickItem");
+ delete rootObject;
+ return;
+ }
+
+ // The root item is ready. Associate it with the window.
+ m_rootItem->setParentItem(m_quickWindow->contentItem());
+
+ // Update item and rendering related geometries.
+ updateSizes();
+
+ // Initialize the render control and our OpenGL resources.
+ m_context->makeCurrent(m_offscreenSurface);
+ m_renderControl->initialize(m_context);
+
+ static const char *vertexShaderSource =
+ "attribute highp vec4 vertex;\n"
+ "attribute lowp vec2 coord;\n"
+ "varying lowp vec2 v_coord;\n"
+ "uniform highp mat4 matrix;\n"
+ "void main() {\n"
+ " v_coord = coord;\n"
+ " gl_Position = matrix * vertex;\n"
+ "}\n";
+ static const char *fragmentShaderSource =
+ "varying lowp vec2 v_coord;\n"
+ "uniform sampler2D sampler;\n"
+ "void main() {\n"
+ " gl_FragColor = vec4(texture2D(sampler, v_coord).rgb, 1.0);\n"
+ "}\n";
+ m_program = new QOpenGLShaderProgram;
+ m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
+ m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
+ m_program->bindAttributeLocation("vertex", 0);
+ m_program->bindAttributeLocation("coord", 1);
+ m_program->link();
+ m_matrixLoc = m_program->uniformLocation("matrix");
+
+ m_vao = new QOpenGLVertexArrayObject;
+ m_vao->create();
+ m_vao->bind();
+
+ m_vbo = new QOpenGLBuffer;
+ m_vbo->create();
+ m_vbo->bind();
+
+ GLfloat v[] = {
+ -0.5, 0.5, 0.5, 0.5,-0.5,0.5,-0.5,-0.5,0.5,
+ 0.5, -0.5, 0.5, -0.5,0.5,0.5,0.5,0.5,0.5,
+ -0.5, -0.5, -0.5, 0.5,-0.5,-0.5,-0.5,0.5,-0.5,
+ 0.5, 0.5, -0.5, -0.5,0.5,-0.5,0.5,-0.5,-0.5,
+
+ 0.5, -0.5, -0.5, 0.5,-0.5,0.5,0.5,0.5,-0.5,
+ 0.5, 0.5, 0.5, 0.5,0.5,-0.5,0.5,-0.5,0.5,
+ -0.5, 0.5, -0.5, -0.5,-0.5,0.5,-0.5,-0.5,-0.5,
+ -0.5, -0.5, 0.5, -0.5,0.5,-0.5,-0.5,0.5,0.5,
+
+ 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5,
+ -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5,
+ -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5,
+ 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5
+ };
+ GLfloat texCoords[] = {
+ 0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f,
+ 1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f,
+ 1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f,
+ 0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f,
+
+ 1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f,
+ 0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f,
+ 0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f,
+ 1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f,
+
+ 0.0f,1.0f, 1.0f,0.0f, 1.0f,1.0f,
+ 1.0f,0.0f, 0.0f,1.0f, 0.0f,0.0f,
+ 1.0f,0.0f, 1.0f,1.0f, 0.0f,0.0f,
+ 0.0f,1.0f, 0.0f,0.0f, 1.0f,1.0f
+ };
+
+ const int vertexCount = 36;
+ m_vbo->allocate(sizeof(GLfloat) * vertexCount * 5);
+ m_vbo->write(0, v, sizeof(GLfloat) * vertexCount * 3);
+ m_vbo->write(sizeof(GLfloat) * vertexCount * 3, texCoords, sizeof(GLfloat) * vertexCount * 2);
+ m_vbo->release();
+
+ if (m_vao->isCreated())
+ setupVertexAttribs();
+
+ // Must unbind before changing the current context. Hence the absence of
+ // QOpenGLVertexArrayObject::Binder here.
+ m_vao->release();
+
+ m_context->doneCurrent();
+ m_quickInitialized = true;
+}
+
+void Window::updateSizes()
+{
+ // Behave like SizeRootObjectToView.
+ m_rootItem->setWidth(width());
+ m_rootItem->setHeight(height());
+
+ m_quickWindow->setGeometry(0, 0, width(), height());
+
+ m_proj.setToIdentity();
+ m_proj.perspective(45, width() / float(height()), 0.01f, 100.0f);
+}
+
+void Window::setupVertexAttribs()
+{
+ m_vbo->bind();
+ m_program->enableAttributeArray(0);
+ m_program->enableAttributeArray(1);
+ m_context->functions()->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+ m_context->functions()->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0,
+ (const void *)(36 * 3 * sizeof(GLfloat)));
+ m_vbo->release();
+}
+
+void Window::startQuick(const QString &filename)
+{
+ m_qmlComponent = new QQmlComponent(m_qmlEngine, QUrl(filename));
+ if (m_qmlComponent->isLoading())
+ connect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Window::run);
+ else
+ run();
+}
+
+void Window::exposeEvent(QExposeEvent *)
+{
+ if (isExposed()) {
+ render();
+ if (!m_quickInitialized)
+ startQuick(QStringLiteral("qrc:/rendercontrol/demo.qml"));
+ }
+}
+
+void Window::resizeEvent(QResizeEvent *)
+{
+ // If this is a resize after the scene is up and running, recreate the fbo and the
+ // Quick item and scene.
+ if (m_rootItem && m_context->makeCurrent(m_offscreenSurface)) {
+ delete m_fbo;
+ createFbo();
+ m_context->doneCurrent();
+ updateSizes();
+ }
+}
+
+void Window::updateQuick()
+{
+ if (!m_context->makeCurrent(m_offscreenSurface))
+ return;
+
+ // Polish, synchronize and render the next frame (into our fbo). In this example
+ // everything happens on the same thread and therefore all three steps are performed
+ // in succession from here. In a threaded setup the render() call would happen on a
+ // separate thread.
+ m_renderControl->polishItems();
+ m_renderControl->sync();
+ m_renderControl->render();
+
+ m_quickWindow->resetOpenGLState();
+ QOpenGLFramebufferObject::bindDefault();
+
+ m_quickReady = true;
+
+ // Get something onto the screen.
+ render();
+}
+
+void Window::render()
+{
+ if (!m_context->makeCurrent(this))
+ return;
+
+ QOpenGLFunctions *f = m_context->functions();
+ f->glClearColor(0.0f, 0.1f, 0.25f, 1.0f);
+ f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if (m_quickReady) {
+ f->glFrontFace(GL_CW); // because our cube's vertex data is such
+ f->glEnable(GL_CULL_FACE);
+ f->glEnable(GL_DEPTH_TEST);
+
+ f->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+
+ m_program->bind();
+ QOpenGLVertexArrayObject::Binder vaoBinder(m_vao);
+ // If VAOs are not supported, set the vertex attributes every time.
+ if (!m_vao->isCreated())
+ setupVertexAttribs();
+
+ static GLfloat angle = 0;
+ QMatrix4x4 m;
+ m.translate(0, 0, -2);
+ m.rotate(90, 0, 0, 1);
+ m.rotate(angle, 0.5, 1, 0);
+ angle += 0.5f;
+
+ m_program->setUniformValue(m_matrixLoc, m_proj * m);
+
+ // Draw the cube.
+ f->glDrawArrays(GL_TRIANGLES, 0, 36);
+
+ m_program->release();
+ f->glDisable(GL_DEPTH_TEST);
+ f->glDisable(GL_CULL_FACE);
+ }
+
+ m_context->swapBuffers(this);
+}
+
+void Window::mousePressEvent(QMouseEvent *e)
+{
+ // Use the constructor taking localPos and screenPos. That puts localPos into the
+ // event's localPos and windowPos, and screenPos into the event's screenPos. This way
+ // the windowPos in e is ignored and is replaced by localPos. This is necessary
+ // because QQuickWindow thinks of itself as a top-level window always.
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
+ QCoreApplication::sendEvent(m_quickWindow, &mappedEvent);
+}
+
+void Window::mouseReleaseEvent(QMouseEvent *e)
+{
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
+ QCoreApplication::sendEvent(m_quickWindow, &mappedEvent);
+}
diff --git a/examples/quick/rendercontrol/window.h b/examples/quick/rendercontrol/window.h
new file mode 100644
index 0000000000..2723aeb011
--- /dev/null
+++ b/examples/quick/rendercontrol/window.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QWindow>
+#include <QMatrix4x4>
+#include <QTimer>
+
+QT_FORWARD_DECLARE_CLASS(QOpenGLContext)
+QT_FORWARD_DECLARE_CLASS(QOpenGLFramebufferObject)
+QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
+QT_FORWARD_DECLARE_CLASS(QOpenGLBuffer)
+QT_FORWARD_DECLARE_CLASS(QOpenGLVertexArrayObject)
+QT_FORWARD_DECLARE_CLASS(QOffscreenSurface)
+QT_FORWARD_DECLARE_CLASS(QQuickRenderControl)
+QT_FORWARD_DECLARE_CLASS(QQuickWindow)
+QT_FORWARD_DECLARE_CLASS(QQmlEngine)
+QT_FORWARD_DECLARE_CLASS(QQmlComponent)
+QT_FORWARD_DECLARE_CLASS(QQuickItem)
+
+class Window : public QWindow
+{
+ Q_OBJECT
+
+public:
+ Window();
+ ~Window();
+
+protected:
+ void exposeEvent(QExposeEvent *e) Q_DECL_OVERRIDE;
+ void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE;
+ void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
+ void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
+
+private slots:
+ void render();
+ void updateQuick();
+ void run();
+ void createFbo();
+ void destroyFbo();
+ void requestUpdate();
+
+private:
+ void startQuick(const QString &filename);
+ void setupVertexAttribs();
+ void updateSizes();
+
+ QOpenGLContext *m_context;
+ QOffscreenSurface *m_offscreenSurface;
+ QQuickRenderControl *m_renderControl;
+ QQuickWindow *m_quickWindow;
+ QQmlEngine *m_qmlEngine;
+ QQmlComponent *m_qmlComponent;
+ QQuickItem *m_rootItem;
+ QOpenGLFramebufferObject *m_fbo;
+ QOpenGLShaderProgram *m_program;
+ QOpenGLBuffer *m_vbo;
+ QOpenGLVertexArrayObject *m_vao;
+ bool m_quickInitialized;
+ bool m_quickReady;
+ int m_matrixLoc;
+ QMatrix4x4 m_proj;
+ QTimer m_updateTimer;
+};
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index 7a54b7a021..1f8147c4d1 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -244,11 +244,11 @@ animations, process events, etc.
\endlist
-The threaded renderer is currently used by default on Linux, Mac OS X
-and EGLFS based QPA platforms, but this is subject to change. It is
-possible to force use of the threaded renderer by setting \c
-{QML_FORCE_THREADED_RENDERER=1} in the environment.
-
+The threaded renderer is currently used by default on Linux with
+non-Mesa based drivers, OS X and EGLFS based QPA platforms, but this
+is subject to change. It is possible to force use of the threaded
+renderer by setting \c {QSG_RENDER_LOOP=threaded} in the
+environment.
\section2 Non-threaded Render Loop
@@ -267,6 +267,16 @@ sequence in the non-threaded renderer.
\image sg-renderloop-singlethreaded.jpg
+\section2 Custom control over rendering with QQuickRenderControl
+
+When using QQuickRenderControl, the responsibility for driving the
+rendering loop is transferred to the application. In this case no
+built-in render loop is used. Instead, it is up to the application to
+invoke the polish, synchronize and rendering steps at the appropriate
+time. It is possible to implement either a threaded or non-threaded
+behavior similar to the ones shown above.
+
+
\section2 Mixing Scene Graph and OpenGL
The scene graph offers two methods for integrating OpenGL content:
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index add909d0cb..042ff80abc 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -10,7 +10,6 @@ HEADERS += \
$$PWD/qquickrectangle_p_p.h \
$$PWD/qquickwindow.h \
$$PWD/qquickwindow_p.h \
- $$PWD/qquickrendercontrol_p.h \
$$PWD/qquickfocusscope_p.h \
$$PWD/qquickitemsmodule_p.h \
$$PWD/qquickpainteditem.h \
@@ -76,7 +75,9 @@ HEADERS += \
$$PWD/qquickscreen_p.h \
$$PWD/qquickwindowmodule_p.h \
$$PWD/qquickframebufferobject.h \
- $$PWD/qquickitemgrabresult.h
+ $$PWD/qquickitemgrabresult.h \
+ $$PWD/qquickrendercontrol.h \
+ $$PWD/qquickrendercontrol_p.h
SOURCES += \
$$PWD/qquickevents.cpp \
@@ -84,7 +85,6 @@ SOURCES += \
$$PWD/qquickitem.cpp \
$$PWD/qquickrectangle.cpp \
$$PWD/qquickwindow.cpp \
- $$PWD/qquickrendercontrol.cpp \
$$PWD/qquickfocusscope.cpp \
$$PWD/qquickitemsmodule.cpp \
$$PWD/qquickpainteditem.cpp \
@@ -130,7 +130,8 @@ SOURCES += \
$$PWD/qquickwindowmodule.cpp \
$$PWD/qquickscreen.cpp \
$$PWD/qquickframebufferobject.cpp \
- $$PWD/qquickitemgrabresult.cpp
+ $$PWD/qquickitemgrabresult.cpp \
+ $$PWD/qquickrendercontrol.cpp
SOURCES += \
$$PWD/qquickshadereffect.cpp \
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index b8d572114a..311a1b95f8 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -39,6 +39,7 @@
**
****************************************************************************/
+#include "qquickrendercontrol.h"
#include "qquickrendercontrol_p.h"
#include <QtCore/QCoreApplication>
@@ -53,7 +54,6 @@
#include <QtQuick/QQuickWindow>
#include <QtQuick/private/qquickwindow_p.h>
-#include <QtQuick/private/qsgcontext_p.h>
#include <private/qqmlprofilerservice_p.h>
#include <QtCore/private/qobject_p.h>
@@ -61,59 +61,139 @@ QT_BEGIN_NAMESPACE
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-class QQuickRenderControlPrivate : public QObjectPrivate
-{
-public:
- QQuickRenderControlPrivate()
- : window(0)
- {
- sg = QSGContext::createDefaultContext();
- rc = new QSGRenderContext(sg);
- }
+/*!
+ \class QQuickRenderControl
- ~QQuickRenderControlPrivate()
- {
- delete rc;
- delete sg;
- }
+ \brief The QQuickRenderControl class provides a mechanism for rendering the Qt
+ Quick scenegraph onto an offscreen render target in a fully
+ application-controlled manner.
- QQuickWindow *window;
- QSGContext *sg;
- QSGRenderContext *rc;
-};
+ \since 5.4
-/*!
- \class QQuickRenderControl
- \brief The QQuickRenderControl class provides a mechanism for rendering the Qt Quick scenegraph.
+ QQuickWindow and QQuickView and their associated internal render loops render
+ the Qt Quick scene onto a native window. In some cases, for example when
+ integrating with 3rd party OpenGL renderers, it might be beneficial to get the
+ scene into a texture that can then be used in arbitrary ways by the external
+ rendering engine. QQuickRenderControl makes this possible in a hardware
+ accelerated manner, unlike the performance-wise limited alternative of using
+ QQuickWindow::grabWindow()
+
+ When using a QQuickRenderControl, the QQuickWindow does not have to be shown
+ or even created at all. This means there will not be an underlying native
+ window for it. Instead, the QQuickWindow instance is associated with the
+ render control, using the overload of the QQuickWindow constructor, and an
+ OpenGL framebuffer object by calling QQuickWindow::setRenderTarget().
+
+ Management of the context and framebuffer object is up to the application. The
+ context that will be used by Qt Quick must be created before calling
+ initialize(). The creation of the framebuffer object can be deferred, see
+ below. Qt 5.4 introduces the ability for QOpenGLContext to adopt existing
+ native contexts. Together with QQuickRenderControl this makes it possible to
+ create a QOpenGLContext that shares with an external rendering engine's
+ existing context. This new QOpenGLContext can then be used to render the Qt
+ Quick scene into a texture that is accessible by the other engine's context
+ too.
+
+ Loading and instantiation of the QML components happen by using a
+ QQmlEngine. Once the root object is created, it will need to be parented to
+ the QQuickWindow's contentItem().
+
+ Applications will usually have to connect to 4 important signals:
- \internal
+ \list
+
+ \li QQuickWindow::sceneGraphInitialized() Emitted at some point after calling
+ QQuickRenderControl::initialize(). Upon this signal, the application is
+ expected to create its framebuffer object and associate it with the
+ QQuickWindow.
+
+ \li QQuickWindow::sceneGraphInvalidated() When the scenegraph resources are
+ released, the framebuffer object can be destroyed too.
+
+ \li QQuickRenderControl::renderRequested() Indicates that the scene has to be
+ rendered by calling render(). After making the context current, applications
+ are expected to call render().
+
+ \li QQuickRenderControl::sceneChanged() Inidcates that the scene has changed
+ meaning that, before rendering, polishing and synchronizing is also necessary.
+
+ \endlist
+
+ To send events, for example mouse or keyboard events, to the scene, use
+ QCoreApplication::sendEvent() with the QQuickWindow instance as the receiver.
\inmodule QtQuick
*/
-QQuickRenderControl::QQuickRenderControl()
- : QObject(*(new QQuickRenderControlPrivate), 0)
+QSGContext *QQuickRenderControlPrivate::sg = 0;
+
+QQuickRenderControlPrivate::QQuickRenderControlPrivate()
+ : initialized(0),
+ window(0)
{
+ if (!sg) {
+ qAddPostRoutine(cleanup);
+ sg = QSGContext::createDefaultContext();
+ }
+ rc = new QSGRenderContext(sg);
}
-QQuickRenderControl::~QQuickRenderControl()
+QQuickRenderControlPrivate::~QQuickRenderControlPrivate()
{
+ delete rc;
}
-void QQuickRenderControl::windowDestroyed()
+void QQuickRenderControlPrivate::cleanup()
+{
+ delete sg;
+ sg = 0;
+}
+
+QQuickRenderControl::QQuickRenderControl(QObject *parent)
+ : QObject(*(new QQuickRenderControlPrivate), parent)
+{
+}
+
+/*!
+ Destroys the instance. Releases all scenegraph resources.
+
+ \sa stop()
+ */
+QQuickRenderControl::~QQuickRenderControl()
{
Q_D(QQuickRenderControl);
- if (d->window == 0) {
- d->rc->invalidate();
+
+ stop();
+
+ if (d->window)
+ QQuickWindowPrivate::get(d->window)->renderControl = 0;
+}
+
+void QQuickRenderControlPrivate::windowDestroyed()
+{
+ if (window == 0) {
+ rc->invalidate();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
}
}
+/*!
+ Initializes the scene graph resources. The context \a gl has to
+ be the current context.
+ */
void QQuickRenderControl::initialize(QOpenGLContext *gl)
{
Q_D(QQuickRenderControl);
- if (!d->window)
+
+ if (!d->window) {
+ qWarning("QQuickRenderControl::initialize called with no associated window");
+ return;
+ }
+
+ if (QOpenGLContext::currentContext() != gl) {
+ qWarning("QQuickRenderControl::initialize called with incorrect current context");
return;
+ }
// It is the caller's responsiblity to make a context/surface current.
// It cannot be done here since the surface to use may not be the
@@ -121,17 +201,14 @@ void QQuickRenderControl::initialize(QOpenGLContext *gl)
// window/surface at all.
d->rc->initialize(gl);
-}
-void QQuickRenderControl::invalidate()
-{
- Q_D(QQuickRenderControl);
- d->rc->invalidate();
+ d->initialized = true;
}
/*!
This function should be called as late as possible before
- sync(). In a threaded scenario, rendering can happen in parallel with this function.
+ sync(). In a threaded scenario, rendering can happen in parallel
+ with this function.
*/
void QQuickRenderControl::polishItems()
{
@@ -147,9 +224,13 @@ void QQuickRenderControl::polishItems()
}
/*!
- Synchronize GUI and scenegraph. Returns true if the scene graph was changed.
+ This function is used to synchronize the QML scene with the rendering scene
+ graph.
- This function is a synchronization point. Rendering can not happen in parallel.
+ If a dedicated render thread is used, the GUI thread should be blocked for the
+ duration of this call.
+
+ \return \e true if the synchronization changed the scene graph.
*/
bool QQuickRenderControl::sync()
{
@@ -165,15 +246,36 @@ bool QQuickRenderControl::sync()
}
/*!
- Stop rendering and release resources. This function is typically
- called when the window is hidden. Requires a current context.
+ Stop rendering and release resources. Requires a current context.
+
+ This is the equivalent of the cleanup operations that happen with a
+ real QQuickWindow when the window becomes hidden.
+
+ This function takes QQuickWindow::persistentSceneGraph() into
+ account, meaning that context-specific resources are not released
+ when persistency is enabled.
+
+ This function is called from the destructor. Therefore there will
+ typically be no need to call it directly. Pay attention however to
+ the fact that this requires the context, that was passed to
+ initialize(), to be the current one at the time of destroying the
+ QQuickRenderControl instance.
+
+ Once stop() has been called, it is possible to reuse the
+ QQuickRenderControl instance by calling initialize() again.
*/
void QQuickRenderControl::stop()
{
Q_D(QQuickRenderControl);
+ if (!d->initialized)
+ return;
+
if (!d->window)
return;
+ if (!QOpenGLContext::currentContext())
+ return;
+
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
cd->fireAboutToStop();
cd->cleanupNodesOnShutdown();
@@ -182,10 +284,12 @@ void QQuickRenderControl::stop()
d->rc->invalidate();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
}
+
+ d->initialized = false;
}
/*!
- Render the scenegraph using the current context.
+ Renders the scenegraph using the current context.
*/
void QQuickRenderControl::render()
{
@@ -197,7 +301,6 @@ void QQuickRenderControl::render()
cd->renderSceneGraph(d->window->size());
}
-
/*!
\fn void QQuickRenderControl::renderRequested()
@@ -212,7 +315,9 @@ void QQuickRenderControl::render()
true, then render() needs to be called.
*/
-
+/*!
+ Grabs the contents of the scene and returns it as an image.
+ */
QImage QQuickRenderControl::grab()
{
Q_D(QQuickRenderControl);
@@ -224,47 +329,16 @@ QImage QQuickRenderControl::grab()
return grabContent;
}
-QSGContext *QQuickRenderControl::sceneGraphContext() const
-{
- Q_D(const QQuickRenderControl);
- return d->sg;
-}
-
-QSGRenderContext *QQuickRenderControl::renderContext(QSGContext *) const
+void QQuickRenderControlPrivate::update()
{
- Q_D(const QQuickRenderControl);
- return d->rc;
+ Q_Q(QQuickRenderControl);
+ emit q->renderRequested();
}
-void QQuickRenderControl::setWindow(QQuickWindow *window)
+void QQuickRenderControlPrivate::maybeUpdate()
{
- Q_D(QQuickRenderControl);
- d->window = window;
-}
-
-/*!
- Returns the offscreen window.
- */
-
-QQuickWindow *QQuickRenderControl::window() const
-{
- Q_D(const QQuickRenderControl);
- return d->window;
-}
-
-/*!
- Create an offscreen QQuickWindow for this render control,
- unless the render control already has a window().
-
- Returns the offscreen window if one is created, otherwise returns null.
- The caller takes ownership of the window, and is responsible for deleting it.
- */
-QQuickWindow *QQuickRenderControl::createOffscreenWindow()
-{
- Q_D(QQuickRenderControl);
- if (!d->window)
- return new QQuickWindow(this);
- return 0;
+ Q_Q(QQuickRenderControl);
+ emit q->sceneChanged();
}
/*!
@@ -284,7 +358,6 @@ QQuickWindow *QQuickRenderControl::createOffscreenWindow()
inside its window.
*/
-
QWindow *QQuickRenderControl::renderWindowFor(QQuickWindow *win, QPoint *offset)
{
if (!win)
@@ -295,6 +368,4 @@ QWindow *QQuickRenderControl::renderWindowFor(QQuickWindow *win, QPoint *offset)
return 0;
}
-
-
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickrendercontrol.h b/src/quick/items/qquickrendercontrol.h
new file mode 100644
index 0000000000..e5c04fee23
--- /dev/null
+++ b/src/quick/items/qquickrendercontrol.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKRENDERCONTROL_H
+#define QQUICKRENDERCONTROL_H
+
+#include <QtQuick/qtquickglobal.h>
+#include <QtGui/QImage>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickWindow;
+class QOpenGLContext;
+class QQuickRenderControlPrivate;
+
+class Q_QUICK_EXPORT QQuickRenderControl : public QObject
+{
+ Q_OBJECT
+
+public:
+ QQuickRenderControl(QObject *parent = 0);
+ ~QQuickRenderControl();
+
+ void initialize(QOpenGLContext *gl);
+ void stop();
+
+ void polishItems();
+ void render();
+ bool sync();
+
+ QImage grab();
+
+ static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = 0);
+ virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return 0; }
+
+Q_SIGNALS:
+ void renderRequested();
+ void sceneChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QQuickRenderControl)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKRENDERCONTROL_H
diff --git a/src/quick/items/qquickrendercontrol_p.h b/src/quick/items/qquickrendercontrol_p.h
index cc30e37724..18b1b370b3 100644
--- a/src/quick/items/qquickrendercontrol_p.h
+++ b/src/quick/items/qquickrendercontrol_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -42,55 +42,45 @@
#ifndef QQUICKRENDERCONTROL_P_H
#define QQUICKRENDERCONTROL_P_H
-#include <QtGui/QImage>
-#include <private/qtquickglobal_p.h>
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
-QT_BEGIN_NAMESPACE
+#include "qquickrendercontrol.h"
+#include <QtQuick/private/qsgcontext_p.h>
-class QQuickWindow;
-class QSGContext;
-class QSGRenderContext;
-class QAnimationDriver;
-class QOpenGLContext;
-class QQuickRenderControlPrivate;
+QT_BEGIN_NAMESPACE
-class Q_QUICK_PRIVATE_EXPORT QQuickRenderControl : public QObject
+class QQuickRenderControlPrivate : public QObjectPrivate
{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QQuickRenderControl)
public:
- QQuickRenderControl();
- ~QQuickRenderControl();
+ Q_DECLARE_PUBLIC(QQuickRenderControl)
- QQuickWindow *window() const;
- QQuickWindow *createOffscreenWindow();
- virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return 0; }
- static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = 0);
+ QQuickRenderControlPrivate();
+ ~QQuickRenderControlPrivate();
- void windowDestroyed();
+ static QQuickRenderControlPrivate *get(QQuickRenderControl *renderControl) {
+ return renderControl->d_func();
+ }
- void initialize(QOpenGLContext *gl);
- void invalidate();
- void polishItems();
- void render();
- bool sync();
- void stop();
+ static void cleanup();
- QImage grab();
-
-Q_SIGNALS:
- void renderRequested();
- void sceneChanged();
+ void windowDestroyed();
-private:
- friend class QQuickWindowPrivate;
- friend class QQuickWindow;
- void setWindow(QQuickWindow *window);
- inline void update() { /*emit*/ renderRequested(); }
- inline void maybeUpdate() { /*emit*/ sceneChanged(); }
+ void update();
+ void maybeUpdate();
- QSGContext *sceneGraphContext() const;
- QSGRenderContext *renderContext(QSGContext *) const;
+ bool initialized;
+ QQuickWindow *window;
+ static QSGContext *sg;
+ QSGRenderContext *rc;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 82897b3f5e..de8eb115dc 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -287,7 +287,7 @@ void QQuickWindow::update()
if (d->windowManager)
d->windowManager->update(this);
else if (d->renderControl)
- d->renderControl->update();
+ QQuickRenderControlPrivate::get(d->renderControl)->update();
}
void forcePolishHelper(QQuickItem *item)
@@ -438,7 +438,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
customRenderMode = qgetenv("QSG_VISUALIZE");
renderControl = control;
if (renderControl)
- renderControl->setWindow(q);
+ QQuickRenderControlPrivate::get(renderControl)->window = q;
if (!renderControl)
windowManager = QSGRenderLoop::instance();
@@ -447,8 +447,9 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
QSGContext *sg;
if (renderControl) {
- sg = renderControl->sceneGraphContext();
- context = renderControl->renderContext(sg);
+ QQuickRenderControlPrivate *renderControlPriv = QQuickRenderControlPrivate::get(renderControl);
+ sg = renderControlPriv->sg;
+ context = renderControlPriv->rc;
} else {
windowManager->addWindow(q);
sg = windowManager->sceneGraphContext();
@@ -1087,7 +1088,7 @@ QQuickWindow::~QQuickWindow()
d->animationController->deleteLater();
if (d->renderControl) {
- d->renderControl->windowDestroyed();
+ QQuickRenderControlPrivate::get(d->renderControl)->windowDestroyed();
} else if (d->windowManager) {
d->windowManager->removeWindow(this);
d->windowManager->windowDestroyed(this);
@@ -1125,8 +1126,9 @@ void QQuickWindow::releaseResources()
/*!
- Sets whether the OpenGL context can be released to \a
- persistent. The default value is true.
+ Sets whether the OpenGL context should be preserved, and cannot be
+ released until the last window is deleted, to \a persistent. The
+ default value is true.
The OpenGL context can be released to free up graphics resources
when the window is obscured, hidden or not rendering. When this
@@ -2798,7 +2800,7 @@ void QQuickWindow::maybeUpdate()
{
Q_D(QQuickWindow);
if (d->renderControl)
- d->renderControl->maybeUpdate();
+ QQuickRenderControlPrivate::get(d->renderControl)->maybeUpdate();
else if (d->windowManager)
d->windowManager->maybeUpdate(this);
}
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index c95ec5b46d..4ed663ee6e 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -87,6 +87,7 @@ public:
Q_ENUMS(SceneGraphError)
QQuickWindow(QWindow *parent = 0);
+ explicit QQuickWindow(QQuickRenderControl *renderControl);
virtual ~QQuickWindow();
@@ -201,7 +202,6 @@ private:
friend class QQuickWidget;
friend class QQuickRenderControl;
friend class QQuickAnimatorController;
- explicit QQuickWindow(QQuickRenderControl*);
Q_DISABLE_COPY(QQuickWindow)
};
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index f91d512ab0..dc6b872fb2 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -72,7 +72,7 @@ class QQuickWidgetRenderControl : public QQuickRenderControl
{
public:
QQuickWidgetRenderControl(QQuickWidget *quickwidget) : m_quickWidget(quickwidget) {}
- QWindow *renderWindow(QPoint *offset) {
+ QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE {
if (offset)
*offset = m_quickWidget->mapTo(m_quickWidget->window(), QPoint());
return m_quickWidget->window()->windowHandle();
@@ -86,7 +86,7 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
Q_Q(QQuickWidget);
renderControl = new QQuickWidgetRenderControl(q);
- offscreenWindow = renderControl->createOffscreenWindow();
+ offscreenWindow = new QQuickWindow(renderControl);
offscreenWindow->setTitle(QString::fromLatin1("Offscreen"));
// Do not call create() on offscreenWindow.
@@ -162,8 +162,8 @@ QQuickWidgetPrivate::~QQuickWidgetPrivate()
// context and offscreenSurface are current at this stage, if the context was created.
Q_ASSERT(!context || (QOpenGLContext::currentContext() == context && context->surface() == offscreenSurface));
+ delete renderControl; // always delete the rendercontrol first
delete offscreenWindow;
- delete renderControl;
delete resolvedFbo;
delete fbo;
@@ -877,7 +877,7 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
d->createContext();
createFramebufferObject();
- d->offscreenWindow->resizeEvent(e);
+ QCoreApplication::sendEvent(d->offscreenWindow, e);
d->offscreenWindow->setGeometry(0, 0, e->size().width(), e->size().height());
QOpenGLContext *context = d->offscreenWindow->openglContext();
@@ -898,7 +898,7 @@ void QQuickWidget::keyPressEvent(QKeyEvent *e)
Q_D(QQuickWidget);
Q_QUICK_PROFILE(addEvent<QQuickProfiler::Key>());
- d->offscreenWindow->keyPressEvent(e);
+ QCoreApplication::sendEvent(d->offscreenWindow, e);
}
/*! \reimp */
@@ -907,7 +907,7 @@ void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
Q_D(QQuickWidget);
Q_QUICK_PROFILE(addEvent<QQuickProfiler::Key>());
- d->offscreenWindow->keyReleaseEvent(e);
+ QCoreApplication::sendEvent(d->offscreenWindow, e);
}
/*! \reimp */
@@ -921,7 +921,7 @@ void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
// the windowPos in e is ignored and is replaced by localPos. This is necessary
// because QQuickWindow thinks of itself as a top-level window always.
QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
- d->offscreenWindow->mouseMoveEvent(&mappedEvent);
+ QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
}
/*! \reimp */
@@ -934,10 +934,10 @@ void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
// See QTBUG-25831
QMouseEvent pressEvent(QEvent::MouseButtonPress, e->localPos(), e->screenPos(), e->button(),
e->buttons(), e->modifiers());
- d->offscreenWindow->mousePressEvent(&pressEvent);
+ QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(),
e->modifiers());
- d->offscreenWindow->mouseDoubleClickEvent(&mappedEvent);
+ QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
}
/*! \reimp */
@@ -963,7 +963,7 @@ void QQuickWidget::mousePressEvent(QMouseEvent *e)
Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
- d->offscreenWindow->mousePressEvent(&mappedEvent);
+ QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
}
/*! \reimp */
@@ -973,7 +973,7 @@ void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
- d->offscreenWindow->mouseReleaseEvent(&mappedEvent);
+ QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
}
#ifndef QT_NO_WHEELEVENT
@@ -984,7 +984,7 @@ void QQuickWidget::wheelEvent(QWheelEvent *e)
Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
// Wheel events only have local and global positions, no need to map.
- d->offscreenWindow->wheelEvent(e);
+ QCoreApplication::sendEvent(d->offscreenWindow, e);
}
#endif
@@ -1027,7 +1027,8 @@ bool QQuickWidget::event(QEvent *e)
case QEvent::TouchUpdate:
case QEvent::TouchCancel:
// Touch events only have local and global positions, no need to map.
- return d->offscreenWindow->event(e);
+ return QCoreApplication::sendEvent(d->offscreenWindow, e);
+
case QEvent::WindowChangeInternal:
d->handleWindowChange();
break;