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
This commit is contained in:
Xaver Hugl 2024-04-24 16:16:01 +02:00
parent 6b5571b023
commit 06ba20cc2e
5 changed files with 134 additions and 88 deletions

View file

@ -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<OutputFrame>(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<std::chrono::milliseconds>(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);

View file

@ -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);

View file

@ -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 <KNotification>
#endif
#include <KLocalizedString>
#include <QQuickWindow>
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<OutputFrame>(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<std::chrono::milliseconds>(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()) {

View file

@ -26,6 +26,7 @@ public:
protected:
void start() override;
void stop() override;
void composite(RenderLoop *loop) override;
private:
explicit WaylandCompositor(QObject *parent);

View file

@ -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 <KGlobalAccel>
#include <KLocalizedString>
#include <KSelectionOwner>
#if KWIN_BUILD_NOTIFICATIONS
#include <KNotification>
#endif
#include <QAction>
#include <QOpenGLContext>
@ -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<OutputFrame>(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()) {