Port screenId based rendering methods to AbstractOutput

This commit is contained in:
Xaver Hugl 2021-08-24 22:55:42 +02:00
parent e6cab81b53
commit 1be65e818c
42 changed files with 349 additions and 480 deletions

View file

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

View file

@ -130,7 +130,6 @@ private:
void releaseCompositorSelection();
void deleteUnusedSupportProperties();
int screenForRenderLoop(RenderLoop *renderLoop) const;
void registerRenderLoop(RenderLoop *renderLoop, AbstractOutput *output);
void unregisterRenderLoop(RenderLoop *renderLoop);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(int screen) const
bool EglGbmBackend::directScanoutAllowed(AbstractOutput *output) const
{
return !m_backend->usesSoftwareCursor() && !m_outputs[screen].output->directScanoutInhibited();
return !m_backend->usesSoftwareCursor() && output->directScanoutInhibited();
}
bool EglGbmBackend::hasOutput(AbstractOutput *output) const
{
return m_outputs.contains(output);
}
}

View file

@ -47,17 +47,14 @@ public:
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
void init() override;
bool scanout(int screenId, SurfaceItem *surfaceItem) override;
bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override;
QSharedPointer<GLTexture> textureForOutput(AbstractOutput *requestedOutput) const override;
int screenCount() const override {
return m_outputs.count();
}
bool hasOutput(AbstractOutput *output) const override;
bool addOutput(DrmAbstractOutput *output) override;
void removeOutput(DrmAbstractOutput *output) override;
bool swapBuffers(DrmAbstractOutput *output, const QRegion &dirty) override;
@ -65,13 +62,13 @@ public:
bool exportFramebufferAsDmabuf(DrmAbstractOutput *output, int *fds, int *strides, int *offsets, uint32_t *num_fds, uint32_t *format, uint64_t *modifier) override;
QRegion beginFrameForSecondaryGpu(DrmAbstractOutput *output) override;
bool directScanoutAllowed(int screen) const override;
bool directScanoutAllowed(AbstractOutput *output) const override;
QSharedPointer<DrmBuffer> renderTestFrame(DrmAbstractOutput *output) override;
protected:
void cleanupSurfaces() override;
void aboutToStartPainting(int screenId, const QRegion &damage) override;
void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override;
private:
bool initializeEgl();
@ -99,7 +96,7 @@ private:
};
bool doesRenderFit(DrmAbstractOutput *output, const Output::RenderData &render);
bool resetOutput(Output &output, DrmAbstractOutput *drmOutput);
bool resetOutput(Output &output);
bool makeContextCurrent(const Output::RenderData &output) const;
void setViewport(const Output &output) const;
@ -107,13 +104,12 @@ private:
void renderFramebufferToSurface(Output &output);
QRegion prepareRenderingForOutput(Output &output);
QSharedPointer<DrmBuffer> importFramebuffer(Output &output, const QRegion &dirty) const;
QSharedPointer<DrmBuffer> endFrameWithBuffer(int screenId, const QRegion &dirty);
QSharedPointer<DrmBuffer> endFrameWithBuffer(AbstractOutput *output, const QRegion &dirty);
void updateBufferAge(Output &output, const QRegion &dirty);
void cleanupRenderData(Output::RenderData &output);
QVector<Output> m_outputs;
QVector<Output> m_secondaryGpuOutputs;
QMap<AbstractOutput *, Output> m_outputs;
uint32_t m_gbmFormat;
friend class EglGbmTexture;

View file

@ -57,28 +57,19 @@ void EglMultiBackend::init()
m_initialized = true;
}
QRegion EglMultiBackend::beginFrame(int screenId)
QRegion EglMultiBackend::beginFrame(AbstractOutput *output)
{
int internalScreenId;
AbstractEglBackend *backend = findBackend(screenId, internalScreenId);
Q_ASSERT(backend != nullptr);
return backend->beginFrame(internalScreenId);
return findBackend(output)->beginFrame(output);
}
void EglMultiBackend::endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion)
void EglMultiBackend::endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion)
{
int internalScreenId;
AbstractEglBackend *backend = findBackend(screenId, internalScreenId);
Q_ASSERT(backend != nullptr);
backend->endFrame(internalScreenId, damage, damagedRegion);
findBackend(output)->endFrame(output, damage, damagedRegion);
}
bool EglMultiBackend::scanout(int screenId, SurfaceItem *surfaceItem)
bool EglMultiBackend::scanout(AbstractOutput *output, SurfaceItem *surfaceItem)
{
int internalScreenId;
AbstractEglBackend *backend = findBackend(screenId, internalScreenId);
Q_ASSERT(backend != nullptr);
return backend->scanout(internalScreenId, surfaceItem);
return findBackend(output)->scanout(output, surfaceItem);
}
bool EglMultiBackend::makeCurrent()
@ -107,26 +98,20 @@ QSharedPointer<GLTexture> EglMultiBackend::textureForOutput(AbstractOutput *requ
return m_backends[0]->textureForOutput(requestedOutput);
}
AbstractEglDrmBackend *EglMultiBackend::findBackend(int screenId, int& internalScreenId) const
AbstractEglDrmBackend *EglMultiBackend::findBackend(AbstractOutput *output) const
{
int screens = 0;
for (int i = 0; i < m_backends.count(); i++) {
if (screenId < screens + m_backends[i]->screenCount()) {
internalScreenId = screenId - screens;
return m_backends[i];
for (const auto &backend : qAsConst(m_backends)) {
if (backend->hasOutput(output)) {
return backend;
}
screens += m_backends[i]->screenCount();
}
qCDebug(KWIN_DRM) << "could not find backend!" << screenId << "/" << screens;
Q_UNREACHABLE();
return nullptr;
}
bool EglMultiBackend::directScanoutAllowed(int screenId) const
bool EglMultiBackend::directScanoutAllowed(AbstractOutput *output) const
{
int internalScreenId;
AbstractEglBackend *backend = findBackend(screenId, internalScreenId);
Q_ASSERT(backend != nullptr);
return backend->directScanoutAllowed(internalScreenId);
return findBackend(output)->directScanoutAllowed(output);
}
void EglMultiBackend::addGpu(DrmGpu *gpu)

View file

@ -24,9 +24,9 @@ public:
void init() override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
bool scanout(int screenId, SurfaceItem *surfaceItem) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override;
bool makeCurrent() override;
void doneCurrent() override;
@ -35,7 +35,7 @@ public:
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
QSharedPointer<GLTexture> textureForOutput(AbstractOutput *requestedOutput) const override;
bool directScanoutAllowed(int screen) const override;
bool directScanoutAllowed(AbstractOutput *output) const override;
public Q_SLOTS:
void addGpu(DrmGpu *gpu);
@ -46,7 +46,7 @@ private:
QVector<AbstractEglDrmBackend*> m_backends;
bool m_initialized = false;
AbstractEglDrmBackend *findBackend(int screenId, int& internalScreenId) const;
AbstractEglDrmBackend *findBackend(AbstractOutput *output) const;
};
}

