Skip to content

Commit 4ec8200

Browse files
committed
Fix WOutputLayer::PreserveColorContents invalid on software renderer
On the virtual machine, maybe compositor will fallback to use the software renderer, and cursor layer is force enable, you will see a black screen on the virtual machine's window. This issue is testd on VirtualBox.
1 parent 1546188 commit 4ec8200

File tree

5 files changed

+46
-27
lines changed

5 files changed

+46
-27
lines changed

examples/tinywl/surfacewrapper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,11 @@ bool SurfaceWrapper::startStateChangeAnimation(State targetState, const QRectF &
668668

669669
qreal SurfaceWrapper::radius() const
670670
{
671+
// RoundedClipEffect is use ShaderEffectSource to clip, its only
672+
// supports RHI backend.
673+
if (window()->sceneGraphBackend() == "software")
674+
return 0;
675+
671676
return m_radius;
672677
}
673678

src/server/qtquick/private/wbufferrenderer.cpp

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <qwrendererinterface.h>
1717

1818
#include <QSGImageNode>
19+
#include <QSGSimpleRectNode>
1920

2021
#define protected public
2122
#define private public
@@ -392,7 +393,19 @@ qw_buffer *WBufferRenderer::beginRender(const QSize &pixelSize, qreal devicePixe
392393

393394
if (rtd->type == QQuickRenderTargetPrivate::Type::PaintDevice) {
394395
sgRT.paintDevice = rtd->u.paintDevice;
396+
397+
// // For software renderer, update the dirty parts relative to the last paint device.
398+
PixmanRegion damage;
399+
m_damageRing.get_buffer_damage(bufferAge, damage);
400+
state.dirty = WTools::fromPixmanRegion(damage);
401+
402+
if (devicePixelRatio != 1.0) {
403+
state.dirty = QTransform::fromScale(1.0 / devicePixelRatio,
404+
1.0 / devicePixelRatio).map(state.dirty);
405+
}
395406
} else {
407+
state.dirty = QRegion();
408+
396409
Q_ASSERT(rtd->type == QQuickRenderTargetPrivate::Type::RhiRenderTarget);
397410
sgRT.rt = rtd->u.rhiRt;
398411
sgRT.cb = wd->redirect.commandBuffer;
@@ -415,7 +428,6 @@ qw_buffer *WBufferRenderer::beginRender(const QSize &pixelSize, qreal devicePixe
415428
state.pixelSize = pixelSize;
416429
state.devicePixelRatio = devicePixelRatio;
417430
state.bufferAge = bufferAge;
418-
state.lastRT = lastRT;
419431
state.buffer = buffer;
420432
state.renderTarget = rt;
421433
state.sgRenderTarget = sgRT;
@@ -470,6 +482,23 @@ void WBufferRenderer::render(int sourceIndex, const QMatrix4x4 &renderMatrix,
470482
auto softwareRenderer = dynamic_cast<QSGSoftwareRenderer*>(renderer);
471483
{ // before render
472484
if (softwareRenderer) {
485+
// Avoid do clear before paint, for the software renderer this
486+
// work is expensive.
487+
if (m_clearColor.alpha() == 0)
488+
preserveColorContents = true;
489+
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
490+
softwareRenderer->setClearColorEnabled(!preserveColorContents);
491+
#else
492+
auto bn = softwareRenderer->renderableNode(softwareRenderer->m_background);
493+
if (bn) {
494+
bn->m_opacity = preserveColorContents ? 0 : 1;
495+
}
496+
#endif
497+
if (!state.dirty.isEmpty()) {
498+
softwareRenderer->m_dirtyRegion += state.dirty;
499+
state.dirty = QRegion();
500+
}
501+
473502
// because software renderer don't supports viewportRect,
474503
// so use transform to simulation.
475504
const auto mapTransform = inputMapToOutput(sourceRect, targetRect,
@@ -565,6 +594,8 @@ void WBufferRenderer::render(int sourceIndex, const QMatrix4x4 &renderMatrix,
565594
// drawing result is available for use.
566595
wd->rhi->finish();
567596
} else {
597+
state.dirty = softwareRenderer->flushRegion();
598+
568599
auto currentImage = getImageFrom(state.renderTarget);
569600
Q_ASSERT(currentImage && currentImage == softwareRenderer->m_rt.paintDevice);
570601
currentImage->setDevicePixelRatio(1.0);
@@ -591,28 +622,6 @@ void WBufferRenderer::render(int sourceIndex, const QMatrix4x4 &renderMatrix,
591622
pa.fillRect(r, softwareRenderer->clearColor());
592623
}
593624
}
594-
595-
if (!damage.isEmpty() && state.lastRT.first != state.buffer && !state.lastRT.second.isNull()) {
596-
auto image = getImageFrom(state.lastRT.second);
597-
Q_ASSERT(image);
598-
Q_ASSERT(image->size() == state.pixelSize);
599-
600-
// TODO: Don't use the previous render target, we can get the damage region of QtQuick
601-
// before QQuickRenderControl::render for qw_damage_ring, and add dirty region to
602-
// QSGAbstractSoftwareRenderer to force repaint the damage region of current render target.
603-
QPainter pa(currentImage);
604-
605-
PixmanRegion remainderDamage;
606-
ok = pixman_region32_subtract(remainderDamage, damage, scaledFlushDamage);
607-
Q_ASSERT(ok);
608-
609-
int count = 0;
610-
auto rects = pixman_region32_rectangles(remainderDamage, &count);
611-
for (int i = 0; i < count; ++i) {
612-
auto r = rects[i];
613-
pa.drawImage(r.x1, r.y1, *image, r.x1, r.y1, r.x2 - r.x1, r.y2 - r.y1);
614-
}
615-
}
616625
}
617626

618627
if (!isRootItem(source.source))
@@ -637,6 +646,7 @@ void WBufferRenderer::endRender()
637646
state.buffer = nullptr;
638647
state.renderer = nullptr;
639648
state.batchRenderer = nullptr;
649+
state.dirty = QRegion();
640650

641651
m_lastBuffer = buffer;
642652
m_damageRing.rotate();

src/server/qtquick/private/wbufferrenderer_p.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,10 @@ class WAYLIB_SERVER_EXPORT WBufferRenderer : public QQuickItem
142142
QSize pixelSize;
143143
qreal devicePixelRatio;
144144
int bufferAge;
145-
std::pair<QW_NAMESPACE::qw_buffer*, QQuickRenderTarget> lastRT;
146145
QW_NAMESPACE::qw_buffer *buffer = nullptr;
147146
QQuickRenderTarget renderTarget;
148147
QSGRenderTarget sgRenderTarget;
148+
QRegion dirty;
149149
} state;
150150

151151
QPointer<WOutput> m_output;

src/server/qtquick/woutputrenderwindow.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -950,9 +950,7 @@ WBufferRenderer *OutputHelper::compositeLayers(const QList<LayerData*> layers, b
950950
{
951951
Q_ASSERT(!layers.isEmpty());
952952

953-
const bool usingShadowRenderer = forceShadowRenderer
954-
// TODO: Support preserveColorContents in Qt in QSGSoftwareRenderer
955-
|| dynamic_cast<QSGSoftwareRenderer*>(renderWindowD()->renderer);
953+
const bool usingShadowRenderer = forceShadowRenderer;
956954

957955
if (!m_layerPorxyContainer) {
958956
m_layerPorxyContainer = new QQuickItem(renderWindow()->contentItem());
@@ -981,6 +979,8 @@ WBufferRenderer *OutputHelper::compositeLayers(const QList<LayerData*> layers, b
981979
auto outputProxy = m_layerProxys.first();
982980
outputProxy->setRenderer(bufferRenderer());
983981
outputProxy->setSize(output->size());
982+
outputProxy->setPosition({0, 0});
983+
outputProxy->setZ(0);
984984
} else {
985985
output = m_output;
986986

src/server/qtquick/wquicktextureproxy.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,10 @@ QSGNode *WQuickTextureProxy::updatePaintNode(QSGNode *old, QQuickItem::UpdatePai
238238

239239
const auto tp = d->sourceItem->textureProvider();
240240
if (Q_LIKELY(!tp || !tp->texture())) {
241+
if (tp) {
242+
connect(tp, &QSGTextureProvider::textureChanged,
243+
this, &WQuickTextureProxy::update, Qt::SingleShotConnection);
244+
}
241245
delete old;
242246
return nullptr;
243247
}

0 commit comments

Comments
 (0)