Commit 1be65e81 authored by Xaver Hugl's avatar Xaver Hugl
Browse files

Port screenId based rendering methods to AbstractOutput

parent e6cab81b
......@@ -393,16 +393,6 @@ void Compositor::handleOutputDisabled(AbstractOutput *output)
unregisterRenderLoop(output->renderLoop());
}
int Compositor::screenForRenderLoop(RenderLoop *renderLoop) const
{
Q_ASSERT(m_renderLoops.contains(renderLoop));
AbstractOutput *output = m_renderLoops.value(renderLoop);
if (!output) {
return -1;
}
return kwinApp()->platform()->enabledOutputs().indexOf(output);
}
void Compositor::scheduleRepaint()
{
for (auto it = m_renderLoops.constBegin(); it != m_renderLoops.constEnd(); ++it) {
......@@ -585,9 +575,9 @@ void Compositor::handleFrameRequested(RenderLoop *renderLoop)
void Compositor::composite(RenderLoop *renderLoop)
{
const int screenId = screenForRenderLoop(renderLoop);
const auto &output = m_renderLoops[renderLoop];
fTraceDuration("Paint (", screens()->name(screenId), ")");
fTraceDuration("Paint (", output ? output->name() : QStringLiteral("screens"), ")");
// Create a list of all windows in the stacking order
QList<Toplevel *> windows = Workspace::self()->xStackingOrder();
......@@ -617,10 +607,10 @@ void Compositor::composite(RenderLoop *renderLoop)
}
}
const QRegion repaints = m_scene->repaints(screenId);
m_scene->resetRepaints(screenId);
const QRegion repaints = m_scene->repaints(output);
m_scene->resetRepaints(output);
m_scene->paint(screenId, repaints, windows, renderLoop);
m_scene->paint(output, repaints, windows, renderLoop);
if (waylandServer()) {
const std::chrono::milliseconds frameTime =
......@@ -634,7 +624,7 @@ void Compositor::composite(RenderLoop *renderLoop)
!(window->isLockScreen() || window->isInputMethod())) {
continue;
}
if (!window->isOnScreen(screenId)) {
if (!window->isOnOutput(output)) {
continue;
}
if (auto surface = window->surface()) {
......
......@@ -130,7 +130,6 @@ private:
void releaseCompositorSelection();
void deleteUnusedSupportProperties();
int screenForRenderLoop(RenderLoop *renderLoop) const;
void registerRenderLoop(RenderLoop *renderLoop, AbstractOutput *output);
void unregisterRenderLoop(RenderLoop *renderLoop);
......
......@@ -19,20 +19,13 @@ namespace KWin
Item::Item(Item *parent)
{
setParentItem(parent);
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Item::reallocRepaints);
connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Item::reallocRepaints);
}
reallocRepaints();
connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Item::removeRepaints);
}
Item::~Item()
{
setParentItem(nullptr);
for (int i = 0; i < m_repaints.count(); ++i) {
const QRegion dirty = repaints(i);
for (const auto &dirty : qAsConst(m_repaints)) {
if (!dirty.isEmpty()) {
Compositor::self()->addRepaint(dirty);
}
......@@ -262,19 +255,15 @@ void Item::scheduleRepaintInternal(const QRegion &region)
const QRegion globalRegion = mapToGlobal(region);
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
if (m_repaints.count() != outputs.count()) {
return; // Repaints haven't been reallocated yet, do nothing.
}
for (int screenId = 0; screenId < m_repaints.count(); ++screenId) {
AbstractOutput *output = outputs[screenId];
for (const auto &output : outputs) {
const QRegion dirtyRegion = globalRegion & output->geometry();
if (!dirtyRegion.isEmpty()) {
m_repaints[screenId] += dirtyRegion;
m_repaints[output] += dirtyRegion;
output->renderLoop()->scheduleRepaint();
}
}
} else {
m_repaints[0] += globalRegion;
m_repaints[nullptr] += globalRegion;
kwinApp()->platform()->renderLoop()->scheduleRepaint();
}
}
......@@ -319,32 +308,19 @@ WindowQuadList Item::quads() const
return m_quads.value();
}
QRegion Item::repaints(int screen) const
QRegion Item::repaints(AbstractOutput *output) const
{
Q_ASSERT(!m_repaints.isEmpty());
const int index = screen != -1 ? screen : 0;
if (m_repaints[index] == infiniteRegion()) {
return QRect(QPoint(0, 0), screens()->size());
}
return m_repaints[index];
return m_repaints.value(output, QRect(QPoint(0, 0), screens()->size()));
}
void Item::resetRepaints(int screen)
void Item::resetRepaints(AbstractOutput *output)
{
Q_ASSERT(!m_repaints.isEmpty());
const int index = screen != -1 ? screen : 0;
m_repaints[index] = QRegion();
m_repaints.insert(output, QRegion());
}
void Item::reallocRepaints()
void Item::removeRepaints(AbstractOutput *output)
{
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
m_repaints.resize(kwinApp()->platform()->enabledOutputs().count());
} else {
m_repaints.resize(1);
}
m_repaints.fill(infiniteRegion());
m_repaints.remove(output);
}
bool Item::isVisible() const
......
......@@ -17,6 +17,8 @@
namespace KWin
{
class AbstractOutput;
/**
* The Item class is the base class for items in the scene.
*/
......@@ -85,8 +87,8 @@ public:
void scheduleRepaint(const QRegion &region);
void scheduleFrame();
QRegion repaints(int screen) const;
void resetRepaints(int screen);
QRegion repaints(AbstractOutput *output) const;
void resetRepaints(AbstractOutput *output);
WindowQuadList quads() const;
virtual void preprocess();
......@@ -116,11 +118,11 @@ private:
void removeChild(Item *item);
void updateBoundingRect();
void scheduleRepaintInternal(const QRegion &region);
void reallocRepaints();
void markSortedChildItemsDirty();
bool computeEffectiveVisibility() const;
void updateEffectiveVisibility();
void removeRepaints(AbstractOutput *output);
QPointer<Item> m_parentItem;
QList<Item *> m_childItems;
......@@ -131,7 +133,7 @@ private:
int m_z = 0;
bool m_visible = true;
bool m_effectiveVisible = true;
QVector<QRegion> m_repaints;
QMap<AbstractOutput *, QRegion> m_repaints;
mutable std::optional<WindowQuadList> m_quads;
mutable std::optional<QList<Item *>> m_sortedChildItems;
};
......
......@@ -40,9 +40,9 @@ OverlayWindow* OpenGLBackend::overlayWindow() const
return nullptr;
}
bool OpenGLBackend::scanout(int screenId, SurfaceItem *surfaceItem)
bool OpenGLBackend::scanout(AbstractOutput *output, SurfaceItem *surfaceItem)
{
Q_UNUSED(screenId)
Q_UNUSED(output)
Q_UNUSED(surfaceItem)
return false;
}
......@@ -66,16 +66,16 @@ QSharedPointer<KWin::GLTexture> OpenGLBackend::textureForOutput(AbstractOutput*
return {};
}
void OpenGLBackend::aboutToStartPainting(int screenId, const QRegion &damage)
void OpenGLBackend::aboutToStartPainting(AbstractOutput *output, const QRegion &damage)
{
Q_UNUSED(screenId)
Q_UNUSED(output)
Q_UNUSED(damage)
}
bool OpenGLBackend::directScanoutAllowed(int screen) const
bool OpenGLBackend::directScanoutAllowed(AbstractOutput *output) const
{
Q_UNUSED(screen);
Q_UNUSED(output);
return false;
}
......
......@@ -60,16 +60,16 @@ public:
*
* @p damage contains the reported damage as suggested by windows and effects on prepaint calls.
*/
virtual void aboutToStartPainting(int screenId, const QRegion &damage);
virtual void aboutToStartPainting(AbstractOutput *output, const QRegion &damage);
virtual bool makeCurrent() = 0;
virtual void doneCurrent() = 0;
virtual QRegion beginFrame(int screenId) = 0;
virtual void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) = 0;
virtual QRegion beginFrame(AbstractOutput *output) = 0;
virtual void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) = 0;
/**
* Tries to directly scan out a surface to the screen)
* @return if the scanout fails (or is not supported on the specified screen)
*/
virtual bool scanout(int screenId, SurfaceItem *surfaceItem);
virtual bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem);
/**
* @brief Returns the OverlayWindow used by the backend.
......@@ -121,7 +121,7 @@ public:
{
return m_haveNativeFence;
}
virtual bool directScanoutAllowed(int screen) const;
virtual bool directScanoutAllowed(AbstractOutput *output) const;
/**
* The backend specific extensions (e.g. EGL/GLX extensions).
......
......@@ -22,6 +22,7 @@ namespace KWin
class PlatformSurfaceTexture;
class SurfacePixmapInternal;
class SurfacePixmapWayland;
class AbstractOutput;
class QPainterBackend : public QObject
{
......@@ -33,8 +34,8 @@ public:
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap);
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap);
virtual void endFrame(int screenId, const QRegion &damage) = 0;
virtual QRegion beginFrame(int screenId) = 0;
virtual void endFrame(AbstractOutput *output, const QRegion &damage) = 0;
virtual QRegion beginFrame(AbstractOutput *output) = 0;
/**
* @brief Whether the creation of the Backend failed.
*
......@@ -52,7 +53,7 @@ public:
* @param screenId The id of the screen as used in Screens
* @todo Get a better identifier for screen then a counter variable
*/
virtual QImage *bufferForScreen(int screenId) = 0;
virtual QImage *bufferForScreen(AbstractOutput *output) = 0;
protected:
QPainterBackend();
......
......@@ -26,7 +26,7 @@ class AbstractEglDrmBackend : public AbstractEglBackend
Q_OBJECT
public:
virtual int screenCount() const = 0;
virtual bool hasOutput(AbstractOutput *output) const = 0;
virtual bool addOutput(DrmAbstractOutput *output) = 0;
virtual void removeOutput(DrmAbstractOutput *output) = 0;
virtual bool swapBuffers(DrmAbstractOutput *output, const QRegion &dirty) {
......
......@@ -140,16 +140,15 @@ bool EglGbmBackend::initRenderingContext()
return true;
}
bool EglGbmBackend::resetOutput(Output &output, DrmAbstractOutput *drmOutput)
bool EglGbmBackend::resetOutput(Output &output)
{
output.output = drmOutput;
const QSize size = drmOutput->sourceSize();
QVector<uint64_t> modifiers = drmOutput->supportedModifiers(m_gbmFormat);
const QSize size = output.output->sourceSize();
QVector<uint64_t> modifiers = output.output->supportedModifiers(m_gbmFormat);
QSharedPointer<GbmSurface> gbmSurface;
if (modifiers.isEmpty()) {
int flags = GBM_BO_USE_RENDERING;
if (drmOutput->gpu() == m_gpu) {
if (output.output->gpu() == m_gpu) {
flags |= GBM_BO_USE_SCANOUT;
} else {
flags |= GBM_BO_USE_LINEAR;
......@@ -173,7 +172,7 @@ bool EglGbmBackend::resetOutput(Output &output, DrmAbstractOutput *drmOutput)
output.current = {};
output.current.gbmSurface = gbmSurface;
if (size == drmOutput->pixelSize()) {
if (size == output.output->pixelSize()) {
output.current.shadowBuffer = nullptr;
} else {
makeContextCurrent(output.current);
......@@ -187,58 +186,37 @@ bool EglGbmBackend::resetOutput(Output &output, DrmAbstractOutput *drmOutput)
bool EglGbmBackend::addOutput(DrmAbstractOutput *drmOutput)
{
Output newOutput;
newOutput.output = drmOutput;
if (isPrimary()) {
Output newOutput;
if (!resetOutput(newOutput, drmOutput)) {
if (!resetOutput(newOutput)) {
return false;
}
if (drmOutput->gpu() == m_gpu) {
m_outputs << newOutput;
} else {
m_secondaryGpuOutputs << newOutput;
}
} else {
Output newOutput;
newOutput.output = drmOutput;
if (!renderingBackend()->addOutput(drmOutput)) {
return false;
}
m_outputs << newOutput;
}
m_outputs.insert(drmOutput, newOutput);
return true;
}
void EglGbmBackend::removeOutput(DrmAbstractOutput *drmOutput)
{
QVector<Output> &outputs = drmOutput->gpu() == m_gpu ? m_outputs : m_secondaryGpuOutputs;
auto it = std::find_if(outputs.begin(), outputs.end(),
[drmOutput] (const Output &output) {
return output.output == drmOutput;
}
);
if (it == outputs.end()) {
return;
}
Q_ASSERT(m_outputs.contains(drmOutput));
if (isPrimary()) {
// shadow buffer needs context current for destruction
makeCurrent();
} else {
renderingBackend()->removeOutput((*it).output);
renderingBackend()->removeOutput(drmOutput);
}
outputs.erase(it);
m_outputs.remove(drmOutput);
}
bool EglGbmBackend::swapBuffers(DrmAbstractOutput *drmOutput, const QRegion &dirty)
{
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
[drmOutput] (const Output &output) {
return output.output == drmOutput;
}
);
if (it == m_secondaryGpuOutputs.end()) {
return false;
}
Output &output = *it;
Q_ASSERT(m_outputs.contains(drmOutput));
Output &output = m_outputs[drmOutput];
renderFramebufferToSurface(output);
if (output.current.gbmSurface->swapBuffers()) {
cleanupRenderData(output.old);
......@@ -251,15 +229,8 @@ bool EglGbmBackend::swapBuffers(DrmAbstractOutput *drmOutput, const QRegion &dir
bool EglGbmBackend::exportFramebuffer(DrmAbstractOutput *drmOutput, void *data, const QSize &size, uint32_t stride)
{
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
[drmOutput] (const Output &output) {
return output.output == drmOutput;
}
);
if (it == m_secondaryGpuOutputs.end()) {
return false;
}
auto bo = it->current.gbmSurface->currentBuffer();
Q_ASSERT(m_outputs.contains(drmOutput));
auto bo = m_outputs[drmOutput].current.gbmSurface->currentBuffer();
if (!bo->map(GBM_BO_TRANSFER_READ)) {
return false;
}
......@@ -272,15 +243,8 @@ bool EglGbmBackend::exportFramebuffer(DrmAbstractOutput *drmOutput, void *data,
bool EglGbmBackend::exportFramebufferAsDmabuf(DrmAbstractOutput *drmOutput, int *fds, int *strides, int *offsets, uint32_t *num_fds, uint32_t *format, uint64_t *modifier)
{
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
[drmOutput] (const Output &output) {
return output.output == drmOutput;
}
);
if (it == m_secondaryGpuOutputs.end()) {
return -1;
}
auto bo = it->current.gbmSurface->currentBuffer()->getBo();
Q_ASSERT(m_outputs.contains(drmOutput));
auto bo = m_outputs[drmOutput].current.gbmSurface->currentBuffer()->getBo();
if (gbm_bo_get_handle_for_plane(bo, 0).s32 != -1) {
*num_fds = gbm_bo_get_plane_count(bo);
for (uint32_t i = 0; i < *num_fds; i++) {
......@@ -312,15 +276,8 @@ bool EglGbmBackend::exportFramebufferAsDmabuf(DrmAbstractOutput *drmOutput, int
QRegion EglGbmBackend::beginFrameForSecondaryGpu(DrmAbstractOutput *drmOutput)
{
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
[drmOutput] (const Output &output) {
return output.output == drmOutput;
}
);
if (it == m_secondaryGpuOutputs.end()) {
return QRegion();
}
return prepareRenderingForOutput(*it);
Q_ASSERT(m_outputs.contains(drmOutput));
return prepareRenderingForOutput(m_outputs[drmOutput]);
}
QSharedPointer<DrmBuffer> EglGbmBackend::importFramebuffer(Output &output, const QRegion &dirty) const
......@@ -489,10 +446,11 @@ static QVector<EGLint> regionToRects(const QRegion &region, AbstractWaylandOutpu
return rects;
}
void EglGbmBackend::aboutToStartPainting(int screenId, const QRegion &damagedRegion)
void EglGbmBackend::aboutToStartPainting(AbstractOutput *drmOutput, const QRegion &damagedRegion)
{
Q_ASSERT_X(screenId != -1, "aboutToStartPainting", "not using per screen rendering");
const Output &output = m_outputs.at(screenId);
Q_ASSERT_X(drmOutput, "aboutToStartPainting", "not using per screen rendering");
Q_ASSERT(m_outputs.contains(drmOutput));
const Output &output = m_outputs[drmOutput];
if (output.current.bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) {
const QRegion region = damagedRegion & output.output->geometry();
......@@ -521,9 +479,10 @@ void EglGbmBackend::setViewport(const Output &output) const
glViewport(0, 0, size.width(), size.height());
}
QRegion EglGbmBackend::beginFrame(int screenId)
QRegion EglGbmBackend::beginFrame(AbstractOutput *drmOutput)
{
Output &output = m_outputs[screenId];
Q_ASSERT(m_outputs.contains(drmOutput));
Output &output = m_outputs[drmOutput];
if (output.surfaceInterface) {
qCDebug(KWIN_DRM) << "Direct scanout stopped on output" << output.output->name();
}
......@@ -562,7 +521,7 @@ QRegion EglGbmBackend::prepareRenderingForOutput(Output &output)
output.current = output.old;
output.old = {};
} else {
resetOutput(output, output.output);
resetOutput(output);
}
}
makeContextCurrent(output.current);
......@@ -580,9 +539,10 @@ QRegion EglGbmBackend::prepareRenderingForOutput(Output &output)
return geometry;
}
QSharedPointer<DrmBuffer> EglGbmBackend::endFrameWithBuffer(int screenId, const QRegion &dirty)
QSharedPointer<DrmBuffer> EglGbmBackend::endFrameWithBuffer(AbstractOutput *drmOutput, const QRegion &dirty)
{
Output &output = m_outputs[screenId];
Q_ASSERT(m_outputs.contains(drmOutput));
Output &output = m_outputs[drmOutput];
if (isPrimary()) {
renderFramebufferToSurface(output);
auto buffer = output.current.gbmSurface->swapBuffersForDrm();
......@@ -595,16 +555,17 @@ QSharedPointer<DrmBuffer> EglGbmBackend::endFrameWithBuffer(int screenId, const
}
}
void EglGbmBackend::endFrame(int screenId, const QRegion &renderedRegion,
void EglGbmBackend::endFrame(AbstractOutput *drmOutput, const QRegion &renderedRegion,
const QRegion &damagedRegion)
{
Q_ASSERT(m_outputs.contains(drmOutput));
Q_UNUSED(renderedRegion)
Output &output = m_outputs[screenId];
Output &output = m_outputs[drmOutput];
cleanupRenderData(output.old);
const QRegion dirty = damagedRegion.intersected(output.output->geometry());
QSharedPointer<DrmBuffer> buffer = endFrameWithBuffer(screenId, dirty);
QSharedPointer<DrmBuffer> buffer = endFrameWithBuffer(drmOutput, dirty);
if (!buffer || !output.output->present(buffer, dirty)) {
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(output.output->renderLoop());
renderLoopPrivate->notifyFrameFailed();
......@@ -620,8 +581,9 @@ void EglGbmBackend::updateBufferAge(Output &output, const QRegion &dirty)
}
}
bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem)
bool EglGbmBackend::scanout(AbstractOutput *drmOutput, SurfaceItem *surfaceItem)
{
Q_ASSERT(m_outputs.contains(drmOutput));
SurfaceItemWayland *item = qobject_cast<SurfaceItemWayland *>(surfaceItem);
if (!item) {
return false;
......@@ -636,7 +598,7 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem)
if (!buffer) {
return false;
}
Output &output = m_outputs[screenId];
Output &output = m_outputs[drmOutput];
if (buffer->size() != output.output->modeSize()) {
return false;
}
......@@ -714,41 +676,21 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem)
QSharedPointer<DrmBuffer> EglGbmBackend::renderTestFrame(DrmAbstractOutput *output)
{
for (int i = 0; i < m_outputs.count(); i++) {
if (m_outputs[i].output == output) {
beginFrame(i);
glClear(GL_COLOR_BUFFER_BIT);
return endFrameWithBuffer(i, output->geometry());
}
}
return nullptr;
beginFrame(output);
glClear(GL_COLOR_BUFFER_BIT);
return endFrameWithBuffer(output, output->geometry());
}
QSharedPointer<GLTexture> EglGbmBackend::textureForOutput(AbstractOutput *abstractOutput) const
QSharedPointer<GLTexture> EglGbmBackend::textureForOutput(AbstractOutput *output) const
{
auto itOutput = std::find_if(m_outputs.begin(), m_outputs.end(),
[abstractOutput] (const auto &output) {
return output.output == abstractOutput;
}
);
if (itOutput == m_outputs.end()) {
itOutput = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
[abstractOutput] (const auto &output) {
return output.output == abstractOutput;
}
);
if (itOutput == m_secondaryGpuOutputs.end()) {
return {};
}
}
DrmAbstractOutput *drmOutput = itOutput->output;
if (itOutput->current.shadowBuffer) {
const auto glTexture = QSharedPointer<KWin::GLTexture>::create(itOutput->current.shadowBuffer->texture(), GL_RGBA8, drmOutput->pixelSize());
Q_ASSERT(m_outputs.contains(output));
auto &renderOutput = m_outputs[output];
if (renderOutput.current.shadowBuffer) {
const auto glTexture = QSharedPointer<KWin::GLTexture>::create(renderOutput.current.shadowBuffer->texture(), GL_RGBA8, output->pixelSize());
glTexture->setYInverted(true);
return glTexture;
}
GbmBuffer *gbmBuffer = itOutput->current.gbmSurface->currentBuffer().get();
GbmBuffer *gbmBuffer = renderOutput.current.gbmSurface->currentBuffer().get();
if (!gbmBuffer) {
qCWarning(KWIN_DRM) << "Failed to record frame: No gbm buffer!";
return {};
......@@ -759,12 +701,17 @@ QSharedPointer<GLTexture> EglGbmBackend::textureForOutput(AbstractOutput *abstra
return {};
}
return QSharedPointer<EGLImageTexture>::create(eglDisplay(), image, GL_RGBA8, drmOutput->modeSize());
return QSharedPointer<EGLImageTexture>::create(eglDisplay(), image, GL_RGBA8, static_cast<DrmAbstractOutput*>(output)->modeSize());
}
bool EglGbmBackend::directScanoutAllowed(AbstractOutput *output) const
{
return !m_backend->usesSoftwareCursor() && output->directScanoutInhibited();
}
bool EglGbmBackend::directScanoutAllowed(int screen) const
bool EglGbmBackend::hasOutput(AbstractOutput *output) const
{
return !m_backend->usesSoftwareCursor