View file

@ -298,9 +298,9 @@ bool EglStreamBackend::initRenderingContext()
return !m_outputs.isEmpty() && makeContextCurrent(m_outputs.first());
}
bool EglStreamBackend::resetOutput(Output &o, DrmOutput *drmOutput)
bool EglStreamBackend::resetOutput(Output &o)
{
o.output = drmOutput;
const auto &drmOutput = o.output;
QSize sourceSize = drmOutput->sourceSize();
if (isPrimary()) {
@ -385,7 +385,8 @@ bool EglStreamBackend::addOutput(DrmAbstractOutput *output)
DrmOutput *drmOutput = qobject_cast<DrmOutput *>(output);
if (drmOutput) {
Output o;
if (!resetOutput(o, drmOutput)) {
o.output = drmOutput;
if (!resetOutput(o)) {
return false;
}
if (!isPrimary() && !renderingBackend()->addOutput(drmOutput)) {
@ -394,18 +395,10 @@ bool EglStreamBackend::addOutput(DrmAbstractOutput *output)
connect(drmOutput, &DrmOutput::modeChanged, this,
[drmOutput, this] {
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
[drmOutput] (const auto &o) {
return o.output == drmOutput;
}
);
if (it == m_outputs.end()) {
return;
}
resetOutput(*it, drmOutput);
resetOutput(m_outputs[drmOutput]);
}
);
m_outputs << o;
m_outputs.insert(output, o);
return true;
} else {
return false;
@ -490,9 +483,10 @@ PlatformSurfaceTexture *EglStreamBackend::createPlatformSurfaceTextureWayland(Su
return new EglStreamSurfaceTextureWayland(this, pixmap);
}
QRegion EglStreamBackend::beginFrame(int screenId)
QRegion EglStreamBackend::beginFrame(AbstractOutput *drmOutput)
{
const Output &o = m_outputs.at(screenId);
Q_ASSERT(m_outputs.contains(drmOutput));
const Output &o = m_outputs[drmOutput];
if (isPrimary()) {
makeContextCurrent(o);
if (o.shadowBuffer) {
@ -504,13 +498,12 @@ QRegion EglStreamBackend::beginFrame(int screenId)
}
}
void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion)
void EglStreamBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_ASSERT(m_outputs.contains(output));
Q_UNUSED(renderedRegion);
Output &renderOutput = m_outputs[screenId];
DrmOutput *drmOutput = renderOutput.output;
Output &renderOutput = m_outputs[output];
bool frameFailed = false;
QSharedPointer<DrmDumbBuffer> buffer;
@ -524,13 +517,13 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con
frameFailed = true;
}
} else {
if (!renderingBackend()->swapBuffers(drmOutput, damagedRegion.intersected(drmOutput->geometry()))) {
qCCritical(KWIN_DRM) << "swapping buffers on render backend for" << drmOutput << "failed!";
if (!renderingBackend()->swapBuffers(static_cast<DrmOutput*>(output), damagedRegion.intersected(output->geometry()))) {
qCCritical(KWIN_DRM) << "swapping buffers on render backend for" << output << "failed!";
frameFailed = true;
}
buffer = renderOutput.dumbSwapchain->acquireBuffer();
if (!frameFailed && !renderingBackend()->exportFramebuffer(drmOutput, buffer->data(), buffer->size(), buffer->stride())) {
qCCritical(KWIN_DRM) << "importing framebuffer from render backend for" << drmOutput << "failed!";
if (!frameFailed && !renderingBackend()->exportFramebuffer(static_cast<DrmOutput*>(output), buffer->data(), buffer->size(), buffer->stride())) {
qCCritical(KWIN_DRM) << "importing framebuffer from render backend for" << output << "failed!";
frameFailed = true;
}
}
@ -539,11 +532,11 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con
}
if (frameFailed) {
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop());
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(output->renderLoop());
renderLoopPrivate->notifyFrameFailed();
} else if (isPrimary()) {
EGLAttrib acquireAttribs[] = {
EGL_DRM_FLIP_EVENT_DATA_NV, (EGLAttrib)drmOutput,
EGL_DRM_FLIP_EVENT_DATA_NV, (EGLAttrib)output,
EGL_NONE,
};
if (!pEglStreamConsumerAcquireAttribNV(eglDisplay(), renderOutput.eglStream, acquireAttribs)) {
@ -554,15 +547,9 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con
QSharedPointer<DrmBuffer> EglStreamBackend::renderTestFrame(DrmAbstractOutput *drmOutput)
{
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
[drmOutput] (const Output &o) {
return o.output == drmOutput;
}
);
if (it == m_outputs.end()) {
return nullptr;
}
auto buffer = (*it).dumbSwapchain ? (*it).dumbSwapchain->currentBuffer() : (*it).buffer;
Q_ASSERT(m_outputs.contains(drmOutput));
auto &output = m_outputs[drmOutput];
auto buffer = output.dumbSwapchain ? output.dumbSwapchain->currentBuffer() : output.buffer;
auto size = drmOutput->sourceSize();
if (buffer->size() == size) {
return buffer;
@ -571,6 +558,11 @@ QSharedPointer<DrmBuffer> EglStreamBackend::renderTestFrame(DrmAbstractOutput *d
}
}
bool EglStreamBackend::hasOutput(AbstractOutput *output) const
{
return m_outputs.contains(output);
}
/************************************************
* EglTexture
************************************************/

View file

@ -33,14 +33,11 @@ public:
~EglStreamBackend() override;
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
void init() override;
int screenCount() const override {
return m_outputs.count();
}
bool hasOutput(AbstractOutput *output) const override;
bool addOutput(DrmAbstractOutput *output) override;
void removeOutput(DrmAbstractOutput *output) override;
@ -74,11 +71,11 @@ private:
// for operation as secondary GPU
QSharedPointer<DumbSwapchain> dumbSwapchain;
};
bool resetOutput(Output &output, DrmOutput *drmOutput);
bool resetOutput(Output &output);
bool makeContextCurrent(const Output &output);
void cleanupOutput(Output &output);
QVector<Output> m_outputs;
QMap<AbstractOutput *, Output> m_outputs;
KWaylandServer::EglStreamControllerInterface *m_eglStreamControllerInterface;
QHash<KWaylandServer::SurfaceInterface *, StreamTexture> m_streamTextures;

View file

@ -45,31 +45,24 @@ void DrmQPainterBackend::initOutput(DrmAbstractOutput *output)
Output o;
o.swapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, output->pixelSize());
o.output = output;
m_outputs << o;
m_outputs.insert(output, o);
connect(output, &DrmOutput::modeChanged, this,
[output, this] {
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
[output] (const auto &o) {
return o.output == output;
}
);
if (it == m_outputs.end()) {
return;
}
it->swapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, output->pixelSize());
it->damageJournal.setCapacity(it->swapchain->slotCount());
auto &o = m_outputs[output];
o.swapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, output->pixelSize());
o.damageJournal.setCapacity(o.swapchain->slotCount());
}
);
}
QImage *DrmQPainterBackend::bufferForScreen(int screenId)
QImage *DrmQPainterBackend::bufferForScreen(AbstractOutput *output)
{
return m_outputs[screenId].swapchain->currentBuffer()->image();
return m_outputs[output].swapchain->currentBuffer()->image();
}
QRegion DrmQPainterBackend::beginFrame(int screenId)
QRegion DrmQPainterBackend::beginFrame(AbstractOutput *output)
{
Output *rendererOutput = &m_outputs[screenId];
Output *rendererOutput = &m_outputs[output];
int bufferAge;
rendererOutput->swapchain->acquireBuffer(&bufferAge);
@ -77,9 +70,9 @@ QRegion DrmQPainterBackend::beginFrame(int screenId)
return rendererOutput->damageJournal.accumulate(bufferAge, rendererOutput->output->geometry());
}
void DrmQPainterBackend::endFrame(int screenId, const QRegion &damage)
void DrmQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage)
{
Output &rendererOutput = m_outputs[screenId];
Output &rendererOutput = m_outputs[output];
DrmAbstractOutput *drmOutput = rendererOutput.output;
QSharedPointer<DrmDumbBuffer> back = rendererOutput.swapchain->currentBuffer();

View file

@ -31,9 +31,9 @@ class DrmQPainterBackend : public QPainterBackend
public:
DrmQPainterBackend(DrmBackend *backend, DrmGpu *gpu);
QImage *bufferForScreen(int screenId) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage) override;
QImage *bufferForScreen(AbstractOutput *output) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage) override;
private:
void initOutput(DrmAbstractOutput *output);
@ -42,7 +42,7 @@ private:
QSharedPointer<DumbSwapchain> swapchain;
DamageJournal damageJournal;
};
QVector<Output> m_outputs;
QMap<AbstractOutput *, Output> m_outputs;
DrmBackend *m_backend;
DrmGpu *m_gpu;
};

