From 06ba20cc2ede762bce3bc6c9d818a2fe6341717f Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Wed, 24 Apr 2024 16:16:01 +0200 Subject: [PATCH] compositor: move the composite method into X11 and Wayland implementations There's a bunch of differences between them, like direct scanout, adaptive sync, content type and the actually painted output in the Wayland session but not on Xorg, so keeping them in one method doesn't really make sense --- src/compositor.cpp | 86 ------------------------------------- src/compositor.h | 2 +- src/compositor_wayland.cpp | 88 ++++++++++++++++++++++++++++++++++++++ src/compositor_wayland.h | 1 + src/compositor_x11.cpp | 45 ++++++++++++++++++- 5 files changed, 134 insertions(+), 88 deletions(-) diff --git a/src/compositor.cpp b/src/compositor.cpp index 4c5e2509d8..39dc31d07d 100644 --- a/src/compositor.cpp +++ b/src/compositor.cpp @@ -137,92 +137,6 @@ void Compositor::handleFrameRequested(RenderLoop *renderLoop) composite(renderLoop); } -void Compositor::composite(RenderLoop *renderLoop) -{ - if (m_backend->checkGraphicsReset()) { - qCDebug(KWIN_CORE) << "Graphics reset occurred"; -#if KWIN_BUILD_NOTIFICATIONS - KNotification::event(QStringLiteral("graphicsreset"), i18n("Desktop effects were restarted due to a graphics reset")); -#endif - reinitialize(); - return; - } - - Output *output = findOutput(renderLoop); - OutputLayer *primaryLayer = m_backend->primaryLayer(output); - fTraceDuration("Paint (", output->name(), ")"); - - RenderLayer *superLayer = m_superlayers[renderLoop]; - superLayer->setOutputLayer(primaryLayer); - - renderLoop->prepareNewFrame(); - auto frame = std::make_shared(renderLoop); - - if (primaryLayer->needsRepaint() || superLayer->needsRepaint()) { - renderLoop->beginPaint(); - - QRegion surfaceDamage = primaryLayer->repaints(); - primaryLayer->resetRepaints(); - prePaintPass(superLayer, &surfaceDamage); - - Window *const activeWindow = workspace()->activeWindow(); - SurfaceItem *const activeFullscreenItem = activeWindow && activeWindow->isFullScreen() && activeWindow->isOnOutput(output) ? activeWindow->surfaceItem() : nullptr; - frame->setContentType(activeWindow && activeFullscreenItem ? activeFullscreenItem->contentType() : ContentType::None); - - const bool wantsAdaptiveSync = activeWindow && activeWindow->isOnOutput(output) && activeWindow->wantsAdaptiveSync(); - const bool vrr = (output->capabilities() & Output::Capability::Vrr) && (output->vrrPolicy() == VrrPolicy::Always || (output->vrrPolicy() == VrrPolicy::Automatic && wantsAdaptiveSync)); - const bool tearing = (output->capabilities() & Output::Capability::Tearing) && options->allowTearing() && activeFullscreenItem && activeFullscreenItem->presentationHint() == PresentationModeHint::Async; - if (vrr) { - frame->setPresentationMode(tearing ? PresentationMode::AdaptiveAsync : PresentationMode::AdaptiveSync); - } else { - frame->setPresentationMode(tearing ? PresentationMode::Async : PresentationMode::VSync); - } - - bool directScanout = false; - if (const auto scanoutCandidate = superLayer->delegate()->scanoutCandidate()) { - const auto sublayers = superLayer->sublayers(); - const bool scanoutPossible = std::none_of(sublayers.begin(), sublayers.end(), [](RenderLayer *sublayer) { - return sublayer->isVisible(); - }); - if (scanoutPossible) { - directScanout = primaryLayer->attemptScanout(scanoutCandidate); - } - } else { - primaryLayer->notifyNoScanoutCandidate(); - } - - if (!directScanout) { - if (auto beginInfo = primaryLayer->beginFrame()) { - auto &[renderTarget, repaint] = beginInfo.value(); - - const QRegion bufferDamage = surfaceDamage.united(repaint).intersected(superLayer->rect().toAlignedRect()); - - paintPass(superLayer, renderTarget, bufferDamage); - primaryLayer->endFrame(bufferDamage, surfaceDamage); - } - } - - postPaintPass(superLayer); - } - - m_backend->present(output, frame); - - framePass(superLayer, frame.get()); - - // TODO: Put it inside the cursor layer once the cursor layer can be backed by a real output layer. - if (waylandServer()) { - const std::chrono::milliseconds frameTime = - std::chrono::duration_cast(output->renderLoop()->lastPresentationTimestamp()); - - if (!Cursors::self()->isCursorHidden()) { - Cursor *cursor = Cursors::self()->currentCursor(); - if (cursor->geometry().intersects(output->geometry())) { - cursor->markAsRendered(frameTime); - } - } - } -} - void Compositor::framePass(RenderLayer *layer, OutputFrame *frame) { layer->delegate()->frame(frame); diff --git a/src/compositor.h b/src/compositor.h index c2fc1726a0..4c45ff38d6 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -134,7 +134,7 @@ protected: static Compositor *s_compositor; protected Q_SLOTS: - virtual void composite(RenderLoop *renderLoop); + virtual void composite(RenderLoop *renderLoop) = 0; private Q_SLOTS: void handleFrameRequested(RenderLoop *renderLoop); diff --git a/src/compositor_wayland.cpp b/src/compositor_wayland.cpp index 6e56432c50..45d4ef34e8 100644 --- a/src/compositor_wayland.cpp +++ b/src/compositor_wayland.cpp @@ -13,6 +13,7 @@ #include "core/renderbackend.h" #include "core/renderlayer.h" #include "effect/effecthandler.h" +#include "ftrace.h" #include "main.h" #include "opengl/glplatform.h" #include "platformsupport/scenes/opengl/openglbackend.h" @@ -27,6 +28,11 @@ #include "window.h" #include "workspace.h" +#if KWIN_BUILD_NOTIFICATIONS +#include +#endif +#include + #include namespace KWin @@ -250,6 +256,88 @@ void WaylandCompositor::stop() Q_EMIT compositingToggled(false); } +void WaylandCompositor::composite(RenderLoop *renderLoop) +{ + if (m_backend->checkGraphicsReset()) { + qCDebug(KWIN_CORE) << "Graphics reset occurred"; +#if KWIN_BUILD_NOTIFICATIONS + KNotification::event(QStringLiteral("graphicsreset"), i18n("Desktop effects were restarted due to a graphics reset")); +#endif + reinitialize(); + return; + } + + Output *output = findOutput(renderLoop); + OutputLayer *primaryLayer = m_backend->primaryLayer(output); + fTraceDuration("Paint (", output->name(), ")"); + + RenderLayer *superLayer = m_superlayers[renderLoop]; + superLayer->setOutputLayer(primaryLayer); + + renderLoop->prepareNewFrame(); + auto frame = std::make_shared(renderLoop); + + if (primaryLayer->needsRepaint() || superLayer->needsRepaint()) { + renderLoop->beginPaint(); + + QRegion surfaceDamage = primaryLayer->repaints(); + primaryLayer->resetRepaints(); + prePaintPass(superLayer, &surfaceDamage); + + Window *const activeWindow = workspace()->activeWindow(); + SurfaceItem *const activeFullscreenItem = activeWindow && activeWindow->isFullScreen() && activeWindow->isOnOutput(output) ? activeWindow->surfaceItem() : nullptr; + frame->setContentType(activeWindow && activeFullscreenItem ? activeFullscreenItem->contentType() : ContentType::None); + + const bool wantsAdaptiveSync = activeWindow && activeWindow->isOnOutput(output) && activeWindow->wantsAdaptiveSync(); + const bool vrr = (output->capabilities() & Output::Capability::Vrr) && (output->vrrPolicy() == VrrPolicy::Always || (output->vrrPolicy() == VrrPolicy::Automatic && wantsAdaptiveSync)); + const bool tearing = (output->capabilities() & Output::Capability::Tearing) && options->allowTearing() && activeFullscreenItem && activeFullscreenItem->presentationHint() == PresentationModeHint::Async; + if (vrr) { + frame->setPresentationMode(tearing ? PresentationMode::AdaptiveAsync : PresentationMode::AdaptiveSync); + } else { + frame->setPresentationMode(tearing ? PresentationMode::Async : PresentationMode::VSync); + } + + bool directScanout = false; + if (const auto scanoutCandidate = superLayer->delegate()->scanoutCandidate()) { + const auto sublayers = superLayer->sublayers(); + const bool scanoutPossible = std::none_of(sublayers.begin(), sublayers.end(), [](RenderLayer *sublayer) { + return sublayer->isVisible(); + }); + if (scanoutPossible) { + directScanout = primaryLayer->attemptScanout(scanoutCandidate); + } + } else { + primaryLayer->notifyNoScanoutCandidate(); + } + + if (!directScanout) { + if (auto beginInfo = primaryLayer->beginFrame()) { + auto &[renderTarget, repaint] = beginInfo.value(); + + const QRegion bufferDamage = surfaceDamage.united(repaint).intersected(superLayer->rect().toAlignedRect()); + + paintPass(superLayer, renderTarget, bufferDamage); + primaryLayer->endFrame(bufferDamage, surfaceDamage); + } + } + + postPaintPass(superLayer); + } + + m_backend->present(output, frame); + + framePass(superLayer, frame.get()); + + // TODO: move this into the cursor layer + const auto frameTime = std::chrono::duration_cast(output->renderLoop()->lastPresentationTimestamp()); + if (!Cursors::self()->isCursorHidden()) { + Cursor *cursor = Cursors::self()->currentCursor(); + if (cursor->geometry().intersects(output->geometry())) { + cursor->markAsRendered(frameTime); + } + } +} + void WaylandCompositor::addOutput(Output *output) { if (output->isPlaceholder()) { diff --git a/src/compositor_wayland.h b/src/compositor_wayland.h index 4d501825d8..1fe43a7bd2 100644 --- a/src/compositor_wayland.h +++ b/src/compositor_wayland.h @@ -26,6 +26,7 @@ public: protected: void start() override; void stop() override; + void composite(RenderLoop *loop) override; private: explicit WaylandCompositor(QObject *parent); diff --git a/src/compositor_x11.cpp b/src/compositor_x11.cpp index 39e7abefac..ee9d8528ca 100644 --- a/src/compositor_x11.cpp +++ b/src/compositor_x11.cpp @@ -13,6 +13,7 @@ #include "core/renderbackend.h" #include "core/renderlayer.h" #include "effect/effecthandler.h" +#include "ftrace.h" #include "opengl/glplatform.h" #include "options.h" #include "platformsupport/scenes/opengl/openglbackend.h" @@ -28,6 +29,9 @@ #include #include #include +#if KWIN_BUILD_NOTIFICATIONS +#include +#endif #include #include @@ -437,7 +441,46 @@ void X11Compositor::composite(RenderLoop *renderLoop) createOpenGLSafePoint(OpenGLSafePoint::PreFrame); } - Compositor::composite(renderLoop); + if (m_backend->checkGraphicsReset()) { + qCDebug(KWIN_CORE) << "Graphics reset occurred"; +#if KWIN_BUILD_NOTIFICATIONS + KNotification::event(QStringLiteral("graphicsreset"), i18n("Desktop effects were restarted due to a graphics reset")); +#endif + reinitialize(); + return; + } + + OutputLayer *primaryLayer = m_backend->primaryLayer(nullptr); + fTraceDuration("Paint"); + + RenderLayer *superLayer = m_superlayers[renderLoop]; + superLayer->setOutputLayer(primaryLayer); + + renderLoop->prepareNewFrame(); + auto frame = std::make_shared(renderLoop); + + if (primaryLayer->needsRepaint() || superLayer->needsRepaint()) { + renderLoop->beginPaint(); + + QRegion surfaceDamage = primaryLayer->repaints(); + primaryLayer->resetRepaints(); + prePaintPass(superLayer, &surfaceDamage); + + if (auto beginInfo = primaryLayer->beginFrame()) { + auto &[renderTarget, repaint] = beginInfo.value(); + + const QRegion bufferDamage = surfaceDamage.united(repaint).intersected(superLayer->rect().toAlignedRect()); + + paintPass(superLayer, renderTarget, bufferDamage); + primaryLayer->endFrame(bufferDamage, surfaceDamage); + } + + postPaintPass(superLayer); + } + + m_backend->present(nullptr, frame); + + framePass(superLayer, frame.get()); if (m_syncManager) { if (!m_syncManager->endFrame()) {