Skip to content

Commit 524fa09

Browse files
committed
Fix RenderBufferBlitter z-order error if enabled depth test
1 parent 335feb2 commit 524fa09

File tree

3 files changed

+78
-14
lines changed

3 files changed

+78
-14
lines changed

src/server/qtquick/private/wbufferrenderer.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <private/qrhigles2_p.h>
3434
#include <private/qopenglcontext_p.h>
3535
#endif
36+
#include <private/qsgbatchrenderer_p.h>
3637

3738
#include <pixman.h>
3839
#include <drm_fourcc.h>
@@ -233,6 +234,12 @@ QSGRenderer *WBufferRenderer::currentRenderer() const
233234
return state.renderer;
234235
}
235236

237+
QSGBatchRenderer::Renderer *WBufferRenderer::currentBatchRenderer() const
238+
{
239+
Q_ASSERT(state.renderer == state.batchRenderer);
240+
return state.batchRenderer;
241+
}
242+
236243
qreal WBufferRenderer::currentDevicePixelRatio() const
237244
{
238245
return state.devicePixelRatio;
@@ -433,6 +440,7 @@ void WBufferRenderer::render(int sourceIndex, const QMatrix4x4 &renderMatrix,
433440

434441
const qreal devicePixelRatio = state.devicePixelRatio;
435442
state.renderer = renderer;
443+
state.batchRenderer = dynamic_cast<QSGBatchRenderer::Renderer*>(renderer);
436444
state.worldTransform = renderMatrix;
437445
// The renderer should always receive the window's DPR (Device Pixel Ratio)
438446
// because, regardless of the DPR used for rendering, all resources within
@@ -628,6 +636,7 @@ void WBufferRenderer::endRender()
628636
auto buffer = state.buffer;
629637
state.buffer = nullptr;
630638
state.renderer = nullptr;
639+
state.batchRenderer = nullptr;
631640

632641
m_lastBuffer = buffer;
633642
m_damageRing.rotate();

src/server/qtquick/private/wbufferrenderer_p.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ Q_MOC_INCLUDE(<private/qsgplaintexture_p.h>)
1919
QT_BEGIN_NAMESPACE
2020
class QSGPlainTexture;
2121
class QSGRenderContext;
22+
namespace QSGBatchRenderer {
23+
class Renderer;
24+
}
2225
QT_END_NAMESPACE
2326

2427
QW_BEGIN_NAMESPACE
@@ -68,6 +71,7 @@ class WAYLIB_SERVER_EXPORT WBufferRenderer : public QQuickItem
6871
void setClearColor(const QColor &clearColor);
6972

7073
QSGRenderer *currentRenderer() const;
74+
QSGBatchRenderer::Renderer *currentBatchRenderer() const;
7175
qreal currentDevicePixelRatio() const;
7276
const QMatrix4x4 &currentWorldTransform() const;
7377
QW_NAMESPACE::qw_buffer *currentBuffer() const;
@@ -133,6 +137,7 @@ class WAYLIB_SERVER_EXPORT WBufferRenderer : public QQuickItem
133137
RenderFlags flags;
134138
QSGRenderContext *context;
135139
QSGRenderer *renderer;
140+
QSGBatchRenderer::Renderer *batchRenderer;
136141
QMatrix4x4 worldTransform;
137142
QSize pixelSize;
138143
qreal devicePixelRatio;

src/server/qtquick/private/wrenderbuffernode.cpp

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define protected public
66
#define private public
77
#include <private/qsgrenderer_p.h>
8+
#include <private/qsgbatchrenderer_p.h>
89
#undef protected
910
#undef private
1011

@@ -302,19 +303,22 @@ class Q_DECL_HIDDEN RhiManager : public DataManager<RhiManager, void>
302303
}
303304

304305
void sync(const QSize &pixelSize, QSGRootNode *rootNode,
305-
const QMatrix4x4 &matrix = {}, QSGRenderer *base = nullptr,
306-
const QVector2D &dpr = {}) {
306+
const QMatrix4x4 &matrix = {}, const QMatrix4x4 &baseProjectionMatrix = {},
307+
QSGRenderer *base = nullptr, const QVector2D &dpr = {}) {
307308
Q_ASSERT(!renderer->rootNode());
308309

309310
if (base) {
310311
renderer->setDevicePixelRatio(base->devicePixelRatio());
311312
renderer->setDeviceRect(base->deviceRect());
312313
renderer->setViewportRect(base->viewportRect());
314+
315+
// The m22 and m23 is control the z-order for depth test.
316+
// If have a base QSGRenderer, we should inherit the depth test from
317+
// baseProjectionMatrix.
318+
renderer->setProjectionMatrix(baseProjectionMatrix);
313319
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
314-
renderer->setProjectionMatrix(base->projectionMatrix(0));
315320
renderer->setProjectionMatrixWithNativeNDC(base->projectionMatrixWithNativeNDC(0));
316321
#else
317-
renderer->setProjectionMatrix(base->projectionMatrix());
318322
renderer->setProjectionMatrixWithNativeNDC(base->projectionMatrixWithNativeNDC());
319323
#endif
320324
} else {
@@ -360,28 +364,53 @@ class Q_DECL_HIDDEN RhiManager : public DataManager<RhiManager, void>
360364
return true;
361365
}
362366

363-
bool render(qreal oldDPR, QRhiCommandBuffer* &oldCB) {
367+
bool render(qreal oldDPR, QRhiCommandBuffer* &oldCB, bool forceDepthTest = false) {
364368
Q_ASSERT(renderer->m_is_rendering);
365369
renderer->render();
366370
renderer->m_is_rendering = false;
367371
renderer->m_changed_emitted = false;
368372

369373
context->prepareSync(oldDPR, oldCB, graphicsConfiguration());
374+
bool ok = false;
375+
376+
do {
377+
if (forceDepthTest && Q_LIKELY(isBatchRenderer)) {
378+
auto batchRenderer = static_cast<QSGBatchRenderer::Renderer*>(renderer);
379+
if (auto sm = batchRenderer->m_shaderManager) {
380+
if (Q_LIKELY(!sm->pipelineCache.isEmpty())) {
381+
QVector<std::pair<QRhiGraphicsPipeline*, bool>> tmp;
382+
tmp.reserve(sm->pipelineCache.size());
383+
384+
for (auto pipeline : std::as_const(sm->pipelineCache)) {
385+
tmp.append({pipeline, pipeline->hasDepthTest()});
386+
pipeline->setDepthTest(true);
387+
}
388+
ok = rhi()->endOffscreenFrame() == QRhi::FrameOpSuccess;
389+
Q_ASSERT(tmp.size() == sm->pipelineCache.size());
390+
for (auto i : std::as_const(tmp))
391+
i.first->setDepthTest(i.second);
392+
393+
break;
394+
}
395+
}
396+
}
397+
398+
ok = rhi()->endOffscreenFrame() == QRhi::FrameOpSuccess;
399+
} while (false);
370400

371-
bool ok = rhi()->endOffscreenFrame() == QRhi::FrameOpSuccess;
372401
renderer->setRootNode(nullptr);
373402

374403
return ok;
375404
}
376405

377-
inline bool render(QRhiRenderTarget *rt) {
406+
inline bool render(QRhiRenderTarget *rt, bool forceDepthTest = false) {
378407
qreal oldDPR;
379408
QRhiCommandBuffer *oldCB;
380409

381410
if (!preprocess(rt, oldDPR, oldCB))
382411
return false;
383412

384-
return render(oldDPR, oldCB);
413+
return render(oldDPR, oldCB, forceDepthTest);
385414
}
386415

387416
private:
@@ -404,7 +433,13 @@ class Q_DECL_HIDDEN RhiManager : public DataManager<RhiManager, void>
404433
m_rhi->offscreenSurface = fallbackSurface.release();
405434

406435
context = QQuickWindowPrivate::get(owner)->context;
436+
// Don't use RenderMode2D, when use this renderer on an exists renderTarget
437+
// we need to ensure the renderer don't overwrite the depth buffer, because
438+
// the exists renderTarget is using in the other QSGRenderer, maybe that
439+
// renderer is using depth test, and the other QSGRenderer is not finished render.
440+
// For an example: RhiNode to render its content nodes on an exists renderTarget.
407441
renderer = context->createRenderer(QSGRendererInterface::RenderMode2DNoDepthBuffer);
442+
isBatchRenderer = dynamic_cast<QSGBatchRenderer::Renderer*>(renderer);
408443
}
409444

410445
~RhiManager() {
@@ -447,6 +482,7 @@ class Q_DECL_HIDDEN RhiManager : public DataManager<RhiManager, void>
447482

448483
QSGRenderContext *context;
449484
QSGRenderer *renderer;
485+
bool isBatchRenderer = false;
450486

451487
QScopedPointer<Rhi> m_rhi;
452488
};
@@ -523,6 +559,17 @@ class Q_DECL_HIDDEN RhiNode : public WRenderBufferNode {
523559
return {0};
524560
}
525561

562+
// ###: Should disable DepthAwareRendering here, because
563+
// if enable depth test, Qt will render the opaque nodes first,
564+
// maybe an opaque node's z-order is higher than the render node,
565+
// will get the wrong texture when copy texture in RhiNode::render.
566+
// But the opaque node will be cover the wrong area to the
567+
// RhiNode::renderTarget after RhiNode::render, but if you using
568+
// MultiEffect's blur effect for the copied texture, the blur result
569+
// will contains the opaque node's contains. Fortunately, this kind
570+
// of problem is not very obvious.
571+
//
572+
// We should fix this bug in Qt in the future.
526573
RenderingFlags flags() const override {
527574
if (Q_UNLIKELY(!contentNode))
528575
return BoundedRectRendering | DepthAwareRendering;
@@ -672,7 +719,7 @@ class Q_DECL_HIDDEN RhiNode : public WRenderBufferNode {
672719
const QPointF sourcePos = renderMatrix.map(m_rect.topLeft());
673720
renderData->imageNode->setRect(QRectF(-(devicePixelRatio - 1) * sourcePos, ct->pixelSize()));
674721

675-
rhi->sync(texture->data->pixelSize(), &renderData->rootNode, renderMatrix.inverted(), nullptr,
722+
rhi->sync(texture->data->pixelSize(), &renderData->rootNode, renderMatrix.inverted(), {}, nullptr,
676723
{texture->data->pixelSize().width() / float(m_rect.width() * devicePixelRatio),
677724
texture->data->pixelSize().height() / float(m_rect.height() * devicePixelRatio)});
678725
rhi->render(renderData->rt.get());
@@ -707,6 +754,10 @@ class Q_DECL_HIDDEN RhiNode : public WRenderBufferNode {
707754
textureRT->setFlags(QRhiTextureRenderTarget::PreserveColorContents
708755
| QRhiTextureRenderTarget::PreserveDepthStencilContents);
709756
auto currentRenderer = maybeBufferRenderer();
757+
// If the source renderer enable depth test, we should enable depth test also,
758+
// to ensure the contentNode's z order on RenderMode2DNoDepthBuffer render mode.
759+
const bool forceDepthTest = currentRenderer->currentBatchRenderer()
760+
&& currentRenderer->currentBatchRenderer()->useDepthBuffer();
710761

711762
if (clipList() || inheritedOpacity() < 1.0) {
712763
if (!node)
@@ -736,7 +787,7 @@ class Q_DECL_HIDDEN RhiNode : public WRenderBufferNode {
736787

737788
overrideChildNodesTo(contentNode, childContainer);
738789

739-
rhi->sync(ct->pixelSize(), &node->rootNode, {},
790+
rhi->sync(ct->pixelSize(), &node->rootNode, {}, *projectionMatrix(),
740791
currentRenderer ? currentRenderer->currentRenderer() : nullptr);
741792
qreal oldDPR;
742793
QRhiCommandBuffer *oldCB;
@@ -753,16 +804,15 @@ class Q_DECL_HIDDEN RhiNode : public WRenderBufferNode {
753804
}
754805
}
755806

756-
rhi->render(oldDPR, oldCB);
807+
rhi->render(oldDPR, oldCB, forceDepthTest);
757808
}
758809

759810
restoreChildNodesTo(childContainer, contentNode);
760811
} else {
761812
node.reset();
762-
763-
rhi->sync(ct->pixelSize(), contentNode, *this->matrix(),
813+
rhi->sync(ct->pixelSize(), contentNode, *this->matrix(), *projectionMatrix(),
764814
currentRenderer ? currentRenderer->currentRenderer() : nullptr);
765-
rhi->render(textureRT);
815+
rhi->render(textureRT, forceDepthTest);
766816
}
767817

768818
textureRT->setFlags(saveFlags);

0 commit comments

Comments
 (0)