View file

@ -63,28 +63,26 @@ void FramebufferQPainterBackend::deactivate()
FramebufferQPainterBackend::~FramebufferQPainterBackend() = default;
QImage* FramebufferQPainterBackend::bufferForScreen(int screenId)
QImage* FramebufferQPainterBackend::bufferForScreen(AbstractOutput *output)
{
Q_UNUSED(screenId)
Q_UNUSED(output)
return &m_renderBuffer;
}
QRegion FramebufferQPainterBackend::beginFrame(int screenId)
QRegion FramebufferQPainterBackend::beginFrame(AbstractOutput *output)
{
return screens()->geometry(screenId);
return output->geometry();
}
void FramebufferQPainterBackend::endFrame(int screenId, const QRegion &damage)
void FramebufferQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage)
{
Q_UNUSED(screenId)
Q_UNUSED(damage)
if (!kwinApp()->platform()->session()->isActive()) {
return;
}
FramebufferOutput *output = static_cast<FramebufferOutput *>(m_backend->findOutput(screenId));
output->vsyncMonitor()->arm();
static_cast<FramebufferOutput *>(output)->vsyncMonitor()->arm();
QPainter p(&m_backBuffer);
p.drawImage(QPoint(0, 0), m_backend->isBGR() ? m_renderBuffer.rgbSwapped() : m_renderBuffer);

View file

@ -24,9 +24,9 @@ public:
FramebufferQPainterBackend(FramebufferBackend *backend);
~FramebufferQPainterBackend() override;
QImage *bufferForScreen(int screenId) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage) override;
QImage *bufferForScreen(AbstractOutput *output) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage) override;
private:
void reactivate();

View file

