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()) {