From 7e57e37d8bb5820d4e70c35a4c85a94f086ab61e Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 28 Nov 2024 15:01:07 +0800 Subject: [PATCH 1/4] Use schedule_frame to do render if layers changed The WOutputRenderWindow::scheduleRender is not by the wlroots's schedule frame, so maybe trigger an invalid render request. --- src/server/qtquick/woutputhelper.cpp | 18 ++++++++++++------ src/server/qtquick/woutputhelper.h | 2 +- src/server/qtquick/woutputrenderwindow.cpp | 8 +++----- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/server/qtquick/woutputhelper.cpp b/src/server/qtquick/woutputhelper.cpp index 3f89b5ad8..5c7cc59cc 100644 --- a/src/server/qtquick/woutputhelper.cpp +++ b/src/server/qtquick/woutputhelper.cpp @@ -47,10 +47,7 @@ class Q_DECL_HIDDEN WOutputHelperPrivate : public WObjectPrivate output->safeConnect(&qw_output::notify_frame, qq, [this] { on_frame(); }); - output->safeConnect(&qw_output::notify_needs_frame, qq, [this] { - setNeedsFrame(true); - qwoutput()->qw_output::schedule_frame(); - }); + output->safeConnect(&qw_output::notify_needs_frame, qq, &WOutputHelper::requestFrame); output->safeConnect(&qw_output::notify_damage, qq, [this] { on_damage(); }); @@ -134,8 +131,10 @@ void WOutputHelperPrivate::on_frame() void WOutputHelperPrivate::on_damage() { - setContentIsDirty(true); - Q_EMIT q_func()->damaged(); + // The damage envent is from wlr_cursor. + + // The cursor's implementation is in WOutputLayer, + // is not in wlroots, so don't do anything here. } qw_buffer *WOutputHelperPrivate::acquireBuffer(wlr_swapchain **sc, int *bufferAge) @@ -335,6 +334,13 @@ void WOutputHelper::update() d->update(); } +void WOutputHelper::requestFrame() +{ + W_D(WOutputHelper); + d->setNeedsFrame(true); + d->qwoutput()->schedule_frame(); +} + WAYLIB_SERVER_END_NAMESPACE #include "moc_woutputhelper.cpp" diff --git a/src/server/qtquick/woutputhelper.h b/src/server/qtquick/woutputhelper.h index ce37cc83c..9d7fa1fa0 100644 --- a/src/server/qtquick/woutputhelper.h +++ b/src/server/qtquick/woutputhelper.h @@ -68,13 +68,13 @@ class WAYLIB_SERVER_EXPORT WOutputHelper : public QObject, public WObject void resetState(bool resetRenderable); void update(); + void requestFrame(); protected: WOutputHelper(WOutput *output, bool renderable, bool contentIsDirty, bool needsFrame, QObject *parent = nullptr); Q_SIGNALS: void requestRender(); - void damaged(); void renderableChanged(); void contentIsDirtyChanged(); void needsFrameChanged(); diff --git a/src/server/qtquick/woutputrenderwindow.cpp b/src/server/qtquick/woutputrenderwindow.cpp index cee8d7579..7112d190d 100644 --- a/src/server/qtquick/woutputrenderwindow.cpp +++ b/src/server/qtquick/woutputrenderwindow.cpp @@ -177,7 +177,6 @@ class Q_DECL_HIDDEN OutputHelper : public WOutputHelper inline void init() { connect(this, &OutputHelper::requestRender, renderWindow(), qOverload<>(&WOutputRenderWindow::render)); - connect(this, &OutputHelper::damaged, renderWindow(), &WOutputRenderWindow::scheduleRender); // TODO: pre update scale after WOutputHelper::setScale output()->output()->safeConnect(&WOutput::scaleChanged, this, &OutputHelper::updateSceneDPR); } @@ -1646,10 +1645,10 @@ void WOutputRenderWindow::attach(WOutputLayer *layer, WOutputViewport *output) auto outputHelper = d->getOutputHelper(output); if (outputHelper && outputHelper->attachLayer(wapper)) - d->scheduleDoRender(); + outputHelper->requestFrame(); - connect(layer, &WOutputLayer::flagsChanged, this, &WOutputRenderWindow::scheduleRender); - connect(layer, &WOutputLayer::zChanged, this, &WOutputRenderWindow::scheduleRender); + connect(layer, &WOutputLayer::flagsChanged, outputHelper, &OutputHelper::requestFrame); + connect(layer, &WOutputLayer::zChanged, outputHelper, &OutputHelper::requestFrame); if (auto od = WOutputViewportPrivate::get(output)) { od->notifyLayersChanged(); @@ -1876,7 +1875,6 @@ void WOutputRenderWindow::update(WOutputViewport *output) int index = d->indexOfOutputHelper(output); Q_ASSERT(index >= 0); d->outputs.at(index)->update(); - d->scheduleDoRender(); } qreal WOutputRenderWindow::width() const From 9910b6ab7138ee62bdb7fb63443374b99e949418 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 28 Nov 2024 15:54:39 +0800 Subject: [PATCH 2/4] Fix output not update after scale changed --- src/server/qtquick/woutputrenderwindow.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/server/qtquick/woutputrenderwindow.cpp b/src/server/qtquick/woutputrenderwindow.cpp index 7112d190d..1f736af68 100644 --- a/src/server/qtquick/woutputrenderwindow.cpp +++ b/src/server/qtquick/woutputrenderwindow.cpp @@ -1744,7 +1744,8 @@ void WOutputRenderWindow::setOutputScale(WOutputViewport *output, float scale) if (auto helper = d->getOutputHelper(output)) { helper->setScale(scale); - update(); + helper->WOutputHelper::commit(); + helper->update(); } } @@ -1754,7 +1755,8 @@ void WOutputRenderWindow::rotateOutput(WOutputViewport *output, WOutput::Transfo if (auto helper = d->getOutputHelper(output)) { helper->setTransform(t); - update(); + helper->WOutputHelper::commit(); + helper->update(); } } From e7a1b197ae7ed710fd2fd492d68b13c57014c28f Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 28 Nov 2024 17:37:07 +0800 Subject: [PATCH 3/4] Fix screen flash on set output scale --- src/server/qtquick/woutputhelper.cpp | 8 ++++++++ src/server/qtquick/woutputrenderwindow.cpp | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/server/qtquick/woutputhelper.cpp b/src/server/qtquick/woutputhelper.cpp index 5c7cc59cc..be17d42f1 100644 --- a/src/server/qtquick/woutputhelper.cpp +++ b/src/server/qtquick/woutputhelper.cpp @@ -255,6 +255,14 @@ bool WOutputHelper::commit() { W_D(WOutputHelper); wlr_output_state state = d->state; + if (state.committed == 0) + return false; + + if (state.committed != WLR_OUTPUT_STATE_LAYERS) { + Q_ASSERT_X(state.committed & WLR_OUTPUT_STATE_BUFFER, Q_FUNC_INFO, + "WOutputHelper::commit: buffer is not set, you will got a black frame"); + } + wlr_output_state_init(&d->state); bool ok = d->qwoutput()->commit_state(&state); wlr_output_state_finish(&state); diff --git a/src/server/qtquick/woutputrenderwindow.cpp b/src/server/qtquick/woutputrenderwindow.cpp index 1f736af68..cd7def73c 100644 --- a/src/server/qtquick/woutputrenderwindow.cpp +++ b/src/server/qtquick/woutputrenderwindow.cpp @@ -240,6 +240,7 @@ class Q_DECL_HIDDEN OutputHelper : public WOutputHelper WBufferRenderer *afterRender(); WBufferRenderer *compositeLayers(const QVector layers, bool forceShadowRenderer); bool commit(WBufferRenderer *buffer); + bool commitWithCurrentBuffer(); bool tryToHardwareCursor(const LayerData *layer); private: @@ -1068,6 +1069,17 @@ bool OutputHelper::commit(WBufferRenderer *buffer) return WOutputHelper::commit(); } +bool OutputHelper::commitWithCurrentBuffer() +{ + if (output()->offscreen()) + return true; + if (!m_lastCommitBuffer) + return false; + setBuffer(m_lastCommitBuffer->lastBuffer()); + + return WOutputHelper::commit(); +} + bool OutputHelper::tryToHardwareCursor(const LayerData *layer) { do { @@ -1744,7 +1756,7 @@ void WOutputRenderWindow::setOutputScale(WOutputViewport *output, float scale) if (auto helper = d->getOutputHelper(output)) { helper->setScale(scale); - helper->WOutputHelper::commit(); + helper->commitWithCurrentBuffer(); helper->update(); } } @@ -1755,7 +1767,7 @@ void WOutputRenderWindow::rotateOutput(WOutputViewport *output, WOutput::Transfo if (auto helper = d->getOutputHelper(output)) { helper->setTransform(t); - helper->WOutputHelper::commit(); + helper->commitWithCurrentBuffer(); helper->update(); } } From 6d58fff52712f573735e777d013a3ec6f09942d8 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 28 Nov 2024 19:31:01 +0800 Subject: [PATCH 4/4] WIP --- examples/tinywl/helper.cpp | 13 ++--- examples/tinywl/output.cpp | 16 ++++++ examples/tinywl/output.h | 3 + src/server/qtquick/woutputhelper.cpp | 12 ---- src/server/qtquick/woutputhelper.h | 2 - src/server/qtquick/woutputrenderwindow.cpp | 67 ++++++++++++++++------ src/server/qtquick/woutputrenderwindow.h | 5 +- src/server/qtquick/woutputviewport.cpp | 34 +++++++++-- src/server/qtquick/woutputviewport.h | 3 + 9 files changed, 108 insertions(+), 47 deletions(-) diff --git a/examples/tinywl/helper.cpp b/examples/tinywl/helper.cpp index 73a9f0854..4856a34a8 100644 --- a/examples/tinywl/helper.cpp +++ b/examples/tinywl/helper.cpp @@ -405,7 +405,7 @@ void Helper::init() qw_output_state newState; newState.set_gamma_lut(ramp_size, r, g, b); - if (!qwOutput->commit_state(newState)) { + if (!getOutput(WOutput::fromHandle(qwOutput))->commitState(newState.handle())) { qw_gamma_control_v1::from(gamma_control)->send_failed_and_destroy(); } }); @@ -441,9 +441,9 @@ void Helper::init() } if (onlyTest) - ok &= output->handle()->test_state(newState); + ok &= getOutput(output)->testState(newState.handle()); else - ok &= output->handle()->commit_state(newState); + ok &= getOutput(output)->commitState(newState.handle()); } wOutputManager->sendResult(config, ok); }); @@ -662,10 +662,9 @@ void Helper::setCursorPosition(const QPointF &position) void Helper::allowNonDrmOutputAutoChangeMode(WOutput *output) { output->safeConnect(&qw_output::notify_request_state, - this, [this] (wlr_output_event_request_state *newState) { + this, [this, output] (wlr_output_event_request_state *newState) { if (newState->state->committed & WLR_OUTPUT_STATE_MODE) { - auto output = qobject_cast(sender()); - output->commit_state(newState->state); + getOutput(output)->commitState(newState->state); } }); } @@ -689,7 +688,7 @@ void Helper::enableOutput(WOutput *output) newState.set_mode(mode); } newState.set_enabled(true); - bool ok = qwoutput->commit_state(newState); + bool ok = getOutput(output)->commitState(newState); Q_ASSERT(ok); } } diff --git a/examples/tinywl/output.cpp b/examples/tinywl/output.cpp index d993d8a60..782c56ef6 100644 --- a/examples/tinywl/output.cpp +++ b/examples/tinywl/output.cpp @@ -410,6 +410,22 @@ void Output::updatePositionFromLayout() m_item->setPosition(pos); } +bool Output::commitState(const wlr_output_state *state) +{ + auto viewport = screenViewport(); + if (!viewport) + return false; + return viewport->commitState(state); +} + +bool Output::testState(const wlr_output_state *state) +{ + auto viewport = screenViewport(); + if (!viewport) + return false; + return viewport->testState(state); +} + std::pair Output::getOutputItemProperty() { WOutputViewport *viewportCopy = outputItem()->findChild({}, Qt::FindDirectChildrenOnly); diff --git a/examples/tinywl/output.h b/examples/tinywl/output.h index 7aa76ceae..5606646bd 100644 --- a/examples/tinywl/output.h +++ b/examples/tinywl/output.h @@ -65,6 +65,9 @@ class Output : public SurfaceListModel WOutputViewport *screenViewport() const; void updatePositionFromLayout(); + bool commitState(const wlr_output_state *state); + bool testState(const wlr_output_state *state); + signals: void exclusiveZoneChanged(); void moveResizeFinised(); diff --git a/src/server/qtquick/woutputhelper.cpp b/src/server/qtquick/woutputhelper.cpp index be17d42f1..391f066b7 100644 --- a/src/server/qtquick/woutputhelper.cpp +++ b/src/server/qtquick/woutputhelper.cpp @@ -213,18 +213,6 @@ qw_buffer *WOutputHelper::buffer() const return d->state.buffer ? qw_buffer::from(d->state.buffer) : nullptr; } -void WOutputHelper::setScale(float scale) -{ - W_D(WOutputHelper); - wlr_output_state_set_scale(&d->state, scale); -} - -void WOutputHelper::setTransform(WOutput::Transform t) -{ - W_D(WOutputHelper); - wlr_output_state_set_transform(&d->state, static_cast(t)); -} - void WOutputHelper::setDamage(const pixman_region32 *damage) { W_D(WOutputHelper); diff --git a/src/server/qtquick/woutputhelper.h b/src/server/qtquick/woutputhelper.h index 9d7fa1fa0..ba9225c94 100644 --- a/src/server/qtquick/woutputhelper.h +++ b/src/server/qtquick/woutputhelper.h @@ -53,8 +53,6 @@ class WAYLIB_SERVER_EXPORT WOutputHelper : public QObject, public WObject void setBuffer(QW_NAMESPACE::qw_buffer *buffer); QW_NAMESPACE::qw_buffer *buffer() const; - void setScale(float scale); - void setTransform(WOutput::Transform t); void setDamage(const pixman_region32 *damage); const pixman_region32 *damage() const; void setLayers(const wlr_output_layer_state_array &layers); diff --git a/src/server/qtquick/woutputrenderwindow.cpp b/src/server/qtquick/woutputrenderwindow.cpp index cd7def73c..d20a00ae4 100644 --- a/src/server/qtquick/woutputrenderwindow.cpp +++ b/src/server/qtquick/woutputrenderwindow.cpp @@ -240,13 +240,13 @@ class Q_DECL_HIDDEN OutputHelper : public WOutputHelper WBufferRenderer *afterRender(); WBufferRenderer *compositeLayers(const QVector layers, bool forceShadowRenderer); bool commit(WBufferRenderer *buffer); - bool commitWithCurrentBuffer(); + qw_buffer* lastBuffer() const; bool tryToHardwareCursor(const LayerData *layer); private: WOutputViewport *m_output = nullptr; QList m_layers; - WBufferRenderer *m_lastCommitBuffer = nullptr; + QPointer m_lastCommitBuffer; // only for render cursor QPointer m_cursorRenderer; BufferRendererProxy *m_cursorLayerProxy = nullptr; @@ -1069,15 +1069,11 @@ bool OutputHelper::commit(WBufferRenderer *buffer) return WOutputHelper::commit(); } -bool OutputHelper::commitWithCurrentBuffer() +qw_buffer *OutputHelper::lastBuffer() const { - if (output()->offscreen()) - return true; - if (!m_lastCommitBuffer) - return false; - setBuffer(m_lastCommitBuffer->lastBuffer()); - - return WOutputHelper::commit(); + if (Q_UNLIKELY(!m_lastCommitBuffer)) + return nullptr; + return m_lastCommitBuffer->lastBuffer(); } bool OutputHelper::tryToHardwareCursor(const LayerData *layer) @@ -1750,26 +1746,59 @@ QList WOutputRenderWindow::hardwareLayers(const WOutputViewport return list; } -void WOutputRenderWindow::setOutputScale(WOutputViewport *output, float scale) +bool WOutputRenderWindow::commitOutputState(WOutputViewport *output, const wlr_output_state *state) { Q_D(WOutputRenderWindow); - if (auto helper = d->getOutputHelper(output)) { - helper->setScale(scale); - helper->commitWithCurrentBuffer(); + auto helper = d->getOutputHelper(output); + auto buffer = helper->lastBuffer(); + + if ((state->committed & WLR_OUTPUT_STATE_BUFFER) + || !buffer) { + return helper->qwoutput()->commit_state(state); + } + + wlr_output_state new_state; + // Don't use the wlr_output_state_copy, we need only a shallow copy + new_state = *state; + wlr_output_state_set_buffer(&new_state, *buffer); + + bool ok = helper->qwoutput()->commit_state(&new_state); + // lock in wlr_output_state_set_buffer + buffer->unlock(); + + if ((state->committed + & (WLR_OUTPUT_STATE_MODE + | WLR_OUTPUT_STATE_SCALE + | WLR_OUTPUT_STATE_TRANSFORM)) != 0) { helper->update(); } + + return ok; } -void WOutputRenderWindow::rotateOutput(WOutputViewport *output, WOutput::Transform t) +bool WOutputRenderWindow::testOutputState(WOutputViewport *output, const wlr_output_state *state) { Q_D(WOutputRenderWindow); - if (auto helper = d->getOutputHelper(output)) { - helper->setTransform(t); - helper->commitWithCurrentBuffer(); - helper->update(); + auto helper = d->getOutputHelper(output); + auto buffer = helper->lastBuffer(); + + if ((state->committed & WLR_OUTPUT_STATE_BUFFER) + || !buffer) { + return helper->qwoutput()->test_state(state); } + + wlr_output_state new_state; + // Don't use the wlr_output_state_copy, we need only a shallow copy + new_state = *state; + wlr_output_state_set_buffer(&new_state, *buffer); + + bool ok = helper->qwoutput()->test_state(&new_state); + // lock in wlr_output_state_set_buffer + buffer->unlock(); + + return ok; } void WOutputRenderWindow::init(qw_renderer *renderer, qw_allocator *allocator) diff --git a/src/server/qtquick/woutputrenderwindow.h b/src/server/qtquick/woutputrenderwindow.h index a3b108618..a0187ae1e 100644 --- a/src/server/qtquick/woutputrenderwindow.h +++ b/src/server/qtquick/woutputrenderwindow.h @@ -42,9 +42,8 @@ class WAYLIB_SERVER_EXPORT WOutputRenderWindow : public QQuickWindow, public QQm WOutputViewport *mapFrom, QQuickItem *mapTo); void detach(WOutputLayer *layer, WOutputViewport *output); - void setOutputScale(WOutputViewport *output, float scale); - void rotateOutput(WOutputViewport *output, WOutput::Transform t); - void setOutputEnabled(WOutputViewport *output, bool enabled); + bool commitOutputState(WOutputViewport *output, const wlr_output_state *state); + bool testOutputState(WOutputViewport *output, const wlr_output_state *state); void init(QW_NAMESPACE::qw_renderer *renderer, QW_NAMESPACE::qw_allocator *allocator); QW_NAMESPACE::qw_renderer *renderer() const; diff --git a/src/server/qtquick/woutputviewport.cpp b/src/server/qtquick/woutputviewport.cpp index cd262493e..0e1b5a6d6 100644 --- a/src/server/qtquick/woutputviewport.cpp +++ b/src/server/qtquick/woutputviewport.cpp @@ -493,18 +493,44 @@ void WOutputViewport::setDepends(const QList &newDepends) Q_EMIT dependsChanged(); } +bool WOutputViewport::commitState(const wlr_output_state *state) +{ + W_D(WOutputViewport); + if (auto window = d->outputWindow()) { + return window->commitOutputState(this, state); + } + + return false; +} + +bool WOutputViewport::testState(const wlr_output_state *state) +{ + W_D(WOutputViewport); + if (auto window = d->outputWindow()) { + return window->testOutputState(this, state); + } + + return false; +} + void WOutputViewport::setOutputScale(float scale) { W_D(WOutputViewport); - if (auto window = d->outputWindow()) - window->setOutputScale(this, scale); + if (auto window = d->outputWindow()) { + qw_output_state state; + state.set_scale(scale); + window->commitOutputState(this, state.handle()); + } } void WOutputViewport::rotateOutput(WOutput::Transform t) { W_D(WOutputViewport); - if (auto window = d->outputWindow()) - window->rotateOutput(this, t); + if (auto window = d->outputWindow()) { + qw_output_state state; + state.set_transform(static_cast(t)); + window->commitOutputState(this, state.handle()); + } } void WOutputViewport::render(bool doCommit) diff --git a/src/server/qtquick/woutputviewport.h b/src/server/qtquick/woutputviewport.h index cc3589ef3..b39cbdbca 100644 --- a/src/server/qtquick/woutputviewport.h +++ b/src/server/qtquick/woutputviewport.h @@ -103,6 +103,9 @@ class WAYLIB_SERVER_EXPORT WOutputViewport : public QQuickItem, public virtual W QList depends() const; void setDepends(const QList &newDepends); + bool commitState(const wlr_output_state *state); + bool testState(const wlr_output_state *state); + public Q_SLOTS: void setOutputScale(float scale); void rotateOutput(WOutput::Transform t);