@ -150,9 +150,9 @@ PlatformSurfaceTexture *EglGbmBackend::createPlatformSurfaceTextureWayland(Surfa
return new BasicEGLSurfaceTextureWayland(this, pixmap);
}
QRegion EglGbmBackend::beginFrame(int screenId)
QRegion EglGbmBackend::beginFrame(AbstractOutput *output)
{
Q_UNUSED(screenId)
Q_UNUSED(output)
if (!GLRenderTarget::isRenderTargetBound()) {
GLRenderTarget::pushRenderTarget(m_fbo);
}
@ -190,14 +190,13 @@ static void convertFromGLImage(QImage &img, int w, int h)
img = img.mirrored();
}
void EglGbmBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion)
void EglGbmBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(renderedRegion)
Q_UNUSED(damagedRegion)
glFlush();
VirtualOutput *output = static_cast<VirtualOutput *>(m_backend->findOutput(screenId));
output->vsyncMonitor()->arm();
static_cast<VirtualOutput *>(output)->vsyncMonitor()->arm();
if (m_backend->saveFrames()) {
QImage img = QImage(QSize(m_backBuffer->width(), m_backBuffer->height()), QImage::Format_ARGB32);

View file

@ -28,8 +28,8 @@ public:
~EglGbmBackend() override;
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void init() override;
private:

View file

@ -27,35 +27,35 @@ VirtualQPainterBackend::VirtualQPainterBackend(VirtualBackend *backend)
VirtualQPainterBackend::~VirtualQPainterBackend() = default;
QImage *VirtualQPainterBackend::bufferForScreen(int screen)
QImage *VirtualQPainterBackend::bufferForScreen(AbstractOutput *output)
{
return &m_backBuffers[screen];
return &m_backBuffers[output];
}
QRegion VirtualQPainterBackend::beginFrame(int screenId)
QRegion VirtualQPainterBackend::beginFrame(AbstractOutput *output)
{
return screens()->geometry(screenId);
return output->geometry();
}
void VirtualQPainterBackend::createOutputs()
{
m_backBuffers.clear();
for (int i = 0; i < screens()->count(); ++i) {
QImage buffer(screens()->size(i) * screens()->scale(i), QImage::Format_RGB32);
const auto outputs = m_backend->enabledOutputs();
for (const auto &output : outputs) {
QImage buffer(output->pixelSize(), QImage::Format_RGB32);
buffer.fill(Qt::black);
m_backBuffers << buffer;
m_backBuffers.insert(output, buffer);
}
}
void VirtualQPainterBackend::endFrame(int screenId, const QRegion &damage)
void VirtualQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage)
{
Q_UNUSED(damage)
VirtualOutput *output = static_cast<VirtualOutput *>(m_backend->findOutput(screenId));
output->vsyncMonitor()->arm();
static_cast<VirtualOutput *>(output)->vsyncMonitor()->arm();
if (m_backend->saveFrames()) {
m_backBuffers[screenId].save(QStringLiteral("%1/screen%2-%3.png").arg(m_backend->screenshotDirPath(), QString::number(screenId), QString::number(m_frameCounter++)));
m_backBuffers[output].save(QStringLiteral("%1/%s-%3.png").arg(m_backend->screenshotDirPath(), output->name(), QString::number(m_frameCounter++)));
}
}

View file

@ -13,6 +13,7 @@
#include <QObject>
#include <QVector>
#include <QMap>
namespace KWin
{
@ -26,14 +27,14 @@ public:
VirtualQPainterBackend(VirtualBackend *backend);
~VirtualQPainterBackend() override;
QImage *bufferForScreen(int screenId) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage) override;
QImage *bufferForScreen(AbstractOutput *output) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage) override;
private:
void createOutputs();
QVector<QImage> m_backBuffers;
QMap<AbstractOutput *, QImage> m_backBuffers;
VirtualBackend *m_backend;
int m_frameCounter = 0;
};

View file

@ -141,11 +141,12 @@ void EglWaylandBackend::cleanupSurfaces()
bool EglWaylandBackend::createEglWaylandOutput(AbstractOutput *waylandOutput)
{
auto *output = new EglWaylandOutput(static_cast<WaylandOutput *>(waylandOutput), this);
const auto &output = new EglWaylandOutput(static_cast<WaylandOutput *>(waylandOutput), this);
if (!output->init(this)) {
delete output;
return false;
}
m_outputs << output;
m_outputs.insert(waylandOutput, output);
return true;
}
@ -298,15 +299,16 @@ static QVector<EGLint> regionToRects(const QRegion &region, AbstractWaylandOutpu
return rects;
}
void EglWaylandBackend::aboutToStartPainting(int screenId, const QRegion &damagedRegion)
void EglWaylandBackend::aboutToStartPainting(AbstractOutput *output, const QRegion &damagedRegion)
{
Q_ASSERT_X(screenId != -1, "aboutToStartPainting", "not using per screen rendering");
EglWaylandOutput *output = m_outputs.at(screenId);
if (output->m_bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) {
const QRegion region = damagedRegion & output->m_waylandOutput->geometry();
Q_ASSERT_X(output, "aboutToStartPainting", "not using per screen rendering");
Q_ASSERT(m_outputs.contains(output));
const auto &eglOutput = m_outputs[output];
if (eglOutput->m_bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) {
const QRegion region = damagedRegion & eglOutput->m_waylandOutput->geometry();
QVector<EGLint> rects = regionToRects(region, output->m_waylandOutput);
const bool correct = eglSetDamageRegionKHR(eglDisplay(), output->m_eglSurface,
QVector<EGLint> rects = regionToRects(region, eglOutput->m_waylandOutput);
const bool correct = eglSetDamageRegionKHR(eglDisplay(), eglOutput->m_eglSurface,
rects.data(), rects.count()/4);
if (!correct) {
qCWarning(KWIN_WAYLAND_BACKEND) << "failed eglSetDamageRegionKHR" << eglGetError();
@ -350,27 +352,29 @@ PlatformSurfaceTexture *EglWaylandBackend::createPlatformSurfaceTextureWayland(S
return new BasicEGLSurfaceTextureWayland(this, pixmap);
}
QRegion EglWaylandBackend::beginFrame(int screenId)
QRegion EglWaylandBackend::beginFrame(AbstractOutput *output)
{
Q_ASSERT(m_outputs.contains(output));
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
auto *output = m_outputs.at(screenId);
makeContextCurrent(output);
const auto &eglOutput = m_outputs[output];
makeContextCurrent(eglOutput);
if (supportsBufferAge()) {
return output->m_damageJournal.accumulate(output->m_bufferAge, output->m_waylandOutput->geometry());
return eglOutput->m_damageJournal.accumulate(eglOutput->m_bufferAge, eglOutput->m_waylandOutput->geometry());
}
return QRegion();
}
void EglWaylandBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion)
void EglWaylandBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_ASSERT(m_outputs.contains(output));
Q_UNUSED(renderedRegion);
EglWaylandOutput *output = m_outputs[screenId];
QRegion damage = damagedRegion.intersected(output->m_waylandOutput->geometry());
presentOnSurface(output, damage);
const auto &eglOutput = m_outputs[output];
QRegion damage = damagedRegion.intersected(eglOutput->m_waylandOutput->geometry());
presentOnSurface(eglOutput, damage);
if (supportsBufferAge()) {
output->m_damageJournal.add(damage);
eglOutput->m_damageJournal.add(damage);
}
}

View file

@ -71,15 +71,15 @@ public:
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
void init() override;
bool havePlatformBase() const {
return m_havePlatformBase;
}
void aboutToStartPainting(int screenId, const QRegion &damage) override;
void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override;
private:
bool initializeEgl();
@ -95,7 +95,7 @@ private:
void presentOnSurface(EglWaylandOutput *output, const QRegion &damagedRegion);
WaylandBackend *m_backend;
QVector<EglWaylandOutput*> m_outputs;
QMap<AbstractOutput *, EglWaylandOutput*> m_outputs;
bool m_havePlatformBase;
friend class EglWaylandTexture;
};

View file

@ -169,25 +169,25 @@ void WaylandQPainterBackend::createOutput(AbstractOutput *waylandOutput)
{
auto *output = new WaylandQPainterOutput(static_cast<WaylandOutput *>(waylandOutput), this);
output->init(m_backend->shmPool());
m_outputs << output;
m_outputs.insert(waylandOutput, output);
}
void WaylandQPainterBackend::endFrame(int screenId, const QRegion &damage)
void WaylandQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage)
{
WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId);
WaylandQPainterOutput *rendererOutput = m_outputs[output];
Q_ASSERT(rendererOutput);
rendererOutput->present(rendererOutput->mapToLocal(damage));
}
QImage *WaylandQPainterBackend::bufferForScreen(int screenId)
QImage *WaylandQPainterBackend::bufferForScreen(AbstractOutput *output)
{
return &m_outputs[screenId]->back()->image;
return &m_outputs[output]->back()->image;
}
QRegion WaylandQPainterBackend::beginFrame(int screenId)
QRegion WaylandQPainterBackend::beginFrame(AbstractOutput *output)
{
WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId);
WaylandQPainterOutput *rendererOutput = m_outputs[output];
Q_ASSERT(rendererOutput);
WaylandQPainterBufferSlot *slot = rendererOutput->acquire();

