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:
parent
6b5571b023
commit
06ba20cc2e
5 changed files with 134 additions and 88 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
protected:
|
||||
void start() override;
|
||||
void stop() override;
|
||||
void composite(RenderLoop *loop) override;
|
||||
|
||||
private:
|
||||
explicit WaylandCompositor(QObject *parent);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
Loading…
Reference in a new issue