diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-06-25 16:37:58 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-07-04 19:49:08 +0200 |
commit | 192d4fa0af5f40f76979f195c4356b26eaed1696 (patch) | |
tree | e4df789d370b45b5a84f0b971b21ce3c2640fa2c | |
parent | fc40f0738e55725d4449059578510802dbf596ec (diff) |
Make openglunderqml functional with and without the rhi
It has to be written following the new split approach (beforeRendering
for resource setup, beforeRenderPassRecording to issue the actual
underlay draw calls), but it will then work both with and
without QSG_RHI=1.
Change-Id: I9b7b35434aa0caec543cae268064b2684256382d
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r-- | examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc | 34 | ||||
-rw-r--r-- | examples/quick/scenegraph/openglunderqml/squircle.cpp | 31 | ||||
-rw-r--r-- | examples/quick/scenegraph/openglunderqml/squircle.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 33 | ||||
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 6 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgcontext.cpp | 28 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgcontext_p.h | 23 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgdefaultrendercontext.cpp | 25 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgdefaultrendercontext_p.h | 18 |
9 files changed, 137 insertions, 62 deletions
diff --git a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc index 778b754869..69a9d2ce4b 100644 --- a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc +++ b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc @@ -94,17 +94,18 @@ \snippet scenegraph/openglunderqml/squircle.cpp 3 - The default behavior of the scene graph is to clear the - framebuffer before rendering. Since we render before the scene - graph, we need to turn this clearing off. This means that we need - to clear ourselves in the \c paint() function. + The default behavior of the scene graph is to clear the framebuffer before + rendering. This is fine since we will insert our own rendering code after + this clear is enqueued. Make sure however that we clear to the desired + color (black). \snippet scenegraph/openglunderqml/squircle.cpp 9 - We use the \c sync() function to initialize the renderer and to - copy the state in our item into the renderer. When the renderer is - created, we also connect the \l QQuickWindow::beforeRendering() to - the renderer's \c paint() slot. + We use the \c sync() function to initialize the renderer and to copy the + state in our item into the renderer. When the renderer is created, we also + connect the \l QQuickWindow::beforeRendering() and \l + QQuickWindow::beforeRenderPassRecording() to the renderer's \c init() and + \c paint() slots. \note The \l QQuickWindow::beforeSynchronizing() signal is emitted on the rendering thread while the GUI thread is blocked, so it is @@ -127,22 +128,13 @@ \snippet scenegraph/openglunderqml/squircle.cpp 4 - In the SquircleRenderer's \c paint() function we start by - initializing the shader program. By initializing the shader - program here, we make sure that the OpenGL context is bound and - that we are on the correct thread. + In the SquircleRenderer's \c init() function we start by initializing the + shader program if not yet done. The OpenGL context is current on the thread + when the slot is invoked. \snippet scenegraph/openglunderqml/squircle.cpp 5 - We use the shader program to draw the squircle. At the end of the - \c paint function we release the program and disable the - attributes we used so that the OpenGL context is in a "clean" - state for the scene graph to pick it up. - - \note If tracking the changes in the OpenGL context's state is not - feasible, one can use the function \l - QQuickWindow::resetOpenGLState() which will reset all state that - the scene graph relies on. + We use the shader program to draw the squircle in \c paint(). \snippet scenegraph/openglunderqml/main.cpp 1 diff --git a/examples/quick/scenegraph/openglunderqml/squircle.cpp b/examples/quick/scenegraph/openglunderqml/squircle.cpp index 4e5848be2a..828857fe24 100644 --- a/examples/quick/scenegraph/openglunderqml/squircle.cpp +++ b/examples/quick/scenegraph/openglunderqml/squircle.cpp @@ -83,10 +83,9 @@ void Squircle::handleWindowChanged(QQuickWindow *win) connect(win, &QQuickWindow::beforeSynchronizing, this, &Squircle::sync, Qt::DirectConnection); connect(win, &QQuickWindow::sceneGraphInvalidated, this, &Squircle::cleanup, Qt::DirectConnection); //! [1] - // If we allow QML to do the clearing, they would clear what we paint - // and nothing would show. //! [3] - win->setClearBeforeRendering(false); + // Ensure we start with cleared to black. The squircle's blend mode relies on this. + win->setColor(Qt::black); } } //! [3] @@ -124,7 +123,8 @@ void Squircle::sync() { if (!m_renderer) { m_renderer = new SquircleRenderer(); - connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::paint, Qt::DirectConnection); + connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::init, Qt::DirectConnection); + connect(window(), &QQuickWindow::beforeRenderPassRecording, m_renderer, &SquircleRenderer::paint, Qt::DirectConnection); } m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio()); m_renderer->setT(m_t); @@ -133,9 +133,12 @@ void Squircle::sync() //! [9] //! [4] -void SquircleRenderer::paint() +void SquircleRenderer::init() { if (!m_program) { + QSGRendererInterface *rif = m_window->rendererInterface(); + Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::OpenGL || rif->graphicsApi() == QSGRendererInterface::OpenGLRhi); + initializeOpenGLFunctions(); m_program = new QOpenGLShaderProgram(); @@ -160,7 +163,15 @@ void SquircleRenderer::paint() m_program->link(); } +} + //! [4] //! [5] +void SquircleRenderer::paint() +{ + // Play nice with the RHI. Not strictly needed when the scenegraph uses + // OpenGL directly. + m_window->beginExternalCommands(); + m_program->bind(); m_program->enableAttributeArray(0); @@ -171,6 +182,11 @@ void SquircleRenderer::paint() -1, 1, 1, 1 }; + + // This example relies on (deprecated) client-side pointers for the vertex + // input. Therefore, we have to make sure no vertex buffer is bound. + glBindBuffer(GL_ARRAY_BUFFER, 0); + m_program->setAttributeArray(0, GL_FLOAT, values, 2); m_program->setUniformValue("t", (float) m_t); @@ -178,9 +194,6 @@ void SquircleRenderer::paint() glDisable(GL_DEPTH_TEST); - glClearColor(0, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); @@ -192,5 +205,7 @@ void SquircleRenderer::paint() // Not strictly needed for this example, but generally useful for when // mixing with raw OpenGL. m_window->resetOpenGLState(); + + m_window->endExternalCommands(); } //! [5] diff --git a/examples/quick/scenegraph/openglunderqml/squircle.h b/examples/quick/scenegraph/openglunderqml/squircle.h index 962ba21101..1b9995bc1e 100644 --- a/examples/quick/scenegraph/openglunderqml/squircle.h +++ b/examples/quick/scenegraph/openglunderqml/squircle.h @@ -70,6 +70,7 @@ public: void setWindow(QQuickWindow *window) { m_window = window; } public slots: + void init(); void paint(); private: diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 0adfbdb922..c51cfc8ac1 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -474,13 +474,18 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa if (rhi) { // ### no offscreen ("renderTargetId") support yet - context->beginRhiFrame(renderer, - swapchain->currentFrameRenderTarget(), - rpDescForSwapchain, - swapchain->currentFrameCommandBuffer(), - emitBeforeRenderPassRecording, - emitAfterRenderPassRecording, - q); + context->beginNextRhiFrame(renderer, + swapchain->currentFrameRenderTarget(), + rpDescForSwapchain, + swapchain->currentFrameCommandBuffer(), + emitBeforeRenderPassRecording, + emitAfterRenderPassRecording, + q); + } else { + context->beginNextFrame(renderer, + emitBeforeRenderPassRecording, + emitAfterRenderPassRecording, + q); } animationController->advance(); @@ -528,7 +533,9 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa runAndClearJobs(&afterRenderingJobs); if (rhi) - context->endRhiFrame(renderer); + context->endNextRhiFrame(renderer); + else + context->endNextFrame(renderer); } QQuickWindowPrivate::QQuickWindowPrivate() @@ -4202,6 +4209,11 @@ QQmlIncubationController *QQuickWindow::incubationController() const attached images). The native graphics objects can be queried via QSGRendererInterface. + When not running with the RHI (and using OpenGL directly), the signal is + emitted after the renderer has cleared the render target. This makes it + possible to create appliations that function identically both with and + without the RHI. + \note Resource updates (uploads, copies) typically cannot be enqueued from within a render pass. Therefore, more complex user rendering will need to connect to both the beforeRendering() and this signals. @@ -4228,6 +4240,11 @@ QQmlIncubationController *QQuickWindow::incubationController() const the attached images). The native graphics objects can be queried via QSGRendererInterface. + When not running with the RHI (and using OpenGL directly), the signal is + emitted after the renderer has finished its rendering, but before + afterRendering(). This makes it possible to create appliations that + function identically both with and without the RHI. + \note Resource updates (uploads, copies) typically cannot be enqueued from within a render pass. Therefore, more complex user rendering will need to connect to both the beforeRendering() and this signals. diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index eab40bb253..14ab7f9393 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -3984,6 +3984,9 @@ void Renderer::renderBatches() bindable()->clear(clearMode()); + if (m_renderPassRecordingCallbacks.start) + m_renderPassRecordingCallbacks.start(m_renderPassRecordingCallbacks.userData); + if (Q_LIKELY(renderOpaque)) { for (int i=0; i<m_opaqueBatches.size(); ++i) { Batch *b = m_opaqueBatches.at(i); @@ -4020,6 +4023,9 @@ void Renderer::renderBatches() glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDepthMask(true); + if (m_renderPassRecordingCallbacks.end) + m_renderPassRecordingCallbacks.end(m_renderPassRecordingCallbacks.userData); + } else { // RHI path diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index a5d9391034..97fd49e4c7 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -341,11 +341,27 @@ void QSGRenderContext::invalidate() { } -void QSGRenderContext::beginRhiFrame(QSGRenderer *renderer, QRhiRenderTarget *rt, QRhiRenderPassDescriptor *rp, - QRhiCommandBuffer *cb, - RenderPassCallback mainPassRecordingStart, - RenderPassCallback mainPassRecordingEnd, - void *callbackUserData) +void QSGRenderContext::beginNextFrame(QSGRenderer *renderer, + RenderPassCallback mainPassRecordingStart, + RenderPassCallback mainPassRecordingEnd, + void *callbackUserData) +{ + Q_UNUSED(renderer); + Q_UNUSED(mainPassRecordingStart); + Q_UNUSED(mainPassRecordingEnd); + Q_UNUSED(callbackUserData); +} + +void QSGRenderContext::endNextFrame(QSGRenderer *renderer) +{ + Q_UNUSED(renderer); +} + +void QSGRenderContext::beginNextRhiFrame(QSGRenderer *renderer, + QRhiRenderTarget *rt, QRhiRenderPassDescriptor *rp, QRhiCommandBuffer *cb, + RenderPassCallback mainPassRecordingStart, + RenderPassCallback mainPassRecordingEnd, + void *callbackUserData) { Q_UNUSED(renderer); Q_UNUSED(rt); @@ -361,7 +377,7 @@ void QSGRenderContext::renderNextRhiFrame(QSGRenderer *renderer) Q_UNUSED(renderer); } -void QSGRenderContext::endRhiFrame(QSGRenderer *renderer) +void QSGRenderContext::endNextRhiFrame(QSGRenderer *renderer) { Q_UNUSED(renderer); } diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index c731baeb74..4e712ab7c3 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -171,15 +171,24 @@ public: struct InitParams { }; virtual void initialize(const InitParams *params); virtual void invalidate(); - virtual void renderNextFrame(QSGRenderer *renderer, uint fboId) = 0; // legacy, GL-only + using RenderPassCallback = void (*)(void *); - virtual void beginRhiFrame(QSGRenderer *renderer, QRhiRenderTarget *rt, QRhiRenderPassDescriptor *rp, - QRhiCommandBuffer *cb, - RenderPassCallback mainPassRecordingStart, - RenderPassCallback mainPassRecordingEnd, - void *callbackUserData); // RHI only + + virtual void beginNextFrame(QSGRenderer *renderer, + RenderPassCallback mainPassRecordingStart, + RenderPassCallback mainPassRecordingEnd, + void *callbackUserData); + virtual void renderNextFrame(QSGRenderer *renderer, uint fboId) = 0; + virtual void endNextFrame(QSGRenderer *renderer); + + virtual void beginNextRhiFrame(QSGRenderer *renderer, + QRhiRenderTarget *rt, QRhiRenderPassDescriptor *rp, QRhiCommandBuffer *cb, + RenderPassCallback mainPassRecordingStart, + RenderPassCallback mainPassRecordingEnd, + void *callbackUserData); virtual void renderNextRhiFrame(QSGRenderer *renderer); - virtual void endRhiFrame(QSGRenderer *renderer); // RHI only + virtual void endNextRhiFrame(QSGRenderer *renderer); + virtual void endSync(); virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font); diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp index e0f1b1b0c3..b6f35b8580 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp +++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp @@ -201,6 +201,14 @@ void QSGDefaultRenderContext::invalidate() static QBasicMutex qsg_framerender_mutex; +void QSGDefaultRenderContext::beginNextFrame(QSGRenderer *renderer, + RenderPassCallback mainPassRecordingStart, + RenderPassCallback mainPassRecordingEnd, + void *callbackUserData) +{ + renderer->setRenderPassRecordingCallbacks(mainPassRecordingStart, mainPassRecordingEnd, callbackUserData); +} + void QSGDefaultRenderContext::renderNextFrame(QSGRenderer *renderer, uint fboId) { if (m_serializedRender) @@ -212,11 +220,16 @@ void QSGDefaultRenderContext::renderNextFrame(QSGRenderer *renderer, uint fboId) qsg_framerender_mutex.unlock(); } -void QSGDefaultRenderContext::beginRhiFrame(QSGRenderer *renderer, QRhiRenderTarget *rt, QRhiRenderPassDescriptor *rp, - QRhiCommandBuffer *cb, - RenderPassCallback mainPassRecordingStart, - RenderPassCallback mainPassRecordingEnd, - void *callbackUserData) +void QSGDefaultRenderContext::endNextFrame(QSGRenderer *renderer) +{ + Q_UNUSED(renderer); +} + +void QSGDefaultRenderContext::beginNextRhiFrame(QSGRenderer *renderer, QRhiRenderTarget *rt, QRhiRenderPassDescriptor *rp, + QRhiCommandBuffer *cb, + RenderPassCallback mainPassRecordingStart, + RenderPassCallback mainPassRecordingEnd, + void *callbackUserData) { Q_ASSERT(!m_currentFrameCommandBuffer); @@ -233,7 +246,7 @@ void QSGDefaultRenderContext::renderNextRhiFrame(QSGRenderer *renderer) renderer->renderScene(); } -void QSGDefaultRenderContext::endRhiFrame(QSGRenderer *renderer) +void QSGDefaultRenderContext::endNextRhiFrame(QSGRenderer *renderer) { Q_UNUSED(renderer); m_currentFrameCommandBuffer = nullptr; diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h index 18698f51f3..79bc9dd76d 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h +++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h @@ -102,15 +102,21 @@ public: void initialize(const QSGRenderContext::InitParams *params) override; void invalidate() override; + + void beginNextFrame(QSGRenderer *renderer, + RenderPassCallback mainPassRecordingStart, + RenderPassCallback mainPassRecordingEnd, + void *callbackUserData) override; void renderNextFrame(QSGRenderer *renderer, uint fboId) override; + void endNextFrame(QSGRenderer *renderer) override; - void beginRhiFrame(QSGRenderer *renderer, QRhiRenderTarget *rt, QRhiRenderPassDescriptor *rp, - QRhiCommandBuffer *cb, - RenderPassCallback mainPassRecordingStart, - RenderPassCallback mainPassRecordingEnd, - void *callbackUserData) override; + void beginNextRhiFrame(QSGRenderer *renderer, + QRhiRenderTarget *rt, QRhiRenderPassDescriptor *rp, QRhiCommandBuffer *cb, + RenderPassCallback mainPassRecordingStart, + RenderPassCallback mainPassRecordingEnd, + void *callbackUserData) override; void renderNextRhiFrame(QSGRenderer *renderer) override; - void endRhiFrame(QSGRenderer *renderer) override; + void endNextRhiFrame(QSGRenderer *renderer) override; QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font) override; |