View file

@ -83,17 +83,17 @@ public:
explicit WaylandQPainterBackend(WaylandBackend *b);
~WaylandQPainterBackend() override;
QImage *bufferForScreen(int screenId) override;
QImage *bufferForScreen(AbstractOutput *output) override;
void endFrame(int screenId, const QRegion& damage) override;
QRegion beginFrame(int screenId) override;
void endFrame(AbstractOutput *output, const QRegion& damage) override;
QRegion beginFrame(AbstractOutput *output) override;
private:
void createOutput(AbstractOutput *waylandOutput);
void frameRendered();
WaylandBackend *m_backend;
QVector<WaylandQPainterOutput*> m_outputs;
QMap<AbstractOutput *, WaylandQPainterOutput*> m_outputs;
};
}

View file

@ -88,9 +88,9 @@ void EglBackend::screenGeometryChanged()
m_bufferAge = 0;
}
QRegion EglBackend::beginFrame(int screenId)
QRegion EglBackend::beginFrame(AbstractOutput *output)
{
Q_UNUSED(screenId)
Q_UNUSED(output)
makeCurrent();
const QSize size = screens()->size();
@ -106,9 +106,9 @@ QRegion EglBackend::beginFrame(int screenId)
return repaint;
}
void EglBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion)
void EglBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(screenId)
Q_UNUSED(output)
// Start the software vsync monitor. There is no any reliable way to determine when
// eglSwapBuffers() or eglSwapBuffersWithDamageEXT() completes.

View file

@ -31,8 +31,8 @@ public:
void init() override;
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *texture) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
private:
void screenGeometryChanged();

View file

@ -739,9 +739,9 @@ PlatformSurfaceTexture *GlxBackend::createPlatformSurfaceTextureX11(SurfacePixma
return new GlxSurfaceTextureX11(this, pixmap);
}
QRegion GlxBackend::beginFrame(int screenId)
QRegion GlxBackend::beginFrame(AbstractOutput *output)
{
Q_UNUSED(screenId)
Q_UNUSED(output)
QRegion repaint;
makeCurrent();
@ -758,9 +758,9 @@ QRegion GlxBackend::beginFrame(int screenId)
return repaint;
}
void GlxBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion)
void GlxBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(screenId)
Q_UNUSED(output)
// If the GLX_INTEL_swap_event extension is not used for getting presentation feedback,
// assume that the frame will be presented at the next vblank event, this is racy.

View file

@ -72,8 +72,8 @@ public:
GlxBackend(Display *display, X11StandalonePlatform *backend);
~GlxBackend() override;
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
bool makeCurrent() override;
void doneCurrent() override;
OverlayWindow* overlayWindow() const override;

View file

@ -47,12 +47,13 @@ void EglX11Backend::cleanupSurfaces()
bool EglX11Backend::createSurfaces()
{
for (int i = 0; i < screens()->count(); ++i) {
EGLSurface s = createSurface(m_backend->windowForScreen(i));
const auto &outputs = m_backend->outputs();
for (const auto &output : outputs) {
EGLSurface s = createSurface(m_backend->windowForScreen(output));
if (s == EGL_NO_SURFACE) {
return false;
}
m_surfaces << s;
m_surfaces.insert(output, s);
}
if (m_surfaces.isEmpty()) {
return false;
@ -61,29 +62,26 @@ bool EglX11Backend::createSurfaces()
return true;
}
QRegion EglX11Backend::beginFrame(int screenId)
QRegion EglX11Backend::beginFrame(AbstractOutput *output)
{
makeContextCurrent(m_surfaces.at(screenId));
setupViewport(screenId);
return screens()->geometry(screenId);
makeContextCurrent(m_surfaces[output]);
setupViewport(output);
return output->geometry();
}
void EglX11Backend::setupViewport(int screenId)
void EglX11Backend::setupViewport(AbstractOutput *output)
{
qreal scale = screens()->scale(screenId);
const QSize size = screens()->geometry(screenId).size() * scale;
const QSize size = output->pixelSize() * output->scale();
glViewport(0, 0, size.width(), size.height());
}
void EglX11Backend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion)
void EglX11Backend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(damagedRegion)
X11WindowedOutput *output = static_cast<X11WindowedOutput *>(kwinApp()->platform()->findOutput(screenId));
output->vsyncMonitor()->arm();
static_cast<X11WindowedOutput *>(output)->vsyncMonitor()->arm();
const QRect &outputGeometry = screens()->geometry(screenId);
presentSurface(m_surfaces.at(screenId), renderedRegion, outputGeometry);
presentSurface(m_surfaces[output], renderedRegion, output->geometry());
}
void EglX11Backend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry)

