diff options
-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; |