View file

@ -10,6 +10,8 @@
#define KWIN_EGL_X11_BACKEND_H
#include "eglonxbackend.h"
#include <QMap>
namespace KWin
{
@ -29,18 +31,18 @@ public:
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
void init() override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
protected:
void cleanupSurfaces() override;
bool createSurfaces() override;
private:
void setupViewport(int screenId);
void setupViewport(AbstractOutput *output);
void presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry);
QVector<EGLSurface> m_surfaces;
QMap<AbstractOutput *, EGLSurface> m_surfaces;
X11WindowedBackend *m_backend;
};

View file

@ -35,32 +35,31 @@ void X11WindowedQPainterBackend::createOutputs()
{
qDeleteAll(m_outputs);
m_outputs.clear();
for (int i = 0; i < screens()->count(); ++i) {
const auto &outputs = m_backend->outputs();
for (const auto &x11Output : outputs) {
Output *output = new Output;
output->window = m_backend->windowForScreen(i);
output->buffer = QImage(screens()->size(i) * screens()->scale(i), QImage::Format_RGB32);
output->window = m_backend->windowForScreen(x11Output);
output->buffer = QImage(x11Output->pixelSize() * x11Output->scale(), QImage::Format_RGB32);
output->buffer.fill(Qt::black);
m_outputs << output;
m_outputs.insert(x11Output, output);
}
}
QImage *X11WindowedQPainterBackend::bufferForScreen(int screen)
QImage *X11WindowedQPainterBackend::bufferForScreen(AbstractOutput *output)
{
return &m_outputs.at(screen)->buffer;
return &m_outputs[output]->buffer;
}
QRegion X11WindowedQPainterBackend::beginFrame(int screenId)
QRegion X11WindowedQPainterBackend::beginFrame(AbstractOutput *output)
{
Q_UNUSED(screenId)
return screens()->geometry(screenId);
return output->geometry();
}
void X11WindowedQPainterBackend::endFrame(int screenId, const QRegion &damage)
void X11WindowedQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage)
{
Q_UNUSED(damage)
X11WindowedOutput *output = static_cast<X11WindowedOutput *>(kwinApp()->platform()->findOutput(screenId));
output->vsyncMonitor()->arm();
static_cast<X11WindowedOutput *>(output)->vsyncMonitor()->arm();
xcb_connection_t *c = m_backend->connection();
const xcb_window_t window = m_backend->window();
@ -69,7 +68,7 @@ void X11WindowedQPainterBackend::endFrame(int screenId, const QRegion &damage)
xcb_create_gc(c, m_gc, window, 0, nullptr);
}
Output *rendererOutput = m_outputs.value(screenId);
Output *rendererOutput = m_outputs[output];
Q_ASSERT(rendererOutput);
// TODO: only update changes?

View file

@ -14,6 +14,7 @@
#include <QObject>
#include <QImage>
#include <QVector>
#include <QMap>
#include <xcb/xcb.h>
@ -29,9 +30,9 @@ public:
X11WindowedQPainterBackend(X11WindowedBackend *backend);
~X11WindowedQPainterBackend() override;
QImage *bufferForScreen(int screenId) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage) override;
QImage *bufferForScreen(AbstractOutput *output) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &damage) override;
private:
void createOutputs();
@ -41,7 +42,7 @@ private:
xcb_window_t window;
QImage buffer;
};
QVector<Output*> m_outputs;
QMap<AbstractOutput *, Output*> m_outputs;
};
}

View file

@ -525,12 +525,17 @@ void X11WindowedBackend::warpPointer(const QPointF &globalPos)
xcb_flush(m_connection);
}
xcb_window_t X11WindowedBackend::windowForScreen(int screen) const
xcb_window_t X11WindowedBackend::windowForScreen(AbstractOutput *output) const
{
if (screen > m_outputs.count()) {
if (!output) {
return XCB_WINDOW_NONE;
}
return m_outputs.at(screen)->window();
return static_cast<X11WindowedOutput*>(output)->window();
}
xcb_window_t X11WindowedBackend::window() const
{
return m_outputs.first()->window();
}
Outputs X11WindowedBackend::outputs() const

View file

@ -47,10 +47,8 @@ public:
int screenNumer() const {
return m_screenNumber;
}
xcb_window_t window() const {
return windowForScreen(0);
}
xcb_window_t windowForScreen(int screen) const;
xcb_window_t window() const;
xcb_window_t windowForScreen(AbstractOutput *output) const;
Display *display() const {
return m_display;
}

View file

@ -34,6 +34,7 @@
#include "shadowitem.h"
#include "surfaceitem.h"
#include "windowitem.h"
#include "abstract_output.h"
#include <logging.h>
#include <cmath>
@ -342,9 +343,9 @@ void SceneOpenGL2::paintCursor(const QRegion &rendered)
glDisable(GL_BLEND);
}
void SceneOpenGL::aboutToStartPainting(int screenId, const QRegion &damage)
void SceneOpenGL::aboutToStartPainting(AbstractOutput *output, const QRegion &damage)
{
m_backend->aboutToStartPainting(screenId, damage);
m_backend->aboutToStartPainting(output, damage);
}
static SurfaceItem *findTopMostSurface(SurfaceItem *item)
@ -357,14 +358,14 @@ static SurfaceItem *findTopMostSurface(SurfaceItem *item)
}
}
void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Toplevel *> &toplevels,
void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QList<Toplevel *> &toplevels,
RenderLoop *renderLoop)
{
if (m_resetOccurred) {
return; // A graphics reset has occurred, do nothing.
}
painted_screen = screenId;
painted_screen = output;
// actually paint the frame, flushed with the NEXT frame
createStackingOrder(toplevels);
@ -373,9 +374,9 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Topleve
QRegion repaint;
QRect geo;
qreal scaling;
if (screenId != -1) {
geo = screens()->geometry(screenId);
scaling = screens()->scale(screenId);
if (output) {
geo = output->geometry();
scaling = output->scale();
} else {
geo = screens()->geometry();
scaling = 1;
@ -391,7 +392,7 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Topleve
for (int i = stacking_order.count() - 1; i >=0; i--) {
Window *window = stacking_order[i];
Toplevel *toplevel = window->window();
if (toplevel->isOnScreen(screenId) && window->isVisible() && toplevel->opacity() > 0) {
if (output && toplevel->isOnOutput(output) && window->isVisible() && toplevel->opacity() > 0) {
AbstractClient *c = dynamic_cast<AbstractClient*>(toplevel);
if (!c || !c->isFullScreen()) {
break;
@ -420,14 +421,14 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Topleve
renderLoop->setFullscreenSurface(fullscreenSurface);
bool directScanout = false;
if (m_backend->directScanoutAllowed(screenId) && !static_cast<EffectsHandlerImpl*>(effects)->blocksDirectScanout()) {
directScanout = m_backend->scanout(screenId, fullscreenSurface);
if (m_backend->directScanoutAllowed(output) && !static_cast<EffectsHandlerImpl*>(effects)->blocksDirectScanout()) {
directScanout = m_backend->scanout(output, fullscreenSurface);
}
if (directScanout) {
renderLoop->endFrame();
} else {
// prepare rendering makescontext current on the output
repaint = m_backend->beginFrame(screenId);
repaint = m_backend->beginFrame(output);
GLVertexBuffer::setVirtualScreenGeometry(geo);
GLRenderTarget::setVirtualScreenGeometry(geo);
@ -440,7 +441,7 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Topleve
renderLoop, projectionMatrix()); // call generic implementation
paintCursor(valid);
if (!GLPlatform::instance()->isGLES() && screenId == -1) {
if (!GLPlatform::instance()->isGLES() && !output) {
const QSize &screenSize = screens()->size();
const QRegion displayRegion(0, 0, screenSize.width(), screenSize.height());
@ -458,7 +459,7 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Topleve
renderLoop->endFrame();
GLVertexBuffer::streamingBuffer()->endOfFrame();
m_backend->endFrame(screenId, valid, update);
m_backend->endFrame(output, valid, update);
GLVertexBuffer::streamingBuffer()->framePosted();
}
}

View file

@ -32,7 +32,7 @@ public:
class EffectFrame;
~SceneOpenGL() override;
bool initFailed() const override;
void paint(int screenId, const QRegion &damage, const QList<Toplevel *> &windows,
void paint(AbstractOutput *output, const QRegion &damage, const QList<Toplevel *> &windows,
RenderLoop *renderLoop) override;
Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame) override;
Shadow *createShadow(Toplevel *toplevel) override;
@ -62,7 +62,7 @@ public:
protected:
SceneOpenGL(OpenGLBackend *backend, QObject *parent = nullptr);
void paintBackground(const QRegion &region) override;
void aboutToStartPainting(int screenId, const QRegion &damage) override;
void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override;
void extendPaintRegion(QRegion &region, bool opaqueFullscreen) override;
QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const;
void paintDesktop(int desktop, int mask, const QRegion &region, ScreenPaintData &data) override;

View file

@ -22,6 +22,7 @@
#include "toplevel.h"
#include "platform.h"
#include "windowitem.h"
#include "abstract_output.h"
#include <kwineffectquickview.h>
// Qt
@ -79,18 +80,18 @@ void SceneQPainter::paintGenericScreen(int mask, const ScreenPaintData &data)
m_painter->restore();
}
void SceneQPainter::paint(int screenId, const QRegion &damage, const QList<Toplevel *> &toplevels,
void SceneQPainter::paint(AbstractOutput *output, const QRegion &damage, const QList<Toplevel *> &toplevels,
RenderLoop *renderLoop)
{
Q_ASSERT(kwinApp()->platform()->isPerScreenRenderingEnabled());
painted_screen = screenId;
painted_screen = output;
createStackingOrder(toplevels);
const QRegion repaint = m_backend->beginFrame(screenId);
const QRect geometry = screens()->geometry(screenId);
const QRegion repaint = m_backend->beginFrame(output);
const QRect geometry = output->geometry();
QImage *buffer = m_backend->bufferForScreen(screenId);
QImage *buffer = m_backend->bufferForScreen(output);
if (buffer && !buffer->isNull()) {
renderLoop->beginFrame();
m_painter->begin(buffer);
@ -102,7 +103,7 @@ void SceneQPainter::paint(int screenId, const QRegion &damage, const QList<Tople
m_painter->end();
renderLoop->endFrame();
m_backend->endFrame(screenId, updateRegion);
m_backend->endFrame(output, updateRegion);
}
// do cleanup
@ -159,9 +160,9 @@ Shadow *SceneQPainter::createShadow(Toplevel *toplevel)
return new SceneQPainterShadow(toplevel);
}
QImage *SceneQPainter::qpainterRenderBuffer(int screenId) const
QImage *SceneQPainter::qpainterRenderBuffer(AbstractOutput *output) const
{
return m_backend->bufferForScreen(screenId);
return m_backend->bufferForScreen(output);
}
//****************************************

View file

@ -24,7 +24,7 @@ class KWIN_EXPORT SceneQPainter : public Scene
public:
~SceneQPainter() override;
OverlayWindow* overlayWindow() const override;
void paint(int screenId, const QRegion &damage, const QList<Toplevel *> &windows,
void paint(AbstractOutput *output, const QRegion &damage, const QList<Toplevel *> &windows,
RenderLoop *renderLoop) override;
void paintGenericScreen(int mask, const ScreenPaintData &data) override;
CompositingType compositingType() const override;
@ -40,7 +40,7 @@ public:
}
QPainter *scenePainter() const override;
QImage *qpainterRenderBuffer(int screenId) const override;
QImage *qpainterRenderBuffer(AbstractOutput *output) const override;
QPainterBackend *backend() const {
return m_backend.data();

View file

@ -85,11 +85,7 @@ namespace KWin
Scene::Scene(QObject *parent)
: QObject(parent)
{
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Scene::reallocRepaints);
connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Scene::reallocRepaints);
}
reallocRepaints();
connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Scene::removeRepaints);
}
Scene::~Scene()
@ -101,14 +97,10 @@ void Scene::addRepaint(const QRegion &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 = region & output->geometry();
if (!dirtyRegion.isEmpty()) {
m_repaints[screenId] += dirtyRegion;
m_repaints[output] += dirtyRegion;
output->renderLoop()->scheduleRepaint();
}
}
@ -118,27 +110,19 @@ void Scene::addRepaint(const QRegion &region)
}
}
QRegion Scene::repaints(int screenId) const
QRegion Scene::repaints(AbstractOutput *output) const
{
const int index = screenId == -1 ? 0 : screenId;
return m_repaints[index];
return m_repaints.value(output, infiniteRegion());
}
void Scene::resetRepaints(int screenId)
void Scene::resetRepaints(AbstractOutput *output)
{
const int index = screenId == -1 ? 0 : screenId;
m_repaints[index] = QRegion();
m_repaints.insert(output, QRegion());
}
void Scene::reallocRepaints()
void Scene::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);
}
// returns mask and possibly modified region
@ -164,7 +148,7 @@ void Scene::paintScreen(const QRegion &damage, const QRegion &repaint,
QRegion region = damage;
auto screen = effects->findScreen(painted_screen);
auto screen = effects->findScreen(kwinApp()->platform()->enabledOutputs().indexOf(painted_screen));
ScreenPrePaintData pdata;
pdata.mask = (damage == displayRegion) ? 0 : PAINT_SCREEN_REGION;
pdata.paint = region;
@ -221,13 +205,13 @@ void Scene::finalPaintScreen(int mask, const QRegion &region, ScreenPaintData& d
paintSimpleScreen(mask, region);
}
static void resetRepaintsHelper(Item *item, int screen)
static void resetRepaintsHelper(Item *item, AbstractOutput *output)
{
item->resetRepaints(screen);
item->resetRepaints(output);
const auto childItems = item->childItems();
for (Item *childItem : childItems) {
resetRepaintsHelper(childItem, screen);
resetRepaintsHelper(childItem, output);
}
}
@ -273,14 +257,14 @@ void Scene::paintGenericScreen(int orig_mask, const ScreenPaintData &)
}
}
static void accumulateRepaints(Item *item, int screen, QRegion *repaints)
static void accumulateRepaints(Item *item, AbstractOutput *output, QRegion *repaints)
{
*repaints += item->repaints(screen);
item->resetRepaints(screen);
*repaints += item->repaints(output);
item->resetRepaints(output);
const auto childItems = item->childItems();
for (Item *childItem : childItems) {
accumulateRepaints(childItem, screen, repaints);
accumulateRepaints(childItem, output, repaints);
}
}
@ -503,9 +487,9 @@ void Scene::paintDesktop(int desktop, int mask, const QRegion &region, ScreenPai
static_cast<EffectsHandlerImpl*>(effects)->paintDesktop(desktop, mask, region, data);
}
void Scene::aboutToStartPainting(int screenId, const QRegion &damage)
void Scene::aboutToStartPainting(AbstractOutput *output, const QRegion &damage)
{
Q_UNUSED(screenId)
Q_UNUSED(output)
Q_UNUSED(damage)
}
@ -554,9 +538,9 @@ QPainter *Scene::scenePainter() const
return nullptr;
}
QImage *Scene::qpainterRenderBuffer(int screenId) const
QImage *Scene::qpainterRenderBuffer(AbstractOutput *output) const
{
Q_UNUSED(screenId)
Q_UNUSED(output)
return nullptr;
}

View file

@ -59,10 +59,10 @@ public:
void addRepaint(const QRegion &region);
/**
* Returns the repaints region for output with the specified @a screenId.
* Returns the repaints region for output with the specified @a output.
*/
QRegion repaints(int screenId) const;
void resetRepaints(int screenId);
QRegion repaints(AbstractOutput *output) const;
void resetRepaints(AbstractOutput *output);
// Returns true if the ctor failed to properly initialize.
virtual bool initFailed() const = 0;
@ -72,7 +72,7 @@ public:
// The entry point for the main part of the painting pass.
// returns the time since the last vblank signal - if there's one
// ie. "what of this frame is lost to painting"
virtual void paint(int screenId, const QRegion &damage, const QList<Toplevel *> &windows,
virtual void paint(AbstractOutput *output, const QRegion &damage, const QList<Toplevel *> &windows,
RenderLoop *renderLoop) = 0;
/**
@ -159,7 +159,7 @@ public:
* The render buffer used by a QPainter based compositor.
* Default implementation returns @c nullptr.
*/
virtual QImage *qpainterRenderBuffer(int screenId) const;
virtual QImage *qpainterRenderBuffer(AbstractOutput *output) const;
/**
* The backend specific extensions (e.g. EGL/GLX extensions).
@ -214,7 +214,7 @@ protected:
*
* @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);
// called after all effects had their paintWindow() called
void finalPaintWindow(EffectWindowImpl* w, int mask, const QRegion &region, WindowPaintData& data);
// shared implementation, starts painting the window
@ -245,15 +245,15 @@ protected:
// The dirty region before it was unioned with repaint_region
QRegion damaged_region;
// The screen that is being currently painted
int painted_screen = -1;
AbstractOutput *painted_screen = nullptr;
// windows in their stacking order
QVector< Window* > stacking_order;
private:
void removeRepaints(AbstractOutput *output);
std::chrono::milliseconds m_expectedPresentTimestamp = std::chrono::milliseconds::zero();
void reallocRepaints();
QHash< Toplevel*, Window* > m_windows;
QVector<QRegion> m_repaints;
QMap<AbstractOutput *, QRegion> m_repaints;
// how many times finalPaintScreen() has been called
int m_paintScreenCount = 0;
};