Port screenId based rendering methods to AbstractOutput
This commit is contained in:
parent
e6cab81b53
commit
1be65e818c
42 changed files with 349 additions and 480 deletions
|
@ -393,16 +393,6 @@ void Compositor::handleOutputDisabled(AbstractOutput *output)
|
||||||
unregisterRenderLoop(output->renderLoop());
|
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()
|
void Compositor::scheduleRepaint()
|
||||||
{
|
{
|
||||||
for (auto it = m_renderLoops.constBegin(); it != m_renderLoops.constEnd(); ++it) {
|
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)
|
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
|
// Create a list of all windows in the stacking order
|
||||||
QList<Toplevel *> windows = Workspace::self()->xStackingOrder();
|
QList<Toplevel *> windows = Workspace::self()->xStackingOrder();
|
||||||
|
@ -617,10 +607,10 @@ void Compositor::composite(RenderLoop *renderLoop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QRegion repaints = m_scene->repaints(screenId);
|
const QRegion repaints = m_scene->repaints(output);
|
||||||
m_scene->resetRepaints(screenId);
|
m_scene->resetRepaints(output);
|
||||||
|
|
||||||
m_scene->paint(screenId, repaints, windows, renderLoop);
|
m_scene->paint(output, repaints, windows, renderLoop);
|
||||||
|
|
||||||
if (waylandServer()) {
|
if (waylandServer()) {
|
||||||
const std::chrono::milliseconds frameTime =
|
const std::chrono::milliseconds frameTime =
|
||||||
|
@ -634,7 +624,7 @@ void Compositor::composite(RenderLoop *renderLoop)
|
||||||
!(window->isLockScreen() || window->isInputMethod())) {
|
!(window->isLockScreen() || window->isInputMethod())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!window->isOnScreen(screenId)) {
|
if (!window->isOnOutput(output)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (auto surface = window->surface()) {
|
if (auto surface = window->surface()) {
|
||||||
|
|
|
@ -130,7 +130,6 @@ private:
|
||||||
void releaseCompositorSelection();
|
void releaseCompositorSelection();
|
||||||
void deleteUnusedSupportProperties();
|
void deleteUnusedSupportProperties();
|
||||||
|
|
||||||
int screenForRenderLoop(RenderLoop *renderLoop) const;
|
|
||||||
void registerRenderLoop(RenderLoop *renderLoop, AbstractOutput *output);
|
void registerRenderLoop(RenderLoop *renderLoop, AbstractOutput *output);
|
||||||
void unregisterRenderLoop(RenderLoop *renderLoop);
|
void unregisterRenderLoop(RenderLoop *renderLoop);
|
||||||
|
|
||||||
|
|
46
src/item.cpp
46
src/item.cpp
|
@ -19,20 +19,13 @@ namespace KWin
|
||||||
Item::Item(Item *parent)
|
Item::Item(Item *parent)
|
||||||
{
|
{
|
||||||
setParentItem(parent);
|
setParentItem(parent);
|
||||||
|
connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Item::removeRepaints);
|
||||||
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
|
|
||||||
connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Item::reallocRepaints);
|
|
||||||
connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Item::reallocRepaints);
|
|
||||||
}
|
|
||||||
reallocRepaints();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item::~Item()
|
Item::~Item()
|
||||||
{
|
{
|
||||||
setParentItem(nullptr);
|
setParentItem(nullptr);
|
||||||
|
for (const auto &dirty : qAsConst(m_repaints)) {
|
||||||
for (int i = 0; i < m_repaints.count(); ++i) {
|
|
||||||
const QRegion dirty = repaints(i);
|
|
||||||
if (!dirty.isEmpty()) {
|
if (!dirty.isEmpty()) {
|
||||||
Compositor::self()->addRepaint(dirty);
|
Compositor::self()->addRepaint(dirty);
|
||||||
}
|
}
|
||||||
|
@ -262,19 +255,15 @@ void Item::scheduleRepaintInternal(const QRegion ®ion)
|
||||||
const QRegion globalRegion = mapToGlobal(region);
|
const QRegion globalRegion = mapToGlobal(region);
|
||||||
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
|
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
|
||||||
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
|
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
|
||||||
if (m_repaints.count() != outputs.count()) {
|
for (const auto &output : outputs) {
|
||||||
return; // Repaints haven't been reallocated yet, do nothing.
|
|
||||||
}
|
|
||||||
for (int screenId = 0; screenId < m_repaints.count(); ++screenId) {
|
|
||||||
AbstractOutput *output = outputs[screenId];
|
|
||||||
const QRegion dirtyRegion = globalRegion & output->geometry();
|
const QRegion dirtyRegion = globalRegion & output->geometry();
|
||||||
if (!dirtyRegion.isEmpty()) {
|
if (!dirtyRegion.isEmpty()) {
|
||||||
m_repaints[screenId] += dirtyRegion;
|
m_repaints[output] += dirtyRegion;
|
||||||
output->renderLoop()->scheduleRepaint();
|
output->renderLoop()->scheduleRepaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_repaints[0] += globalRegion;
|
m_repaints[nullptr] += globalRegion;
|
||||||
kwinApp()->platform()->renderLoop()->scheduleRepaint();
|
kwinApp()->platform()->renderLoop()->scheduleRepaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,32 +308,19 @@ WindowQuadList Item::quads() const
|
||||||
return m_quads.value();
|
return m_quads.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegion Item::repaints(int screen) const
|
QRegion Item::repaints(AbstractOutput *output) const
|
||||||
{
|
{
|
||||||
Q_ASSERT(!m_repaints.isEmpty());
|
return m_repaints.value(output, QRect(QPoint(0, 0), screens()->size()));
|
||||||
const int index = screen != -1 ? screen : 0;
|
|
||||||
if (m_repaints[index] == infiniteRegion()) {
|
|
||||||
return QRect(QPoint(0, 0), screens()->size());
|
|
||||||
}
|
|
||||||
return m_repaints[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Item::resetRepaints(int screen)
|
void Item::resetRepaints(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!m_repaints.isEmpty());
|
m_repaints.insert(output, QRegion());
|
||||||
const int index = screen != -1 ? screen : 0;
|
|
||||||
m_repaints[index] = QRegion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Item::reallocRepaints()
|
void Item::removeRepaints(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
|
m_repaints.remove(output);
|
||||||
m_repaints.resize(kwinApp()->platform()->enabledOutputs().count());
|
|
||||||
} else {
|
|
||||||
m_repaints.resize(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_repaints.fill(infiniteRegion());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Item::isVisible() const
|
bool Item::isVisible() const
|
||||||
|
|
10
src/item.h
10
src/item.h
|
@ -17,6 +17,8 @@
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class AbstractOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Item class is the base class for items in the scene.
|
* The Item class is the base class for items in the scene.
|
||||||
*/
|
*/
|
||||||
|
@ -85,8 +87,8 @@ public:
|
||||||
|
|
||||||
void scheduleRepaint(const QRegion ®ion);
|
void scheduleRepaint(const QRegion ®ion);
|
||||||
void scheduleFrame();
|
void scheduleFrame();
|
||||||
QRegion repaints(int screen) const;
|
QRegion repaints(AbstractOutput *output) const;
|
||||||
void resetRepaints(int screen);
|
void resetRepaints(AbstractOutput *output);
|
||||||
|
|
||||||
WindowQuadList quads() const;
|
WindowQuadList quads() const;
|
||||||
virtual void preprocess();
|
virtual void preprocess();
|
||||||
|
@ -116,11 +118,11 @@ private:
|
||||||
void removeChild(Item *item);
|
void removeChild(Item *item);
|
||||||
void updateBoundingRect();
|
void updateBoundingRect();
|
||||||
void scheduleRepaintInternal(const QRegion ®ion);
|
void scheduleRepaintInternal(const QRegion ®ion);
|
||||||
void reallocRepaints();
|
|
||||||
void markSortedChildItemsDirty();
|
void markSortedChildItemsDirty();
|
||||||
|
|
||||||
bool computeEffectiveVisibility() const;
|
bool computeEffectiveVisibility() const;
|
||||||
void updateEffectiveVisibility();
|
void updateEffectiveVisibility();
|
||||||
|
void removeRepaints(AbstractOutput *output);
|
||||||
|
|
||||||
QPointer<Item> m_parentItem;
|
QPointer<Item> m_parentItem;
|
||||||
QList<Item *> m_childItems;
|
QList<Item *> m_childItems;
|
||||||
|
@ -131,7 +133,7 @@ private:
|
||||||
int m_z = 0;
|
int m_z = 0;
|
||||||
bool m_visible = true;
|
bool m_visible = true;
|
||||||
bool m_effectiveVisible = true;
|
bool m_effectiveVisible = true;
|
||||||
QVector<QRegion> m_repaints;
|
QMap<AbstractOutput *, QRegion> m_repaints;
|
||||||
mutable std::optional<WindowQuadList> m_quads;
|
mutable std::optional<WindowQuadList> m_quads;
|
||||||
mutable std::optional<QList<Item *>> m_sortedChildItems;
|
mutable std::optional<QList<Item *>> m_sortedChildItems;
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,9 +40,9 @@ OverlayWindow* OpenGLBackend::overlayWindow() const
|
||||||
return nullptr;
|
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)
|
Q_UNUSED(surfaceItem)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -66,16 +66,16 @@ QSharedPointer<KWin::GLTexture> OpenGLBackend::textureForOutput(AbstractOutput*
|
||||||
return {};
|
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)
|
Q_UNUSED(damage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool OpenGLBackend::directScanoutAllowed(int screen) const
|
bool OpenGLBackend::directScanoutAllowed(AbstractOutput *output) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(screen);
|
Q_UNUSED(output);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,16 +60,16 @@ public:
|
||||||
*
|
*
|
||||||
* @p damage contains the reported damage as suggested by windows and effects on prepaint calls.
|
* @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 bool makeCurrent() = 0;
|
||||||
virtual void doneCurrent() = 0;
|
virtual void doneCurrent() = 0;
|
||||||
virtual QRegion beginFrame(int screenId) = 0;
|
virtual QRegion beginFrame(AbstractOutput *output) = 0;
|
||||||
virtual void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) = 0;
|
virtual void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) = 0;
|
||||||
/**
|
/**
|
||||||
* Tries to directly scan out a surface to the screen)
|
* Tries to directly scan out a surface to the screen)
|
||||||
* @return if the scanout fails (or is not supported on the specified 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.
|
* @brief Returns the OverlayWindow used by the backend.
|
||||||
|
@ -121,7 +121,7 @@ public:
|
||||||
{
|
{
|
||||||
return m_haveNativeFence;
|
return m_haveNativeFence;
|
||||||
}
|
}
|
||||||
virtual bool directScanoutAllowed(int screen) const;
|
virtual bool directScanoutAllowed(AbstractOutput *output) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The backend specific extensions (e.g. EGL/GLX extensions).
|
* The backend specific extensions (e.g. EGL/GLX extensions).
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace KWin
|
||||||
class PlatformSurfaceTexture;
|
class PlatformSurfaceTexture;
|
||||||
class SurfacePixmapInternal;
|
class SurfacePixmapInternal;
|
||||||
class SurfacePixmapWayland;
|
class SurfacePixmapWayland;
|
||||||
|
class AbstractOutput;
|
||||||
|
|
||||||
class QPainterBackend : public QObject
|
class QPainterBackend : public QObject
|
||||||
{
|
{
|
||||||
|
@ -33,8 +34,8 @@ public:
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap);
|
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap);
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap);
|
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap);
|
||||||
|
|
||||||
virtual void endFrame(int screenId, const QRegion &damage) = 0;
|
virtual void endFrame(AbstractOutput *output, const QRegion &damage) = 0;
|
||||||
virtual QRegion beginFrame(int screenId) = 0;
|
virtual QRegion beginFrame(AbstractOutput *output) = 0;
|
||||||
/**
|
/**
|
||||||
* @brief Whether the creation of the Backend failed.
|
* @brief Whether the creation of the Backend failed.
|
||||||
*
|
*
|
||||||
|
@ -52,7 +53,7 @@ public:
|
||||||
* @param screenId The id of the screen as used in Screens
|
* @param screenId The id of the screen as used in Screens
|
||||||
* @todo Get a better identifier for screen then a counter variable
|
* @todo Get a better identifier for screen then a counter variable
|
||||||
*/
|
*/
|
||||||
virtual QImage *bufferForScreen(int screenId) = 0;
|
virtual QImage *bufferForScreen(AbstractOutput *output) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QPainterBackend();
|
QPainterBackend();
|
||||||
|
|
|
@ -26,7 +26,7 @@ class AbstractEglDrmBackend : public AbstractEglBackend
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int screenCount() const = 0;
|
virtual bool hasOutput(AbstractOutput *output) const = 0;
|
||||||
virtual bool addOutput(DrmAbstractOutput *output) = 0;
|
virtual bool addOutput(DrmAbstractOutput *output) = 0;
|
||||||
virtual void removeOutput(DrmAbstractOutput *output) = 0;
|
virtual void removeOutput(DrmAbstractOutput *output) = 0;
|
||||||
virtual bool swapBuffers(DrmAbstractOutput *output, const QRegion &dirty) {
|
virtual bool swapBuffers(DrmAbstractOutput *output, const QRegion &dirty) {
|
||||||
|
|
|
@ -140,16 +140,15 @@ bool EglGbmBackend::initRenderingContext()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EglGbmBackend::resetOutput(Output &output, DrmAbstractOutput *drmOutput)
|
bool EglGbmBackend::resetOutput(Output &output)
|
||||||
{
|
{
|
||||||
output.output = drmOutput;
|
const QSize size = output.output->sourceSize();
|
||||||
const QSize size = drmOutput->sourceSize();
|
QVector<uint64_t> modifiers = output.output->supportedModifiers(m_gbmFormat);
|
||||||
QVector<uint64_t> modifiers = drmOutput->supportedModifiers(m_gbmFormat);
|
|
||||||
|
|
||||||
QSharedPointer<GbmSurface> gbmSurface;
|
QSharedPointer<GbmSurface> gbmSurface;
|
||||||
if (modifiers.isEmpty()) {
|
if (modifiers.isEmpty()) {
|
||||||
int flags = GBM_BO_USE_RENDERING;
|
int flags = GBM_BO_USE_RENDERING;
|
||||||
if (drmOutput->gpu() == m_gpu) {
|
if (output.output->gpu() == m_gpu) {
|
||||||
flags |= GBM_BO_USE_SCANOUT;
|
flags |= GBM_BO_USE_SCANOUT;
|
||||||
} else {
|
} else {
|
||||||
flags |= GBM_BO_USE_LINEAR;
|
flags |= GBM_BO_USE_LINEAR;
|
||||||
|
@ -173,7 +172,7 @@ bool EglGbmBackend::resetOutput(Output &output, DrmAbstractOutput *drmOutput)
|
||||||
output.current = {};
|
output.current = {};
|
||||||
output.current.gbmSurface = gbmSurface;
|
output.current.gbmSurface = gbmSurface;
|
||||||
|
|
||||||
if (size == drmOutput->pixelSize()) {
|
if (size == output.output->pixelSize()) {
|
||||||
output.current.shadowBuffer = nullptr;
|
output.current.shadowBuffer = nullptr;
|
||||||
} else {
|
} else {
|
||||||
makeContextCurrent(output.current);
|
makeContextCurrent(output.current);
|
||||||
|
@ -187,58 +186,37 @@ bool EglGbmBackend::resetOutput(Output &output, DrmAbstractOutput *drmOutput)
|
||||||
|
|
||||||
bool EglGbmBackend::addOutput(DrmAbstractOutput *drmOutput)
|
bool EglGbmBackend::addOutput(DrmAbstractOutput *drmOutput)
|
||||||
{
|
{
|
||||||
|
Output newOutput;
|
||||||
|
newOutput.output = drmOutput;
|
||||||
if (isPrimary()) {
|
if (isPrimary()) {
|
||||||
Output newOutput;
|
if (!resetOutput(newOutput)) {
|
||||||
if (!resetOutput(newOutput, drmOutput)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (drmOutput->gpu() == m_gpu) {
|
|
||||||
m_outputs << newOutput;
|
|
||||||
} else {
|
|
||||||
m_secondaryGpuOutputs << newOutput;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Output newOutput;
|
|
||||||
newOutput.output = drmOutput;
|
|
||||||
if (!renderingBackend()->addOutput(drmOutput)) {
|
if (!renderingBackend()->addOutput(drmOutput)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_outputs << newOutput;
|
|
||||||
}
|
}
|
||||||
|
m_outputs.insert(drmOutput, newOutput);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EglGbmBackend::removeOutput(DrmAbstractOutput *drmOutput)
|
void EglGbmBackend::removeOutput(DrmAbstractOutput *drmOutput)
|
||||||
{
|
{
|
||||||
QVector<Output> &outputs = drmOutput->gpu() == m_gpu ? m_outputs : m_secondaryGpuOutputs;
|
Q_ASSERT(m_outputs.contains(drmOutput));
|
||||||
auto it = std::find_if(outputs.begin(), outputs.end(),
|
|
||||||
[drmOutput] (const Output &output) {
|
|
||||||
return output.output == drmOutput;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (it == outputs.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isPrimary()) {
|
if (isPrimary()) {
|
||||||
// shadow buffer needs context current for destruction
|
// shadow buffer needs context current for destruction
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
} else {
|
} else {
|
||||||
renderingBackend()->removeOutput((*it).output);
|
renderingBackend()->removeOutput(drmOutput);
|
||||||
}
|
}
|
||||||
outputs.erase(it);
|
m_outputs.remove(drmOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EglGbmBackend::swapBuffers(DrmAbstractOutput *drmOutput, const QRegion &dirty)
|
bool EglGbmBackend::swapBuffers(DrmAbstractOutput *drmOutput, const QRegion &dirty)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
|
Q_ASSERT(m_outputs.contains(drmOutput));
|
||||||
[drmOutput] (const Output &output) {
|
Output &output = m_outputs[drmOutput];
|
||||||
return output.output == drmOutput;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (it == m_secondaryGpuOutputs.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Output &output = *it;
|
|
||||||
renderFramebufferToSurface(output);
|
renderFramebufferToSurface(output);
|
||||||
if (output.current.gbmSurface->swapBuffers()) {
|
if (output.current.gbmSurface->swapBuffers()) {
|
||||||
cleanupRenderData(output.old);
|
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)
|
bool EglGbmBackend::exportFramebuffer(DrmAbstractOutput *drmOutput, void *data, const QSize &size, uint32_t stride)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
|
Q_ASSERT(m_outputs.contains(drmOutput));
|
||||||
[drmOutput] (const Output &output) {
|
auto bo = m_outputs[drmOutput].current.gbmSurface->currentBuffer();
|
||||||
return output.output == drmOutput;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (it == m_secondaryGpuOutputs.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto bo = it->current.gbmSurface->currentBuffer();
|
|
||||||
if (!bo->map(GBM_BO_TRANSFER_READ)) {
|
if (!bo->map(GBM_BO_TRANSFER_READ)) {
|
||||||
return false;
|
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)
|
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(),
|
Q_ASSERT(m_outputs.contains(drmOutput));
|
||||||
[drmOutput] (const Output &output) {
|
auto bo = m_outputs[drmOutput].current.gbmSurface->currentBuffer()->getBo();
|
||||||
return output.output == drmOutput;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (it == m_secondaryGpuOutputs.end()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
auto bo = it->current.gbmSurface->currentBuffer()->getBo();
|
|
||||||
if (gbm_bo_get_handle_for_plane(bo, 0).s32 != -1) {
|
if (gbm_bo_get_handle_for_plane(bo, 0).s32 != -1) {
|
||||||
*num_fds = gbm_bo_get_plane_count(bo);
|
*num_fds = gbm_bo_get_plane_count(bo);
|
||||||
for (uint32_t i = 0; i < *num_fds; i++) {
|
for (uint32_t i = 0; i < *num_fds; i++) {
|
||||||
|
@ -312,15 +276,8 @@ bool EglGbmBackend::exportFramebufferAsDmabuf(DrmAbstractOutput *drmOutput, int
|
||||||
|
|
||||||
QRegion EglGbmBackend::beginFrameForSecondaryGpu(DrmAbstractOutput *drmOutput)
|
QRegion EglGbmBackend::beginFrameForSecondaryGpu(DrmAbstractOutput *drmOutput)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
|
Q_ASSERT(m_outputs.contains(drmOutput));
|
||||||
[drmOutput] (const Output &output) {
|
return prepareRenderingForOutput(m_outputs[drmOutput]);
|
||||||
return output.output == drmOutput;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (it == m_secondaryGpuOutputs.end()) {
|
|
||||||
return QRegion();
|
|
||||||
}
|
|
||||||
return prepareRenderingForOutput(*it);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<DrmBuffer> EglGbmBackend::importFramebuffer(Output &output, const QRegion &dirty) const
|
QSharedPointer<DrmBuffer> EglGbmBackend::importFramebuffer(Output &output, const QRegion &dirty) const
|
||||||
|
@ -489,10 +446,11 @@ static QVector<EGLint> regionToRects(const QRegion ®ion, AbstractWaylandOutpu
|
||||||
return rects;
|
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");
|
Q_ASSERT_X(drmOutput, "aboutToStartPainting", "not using per screen rendering");
|
||||||
const Output &output = m_outputs.at(screenId);
|
Q_ASSERT(m_outputs.contains(drmOutput));
|
||||||
|
const Output &output = m_outputs[drmOutput];
|
||||||
if (output.current.bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) {
|
if (output.current.bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) {
|
||||||
const QRegion region = damagedRegion & output.output->geometry();
|
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());
|
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) {
|
if (output.surfaceInterface) {
|
||||||
qCDebug(KWIN_DRM) << "Direct scanout stopped on output" << output.output->name();
|
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.current = output.old;
|
||||||
output.old = {};
|
output.old = {};
|
||||||
} else {
|
} else {
|
||||||
resetOutput(output, output.output);
|
resetOutput(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
makeContextCurrent(output.current);
|
makeContextCurrent(output.current);
|
||||||
|
@ -580,9 +539,10 @@ QRegion EglGbmBackend::prepareRenderingForOutput(Output &output)
|
||||||
return geometry;
|
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()) {
|
if (isPrimary()) {
|
||||||
renderFramebufferToSurface(output);
|
renderFramebufferToSurface(output);
|
||||||
auto buffer = output.current.gbmSurface->swapBuffersForDrm();
|
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)
|
const QRegion &damagedRegion)
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(m_outputs.contains(drmOutput));
|
||||||
Q_UNUSED(renderedRegion)
|
Q_UNUSED(renderedRegion)
|
||||||
|
|
||||||
Output &output = m_outputs[screenId];
|
Output &output = m_outputs[drmOutput];
|
||||||
cleanupRenderData(output.old);
|
cleanupRenderData(output.old);
|
||||||
|
|
||||||
const QRegion dirty = damagedRegion.intersected(output.output->geometry());
|
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)) {
|
if (!buffer || !output.output->present(buffer, dirty)) {
|
||||||
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(output.output->renderLoop());
|
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(output.output->renderLoop());
|
||||||
renderLoopPrivate->notifyFrameFailed();
|
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);
|
SurfaceItemWayland *item = qobject_cast<SurfaceItemWayland *>(surfaceItem);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -636,7 +598,7 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem)
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Output &output = m_outputs[screenId];
|
Output &output = m_outputs[drmOutput];
|
||||||
if (buffer->size() != output.output->modeSize()) {
|
if (buffer->size() != output.output->modeSize()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -714,41 +676,21 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem)
|
||||||
|
|
||||||
QSharedPointer<DrmBuffer> EglGbmBackend::renderTestFrame(DrmAbstractOutput *output)
|
QSharedPointer<DrmBuffer> EglGbmBackend::renderTestFrame(DrmAbstractOutput *output)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_outputs.count(); i++) {
|
beginFrame(output);
|
||||||
if (m_outputs[i].output == output) {
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
beginFrame(i);
|
return endFrameWithBuffer(output, output->geometry());
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
return endFrameWithBuffer(i, output->geometry());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(),
|
Q_ASSERT(m_outputs.contains(output));
|
||||||
[abstractOutput] (const auto &output) {
|
auto &renderOutput = m_outputs[output];
|
||||||
return output.output == abstractOutput;
|
if (renderOutput.current.shadowBuffer) {
|
||||||
}
|
const auto glTexture = QSharedPointer<KWin::GLTexture>::create(renderOutput.current.shadowBuffer->texture(), GL_RGBA8, output->pixelSize());
|
||||||
);
|
|
||||||
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());
|
|
||||||
glTexture->setYInverted(true);
|
glTexture->setYInverted(true);
|
||||||
return glTexture;
|
return glTexture;
|
||||||
}
|
}
|
||||||
GbmBuffer *gbmBuffer = itOutput->current.gbmSurface->currentBuffer().get();
|
GbmBuffer *gbmBuffer = renderOutput.current.gbmSurface->currentBuffer().get();
|
||||||
if (!gbmBuffer) {
|
if (!gbmBuffer) {
|
||||||
qCWarning(KWIN_DRM) << "Failed to record frame: No gbm buffer!";
|
qCWarning(KWIN_DRM) << "Failed to record frame: No gbm buffer!";
|
||||||
return {};
|
return {};
|
||||||
|
@ -759,12 +701,17 @@ QSharedPointer<GLTexture> EglGbmBackend::textureForOutput(AbstractOutput *abstra
|
||||||
return {};
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,17 +47,14 @@ public:
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
||||||
|
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
|
||||||
void init() 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;
|
QSharedPointer<GLTexture> textureForOutput(AbstractOutput *requestedOutput) const override;
|
||||||
|
|
||||||
int screenCount() const override {
|
bool hasOutput(AbstractOutput *output) const override;
|
||||||
return m_outputs.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool addOutput(DrmAbstractOutput *output) override;
|
bool addOutput(DrmAbstractOutput *output) override;
|
||||||
void removeOutput(DrmAbstractOutput *output) override;
|
void removeOutput(DrmAbstractOutput *output) override;
|
||||||
bool swapBuffers(DrmAbstractOutput *output, const QRegion &dirty) 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;
|
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;
|
QRegion beginFrameForSecondaryGpu(DrmAbstractOutput *output) override;
|
||||||
|
|
||||||
bool directScanoutAllowed(int screen) const override;
|
bool directScanoutAllowed(AbstractOutput *output) const override;
|
||||||
|
|
||||||
QSharedPointer<DrmBuffer> renderTestFrame(DrmAbstractOutput *output) override;
|
QSharedPointer<DrmBuffer> renderTestFrame(DrmAbstractOutput *output) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void cleanupSurfaces() override;
|
void cleanupSurfaces() override;
|
||||||
void aboutToStartPainting(int screenId, const QRegion &damage) override;
|
void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool initializeEgl();
|
bool initializeEgl();
|
||||||
|
@ -99,7 +96,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
bool doesRenderFit(DrmAbstractOutput *output, const Output::RenderData &render);
|
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;
|
bool makeContextCurrent(const Output::RenderData &output) const;
|
||||||
void setViewport(const Output &output) const;
|
void setViewport(const Output &output) const;
|
||||||
|
@ -107,13 +104,12 @@ private:
|
||||||
void renderFramebufferToSurface(Output &output);
|
void renderFramebufferToSurface(Output &output);
|
||||||
QRegion prepareRenderingForOutput(Output &output);
|
QRegion prepareRenderingForOutput(Output &output);
|
||||||
QSharedPointer<DrmBuffer> importFramebuffer(Output &output, const QRegion &dirty) const;
|
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 updateBufferAge(Output &output, const QRegion &dirty);
|
||||||
|
|
||||||
void cleanupRenderData(Output::RenderData &output);
|
void cleanupRenderData(Output::RenderData &output);
|
||||||
|
|
||||||
QVector<Output> m_outputs;
|
QMap<AbstractOutput *, Output> m_outputs;
|
||||||
QVector<Output> m_secondaryGpuOutputs;
|
|
||||||
uint32_t m_gbmFormat;
|
uint32_t m_gbmFormat;
|
||||||
|
|
||||||
friend class EglGbmTexture;
|
friend class EglGbmTexture;
|
||||||
|
|
|
@ -57,28 +57,19 @@ void EglMultiBackend::init()
|
||||||
m_initialized = true;
|
m_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegion EglMultiBackend::beginFrame(int screenId)
|
QRegion EglMultiBackend::beginFrame(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
int internalScreenId;
|
return findBackend(output)->beginFrame(output);
|
||||||
AbstractEglBackend *backend = findBackend(screenId, internalScreenId);
|
|
||||||
Q_ASSERT(backend != nullptr);
|
|
||||||
return backend->beginFrame(internalScreenId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EglMultiBackend::endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion)
|
void EglMultiBackend::endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion)
|
||||||
{
|
{
|
||||||
int internalScreenId;
|
findBackend(output)->endFrame(output, damage, damagedRegion);
|
||||||
AbstractEglBackend *backend = findBackend(screenId, internalScreenId);
|
|
||||||
Q_ASSERT(backend != nullptr);
|
|
||||||
backend->endFrame(internalScreenId, damage, damagedRegion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EglMultiBackend::scanout(int screenId, SurfaceItem *surfaceItem)
|
bool EglMultiBackend::scanout(AbstractOutput *output, SurfaceItem *surfaceItem)
|
||||||
{
|
{
|
||||||
int internalScreenId;
|
return findBackend(output)->scanout(output, surfaceItem);
|
||||||
AbstractEglBackend *backend = findBackend(screenId, internalScreenId);
|
|
||||||
Q_ASSERT(backend != nullptr);
|
|
||||||
return backend->scanout(internalScreenId, surfaceItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EglMultiBackend::makeCurrent()
|
bool EglMultiBackend::makeCurrent()
|
||||||
|
@ -107,26 +98,20 @@ QSharedPointer<GLTexture> EglMultiBackend::textureForOutput(AbstractOutput *requ
|
||||||
return m_backends[0]->textureForOutput(requestedOutput);
|
return m_backends[0]->textureForOutput(requestedOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractEglDrmBackend *EglMultiBackend::findBackend(int screenId, int& internalScreenId) const
|
AbstractEglDrmBackend *EglMultiBackend::findBackend(AbstractOutput *output) const
|
||||||
{
|
{
|
||||||
int screens = 0;
|
for (const auto &backend : qAsConst(m_backends)) {
|
||||||
for (int i = 0; i < m_backends.count(); i++) {
|
if (backend->hasOutput(output)) {
|
||||||
if (screenId < screens + m_backends[i]->screenCount()) {
|
return backend;
|
||||||
internalScreenId = screenId - screens;
|
|
||||||
return m_backends[i];
|
|
||||||
}
|
}
|
||||||
screens += m_backends[i]->screenCount();
|
|
||||||
}
|
}
|
||||||
qCDebug(KWIN_DRM) << "could not find backend!" << screenId << "/" << screens;
|
Q_UNREACHABLE();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EglMultiBackend::directScanoutAllowed(int screenId) const
|
bool EglMultiBackend::directScanoutAllowed(AbstractOutput *output) const
|
||||||
{
|
{
|
||||||
int internalScreenId;
|
return findBackend(output)->directScanoutAllowed(output);
|
||||||
AbstractEglBackend *backend = findBackend(screenId, internalScreenId);
|
|
||||||
Q_ASSERT(backend != nullptr);
|
|
||||||
return backend->directScanoutAllowed(internalScreenId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EglMultiBackend::addGpu(DrmGpu *gpu)
|
void EglMultiBackend::addGpu(DrmGpu *gpu)
|
||||||
|
|
|
@ -24,9 +24,9 @@ public:
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
|
||||||
bool scanout(int screenId, SurfaceItem *surfaceItem) override;
|
bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override;
|
||||||
|
|
||||||
bool makeCurrent() override;
|
bool makeCurrent() override;
|
||||||
void doneCurrent() override;
|
void doneCurrent() override;
|
||||||
|
@ -35,7 +35,7 @@ public:
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
||||||
QSharedPointer<GLTexture> textureForOutput(AbstractOutput *requestedOutput) const override;
|
QSharedPointer<GLTexture> textureForOutput(AbstractOutput *requestedOutput) const override;
|
||||||
|
|
||||||
bool directScanoutAllowed(int screen) const override;
|
bool directScanoutAllowed(AbstractOutput *output) const override;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void addGpu(DrmGpu *gpu);
|
void addGpu(DrmGpu *gpu);
|
||||||
|
@ -46,7 +46,7 @@ private:
|
||||||
QVector<AbstractEglDrmBackend*> m_backends;
|
QVector<AbstractEglDrmBackend*> m_backends;
|
||||||
bool m_initialized = false;
|
bool m_initialized = false;
|
||||||
|
|
||||||
AbstractEglDrmBackend *findBackend(int screenId, int& internalScreenId) const;
|
AbstractEglDrmBackend *findBackend(AbstractOutput *output) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,9 +298,9 @@ bool EglStreamBackend::initRenderingContext()
|
||||||
return !m_outputs.isEmpty() && makeContextCurrent(m_outputs.first());
|
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();
|
QSize sourceSize = drmOutput->sourceSize();
|
||||||
|
|
||||||
if (isPrimary()) {
|
if (isPrimary()) {
|
||||||
|
@ -385,7 +385,8 @@ bool EglStreamBackend::addOutput(DrmAbstractOutput *output)
|
||||||
DrmOutput *drmOutput = qobject_cast<DrmOutput *>(output);
|
DrmOutput *drmOutput = qobject_cast<DrmOutput *>(output);
|
||||||
if (drmOutput) {
|
if (drmOutput) {
|
||||||
Output o;
|
Output o;
|
||||||
if (!resetOutput(o, drmOutput)) {
|
o.output = drmOutput;
|
||||||
|
if (!resetOutput(o)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!isPrimary() && !renderingBackend()->addOutput(drmOutput)) {
|
if (!isPrimary() && !renderingBackend()->addOutput(drmOutput)) {
|
||||||
|
@ -394,18 +395,10 @@ bool EglStreamBackend::addOutput(DrmAbstractOutput *output)
|
||||||
|
|
||||||
connect(drmOutput, &DrmOutput::modeChanged, this,
|
connect(drmOutput, &DrmOutput::modeChanged, this,
|
||||||
[drmOutput, this] {
|
[drmOutput, this] {
|
||||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
|
resetOutput(m_outputs[drmOutput]);
|
||||||
[drmOutput] (const auto &o) {
|
|
||||||
return o.output == drmOutput;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (it == m_outputs.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resetOutput(*it, drmOutput);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
m_outputs << o;
|
m_outputs.insert(output, o);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -490,9 +483,10 @@ PlatformSurfaceTexture *EglStreamBackend::createPlatformSurfaceTextureWayland(Su
|
||||||
return new EglStreamSurfaceTextureWayland(this, pixmap);
|
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()) {
|
if (isPrimary()) {
|
||||||
makeContextCurrent(o);
|
makeContextCurrent(o);
|
||||||
if (o.shadowBuffer) {
|
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);
|
Q_UNUSED(renderedRegion);
|
||||||
|
|
||||||
Output &renderOutput = m_outputs[screenId];
|
Output &renderOutput = m_outputs[output];
|
||||||
DrmOutput *drmOutput = renderOutput.output;
|
|
||||||
|
|
||||||
bool frameFailed = false;
|
bool frameFailed = false;
|
||||||
|
|
||||||
QSharedPointer<DrmDumbBuffer> buffer;
|
QSharedPointer<DrmDumbBuffer> buffer;
|
||||||
|
@ -524,13 +517,13 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con
|
||||||
frameFailed = true;
|
frameFailed = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!renderingBackend()->swapBuffers(drmOutput, damagedRegion.intersected(drmOutput->geometry()))) {
|
if (!renderingBackend()->swapBuffers(static_cast<DrmOutput*>(output), damagedRegion.intersected(output->geometry()))) {
|
||||||
qCCritical(KWIN_DRM) << "swapping buffers on render backend for" << drmOutput << "failed!";
|
qCCritical(KWIN_DRM) << "swapping buffers on render backend for" << output << "failed!";
|
||||||
frameFailed = true;
|
frameFailed = true;
|
||||||
}
|
}
|
||||||
buffer = renderOutput.dumbSwapchain->acquireBuffer();
|
buffer = renderOutput.dumbSwapchain->acquireBuffer();
|
||||||
if (!frameFailed && !renderingBackend()->exportFramebuffer(drmOutput, buffer->data(), buffer->size(), buffer->stride())) {
|
if (!frameFailed && !renderingBackend()->exportFramebuffer(static_cast<DrmOutput*>(output), buffer->data(), buffer->size(), buffer->stride())) {
|
||||||
qCCritical(KWIN_DRM) << "importing framebuffer from render backend for" << drmOutput << "failed!";
|
qCCritical(KWIN_DRM) << "importing framebuffer from render backend for" << output << "failed!";
|
||||||
frameFailed = true;
|
frameFailed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -539,11 +532,11 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frameFailed) {
|
if (frameFailed) {
|
||||||
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop());
|
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(output->renderLoop());
|
||||||
renderLoopPrivate->notifyFrameFailed();
|
renderLoopPrivate->notifyFrameFailed();
|
||||||
} else if (isPrimary()) {
|
} else if (isPrimary()) {
|
||||||
EGLAttrib acquireAttribs[] = {
|
EGLAttrib acquireAttribs[] = {
|
||||||
EGL_DRM_FLIP_EVENT_DATA_NV, (EGLAttrib)drmOutput,
|
EGL_DRM_FLIP_EVENT_DATA_NV, (EGLAttrib)output,
|
||||||
EGL_NONE,
|
EGL_NONE,
|
||||||
};
|
};
|
||||||
if (!pEglStreamConsumerAcquireAttribNV(eglDisplay(), renderOutput.eglStream, acquireAttribs)) {
|
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)
|
QSharedPointer<DrmBuffer> EglStreamBackend::renderTestFrame(DrmAbstractOutput *drmOutput)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
|
Q_ASSERT(m_outputs.contains(drmOutput));
|
||||||
[drmOutput] (const Output &o) {
|
auto &output = m_outputs[drmOutput];
|
||||||
return o.output == drmOutput;
|
auto buffer = output.dumbSwapchain ? output.dumbSwapchain->currentBuffer() : output.buffer;
|
||||||
}
|
|
||||||
);
|
|
||||||
if (it == m_outputs.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
auto buffer = (*it).dumbSwapchain ? (*it).dumbSwapchain->currentBuffer() : (*it).buffer;
|
|
||||||
auto size = drmOutput->sourceSize();
|
auto size = drmOutput->sourceSize();
|
||||||
if (buffer->size() == size) {
|
if (buffer->size() == size) {
|
||||||
return buffer;
|
return buffer;
|
||||||
|
@ -571,6 +558,11 @@ QSharedPointer<DrmBuffer> EglStreamBackend::renderTestFrame(DrmAbstractOutput *d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EglStreamBackend::hasOutput(AbstractOutput *output) const
|
||||||
|
{
|
||||||
|
return m_outputs.contains(output);
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************
|
/************************************************
|
||||||
* EglTexture
|
* EglTexture
|
||||||
************************************************/
|
************************************************/
|
||||||
|
|
|
@ -33,14 +33,11 @@ public:
|
||||||
~EglStreamBackend() override;
|
~EglStreamBackend() override;
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
||||||
int screenCount() const override {
|
bool hasOutput(AbstractOutput *output) const override;
|
||||||
return m_outputs.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool addOutput(DrmAbstractOutput *output) override;
|
bool addOutput(DrmAbstractOutput *output) override;
|
||||||
void removeOutput(DrmAbstractOutput *output) override;
|
void removeOutput(DrmAbstractOutput *output) override;
|
||||||
|
|
||||||
|
@ -74,11 +71,11 @@ private:
|
||||||
// for operation as secondary GPU
|
// for operation as secondary GPU
|
||||||
QSharedPointer<DumbSwapchain> dumbSwapchain;
|
QSharedPointer<DumbSwapchain> dumbSwapchain;
|
||||||
};
|
};
|
||||||
bool resetOutput(Output &output, DrmOutput *drmOutput);
|
bool resetOutput(Output &output);
|
||||||
bool makeContextCurrent(const Output &output);
|
bool makeContextCurrent(const Output &output);
|
||||||
void cleanupOutput(Output &output);
|
void cleanupOutput(Output &output);
|
||||||
|
|
||||||
QVector<Output> m_outputs;
|
QMap<AbstractOutput *, Output> m_outputs;
|
||||||
KWaylandServer::EglStreamControllerInterface *m_eglStreamControllerInterface;
|
KWaylandServer::EglStreamControllerInterface *m_eglStreamControllerInterface;
|
||||||
QHash<KWaylandServer::SurfaceInterface *, StreamTexture> m_streamTextures;
|
QHash<KWaylandServer::SurfaceInterface *, StreamTexture> m_streamTextures;
|
||||||
|
|
||||||
|
|
|
@ -45,31 +45,24 @@ void DrmQPainterBackend::initOutput(DrmAbstractOutput *output)
|
||||||
Output o;
|
Output o;
|
||||||
o.swapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, output->pixelSize());
|
o.swapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, output->pixelSize());
|
||||||
o.output = output;
|
o.output = output;
|
||||||
m_outputs << o;
|
m_outputs.insert(output, o);
|
||||||
connect(output, &DrmOutput::modeChanged, this,
|
connect(output, &DrmOutput::modeChanged, this,
|
||||||
[output, this] {
|
[output, this] {
|
||||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
|
auto &o = m_outputs[output];
|
||||||
[output] (const auto &o) {
|
o.swapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, output->pixelSize());
|
||||||
return o.output == output;
|
o.damageJournal.setCapacity(o.swapchain->slotCount());
|
||||||
}
|
|
||||||
);
|
|
||||||
if (it == m_outputs.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
it->swapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, output->pixelSize());
|
|
||||||
it->damageJournal.setCapacity(it->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;
|
int bufferAge;
|
||||||
rendererOutput->swapchain->acquireBuffer(&bufferAge);
|
rendererOutput->swapchain->acquireBuffer(&bufferAge);
|
||||||
|
@ -77,9 +70,9 @@ QRegion DrmQPainterBackend::beginFrame(int screenId)
|
||||||
return rendererOutput->damageJournal.accumulate(bufferAge, rendererOutput->output->geometry());
|
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;
|
DrmAbstractOutput *drmOutput = rendererOutput.output;
|
||||||
|
|
||||||
QSharedPointer<DrmDumbBuffer> back = rendererOutput.swapchain->currentBuffer();
|
QSharedPointer<DrmDumbBuffer> back = rendererOutput.swapchain->currentBuffer();
|
||||||
|
|
|
@ -31,9 +31,9 @@ class DrmQPainterBackend : public QPainterBackend
|
||||||
public:
|
public:
|
||||||
DrmQPainterBackend(DrmBackend *backend, DrmGpu *gpu);
|
DrmQPainterBackend(DrmBackend *backend, DrmGpu *gpu);
|
||||||
|
|
||||||
QImage *bufferForScreen(int screenId) override;
|
QImage *bufferForScreen(AbstractOutput *output) override;
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initOutput(DrmAbstractOutput *output);
|
void initOutput(DrmAbstractOutput *output);
|
||||||
|
@ -42,7 +42,7 @@ private:
|
||||||
QSharedPointer<DumbSwapchain> swapchain;
|
QSharedPointer<DumbSwapchain> swapchain;
|
||||||
DamageJournal damageJournal;
|
DamageJournal damageJournal;
|
||||||
};
|
};
|
||||||
QVector<Output> m_outputs;
|
QMap<AbstractOutput *, Output> m_outputs;
|
||||||
DrmBackend *m_backend;
|
DrmBackend *m_backend;
|
||||||
DrmGpu *m_gpu;
|
DrmGpu *m_gpu;
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,28 +63,26 @@ void FramebufferQPainterBackend::deactivate()
|
||||||
|
|
||||||
FramebufferQPainterBackend::~FramebufferQPainterBackend() = default;
|
FramebufferQPainterBackend::~FramebufferQPainterBackend() = default;
|
||||||
|
|
||||||
QImage* FramebufferQPainterBackend::bufferForScreen(int screenId)
|
QImage* FramebufferQPainterBackend::bufferForScreen(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
Q_UNUSED(screenId)
|
Q_UNUSED(output)
|
||||||
return &m_renderBuffer;
|
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)
|
Q_UNUSED(damage)
|
||||||
|
|
||||||
if (!kwinApp()->platform()->session()->isActive()) {
|
if (!kwinApp()->platform()->session()->isActive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FramebufferOutput *output = static_cast<FramebufferOutput *>(m_backend->findOutput(screenId));
|
static_cast<FramebufferOutput *>(output)->vsyncMonitor()->arm();
|
||||||
output->vsyncMonitor()->arm();
|
|
||||||
|
|
||||||
QPainter p(&m_backBuffer);
|
QPainter p(&m_backBuffer);
|
||||||
p.drawImage(QPoint(0, 0), m_backend->isBGR() ? m_renderBuffer.rgbSwapped() : m_renderBuffer);
|
p.drawImage(QPoint(0, 0), m_backend->isBGR() ? m_renderBuffer.rgbSwapped() : m_renderBuffer);
|
||||||
|
|
|
@ -24,9 +24,9 @@ public:
|
||||||
FramebufferQPainterBackend(FramebufferBackend *backend);
|
FramebufferQPainterBackend(FramebufferBackend *backend);
|
||||||
~FramebufferQPainterBackend() override;
|
~FramebufferQPainterBackend() override;
|
||||||
|
|
||||||
QImage *bufferForScreen(int screenId) override;
|
QImage *bufferForScreen(AbstractOutput *output) override;
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reactivate();
|
void reactivate();
|
||||||
|
|
|
@ -150,9 +150,9 @@ PlatformSurfaceTexture *EglGbmBackend::createPlatformSurfaceTextureWayland(Surfa
|
||||||
return new BasicEGLSurfaceTextureWayland(this, pixmap);
|
return new BasicEGLSurfaceTextureWayland(this, pixmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegion EglGbmBackend::beginFrame(int screenId)
|
QRegion EglGbmBackend::beginFrame(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
Q_UNUSED(screenId)
|
Q_UNUSED(output)
|
||||||
if (!GLRenderTarget::isRenderTargetBound()) {
|
if (!GLRenderTarget::isRenderTargetBound()) {
|
||||||
GLRenderTarget::pushRenderTarget(m_fbo);
|
GLRenderTarget::pushRenderTarget(m_fbo);
|
||||||
}
|
}
|
||||||
|
@ -190,14 +190,13 @@ static void convertFromGLImage(QImage &img, int w, int h)
|
||||||
img = img.mirrored();
|
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(renderedRegion)
|
||||||
Q_UNUSED(damagedRegion)
|
Q_UNUSED(damagedRegion)
|
||||||
glFlush();
|
glFlush();
|
||||||
|
|
||||||
VirtualOutput *output = static_cast<VirtualOutput *>(m_backend->findOutput(screenId));
|
static_cast<VirtualOutput *>(output)->vsyncMonitor()->arm();
|
||||||
output->vsyncMonitor()->arm();
|
|
||||||
|
|
||||||
if (m_backend->saveFrames()) {
|
if (m_backend->saveFrames()) {
|
||||||
QImage img = QImage(QSize(m_backBuffer->width(), m_backBuffer->height()), QImage::Format_ARGB32);
|
QImage img = QImage(QSize(m_backBuffer->width(), m_backBuffer->height()), QImage::Format_ARGB32);
|
||||||
|
|
|
@ -28,8 +28,8 @@ public:
|
||||||
~EglGbmBackend() override;
|
~EglGbmBackend() override;
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -27,35 +27,35 @@ VirtualQPainterBackend::VirtualQPainterBackend(VirtualBackend *backend)
|
||||||
|
|
||||||
VirtualQPainterBackend::~VirtualQPainterBackend() = default;
|
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()
|
void VirtualQPainterBackend::createOutputs()
|
||||||
{
|
{
|
||||||
m_backBuffers.clear();
|
m_backBuffers.clear();
|
||||||
for (int i = 0; i < screens()->count(); ++i) {
|
const auto outputs = m_backend->enabledOutputs();
|
||||||
QImage buffer(screens()->size(i) * screens()->scale(i), QImage::Format_RGB32);
|
for (const auto &output : outputs) {
|
||||||
|
QImage buffer(output->pixelSize(), QImage::Format_RGB32);
|
||||||
buffer.fill(Qt::black);
|
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)
|
Q_UNUSED(damage)
|
||||||
|
|
||||||
VirtualOutput *output = static_cast<VirtualOutput *>(m_backend->findOutput(screenId));
|
static_cast<VirtualOutput *>(output)->vsyncMonitor()->arm();
|
||||||
output->vsyncMonitor()->arm();
|
|
||||||
|
|
||||||
if (m_backend->saveFrames()) {
|
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++)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
@ -26,14 +27,14 @@ public:
|
||||||
VirtualQPainterBackend(VirtualBackend *backend);
|
VirtualQPainterBackend(VirtualBackend *backend);
|
||||||
~VirtualQPainterBackend() override;
|
~VirtualQPainterBackend() override;
|
||||||
|
|
||||||
QImage *bufferForScreen(int screenId) override;
|
QImage *bufferForScreen(AbstractOutput *output) override;
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createOutputs();
|
void createOutputs();
|
||||||
|
|
||||||
QVector<QImage> m_backBuffers;
|
QMap<AbstractOutput *, QImage> m_backBuffers;
|
||||||
VirtualBackend *m_backend;
|
VirtualBackend *m_backend;
|
||||||
int m_frameCounter = 0;
|
int m_frameCounter = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -141,11 +141,12 @@ void EglWaylandBackend::cleanupSurfaces()
|
||||||
|
|
||||||
bool EglWaylandBackend::createEglWaylandOutput(AbstractOutput *waylandOutput)
|
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)) {
|
if (!output->init(this)) {
|
||||||
|
delete output;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_outputs << output;
|
m_outputs.insert(waylandOutput, output);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,15 +299,16 @@ static QVector<EGLint> regionToRects(const QRegion ®ion, AbstractWaylandOutpu
|
||||||
return rects;
|
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");
|
Q_ASSERT_X(output, "aboutToStartPainting", "not using per screen rendering");
|
||||||
EglWaylandOutput *output = m_outputs.at(screenId);
|
Q_ASSERT(m_outputs.contains(output));
|
||||||
if (output->m_bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) {
|
const auto &eglOutput = m_outputs[output];
|
||||||
const QRegion region = damagedRegion & output->m_waylandOutput->geometry();
|
if (eglOutput->m_bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) {
|
||||||
|
const QRegion region = damagedRegion & eglOutput->m_waylandOutput->geometry();
|
||||||
|
|
||||||
QVector<EGLint> rects = regionToRects(region, output->m_waylandOutput);
|
QVector<EGLint> rects = regionToRects(region, eglOutput->m_waylandOutput);
|
||||||
const bool correct = eglSetDamageRegionKHR(eglDisplay(), output->m_eglSurface,
|
const bool correct = eglSetDamageRegionKHR(eglDisplay(), eglOutput->m_eglSurface,
|
||||||
rects.data(), rects.count()/4);
|
rects.data(), rects.count()/4);
|
||||||
if (!correct) {
|
if (!correct) {
|
||||||
qCWarning(KWIN_WAYLAND_BACKEND) << "failed eglSetDamageRegionKHR" << eglGetError();
|
qCWarning(KWIN_WAYLAND_BACKEND) << "failed eglSetDamageRegionKHR" << eglGetError();
|
||||||
|
@ -350,27 +352,29 @@ PlatformSurfaceTexture *EglWaylandBackend::createPlatformSurfaceTextureWayland(S
|
||||||
return new BasicEGLSurfaceTextureWayland(this, pixmap);
|
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);
|
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
|
||||||
|
|
||||||
auto *output = m_outputs.at(screenId);
|
const auto &eglOutput = m_outputs[output];
|
||||||
makeContextCurrent(output);
|
makeContextCurrent(eglOutput);
|
||||||
if (supportsBufferAge()) {
|
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();
|
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);
|
Q_UNUSED(renderedRegion);
|
||||||
EglWaylandOutput *output = m_outputs[screenId];
|
const auto &eglOutput = m_outputs[output];
|
||||||
QRegion damage = damagedRegion.intersected(output->m_waylandOutput->geometry());
|
QRegion damage = damagedRegion.intersected(eglOutput->m_waylandOutput->geometry());
|
||||||
presentOnSurface(output, damage);
|
presentOnSurface(eglOutput, damage);
|
||||||
|
|
||||||
if (supportsBufferAge()) {
|
if (supportsBufferAge()) {
|
||||||
output->m_damageJournal.add(damage);
|
eglOutput->m_damageJournal.add(damage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,15 +71,15 @@ public:
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
||||||
|
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
||||||
bool havePlatformBase() const {
|
bool havePlatformBase() const {
|
||||||
return m_havePlatformBase;
|
return m_havePlatformBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
void aboutToStartPainting(int screenId, const QRegion &damage) override;
|
void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool initializeEgl();
|
bool initializeEgl();
|
||||||
|
@ -95,7 +95,7 @@ private:
|
||||||
void presentOnSurface(EglWaylandOutput *output, const QRegion &damagedRegion);
|
void presentOnSurface(EglWaylandOutput *output, const QRegion &damagedRegion);
|
||||||
|
|
||||||
WaylandBackend *m_backend;
|
WaylandBackend *m_backend;
|
||||||
QVector<EglWaylandOutput*> m_outputs;
|
QMap<AbstractOutput *, EglWaylandOutput*> m_outputs;
|
||||||
bool m_havePlatformBase;
|
bool m_havePlatformBase;
|
||||||
friend class EglWaylandTexture;
|
friend class EglWaylandTexture;
|
||||||
};
|
};
|
||||||
|
|
|
@ -169,25 +169,25 @@ void WaylandQPainterBackend::createOutput(AbstractOutput *waylandOutput)
|
||||||
{
|
{
|
||||||
auto *output = new WaylandQPainterOutput(static_cast<WaylandOutput *>(waylandOutput), this);
|
auto *output = new WaylandQPainterOutput(static_cast<WaylandOutput *>(waylandOutput), this);
|
||||||
output->init(m_backend->shmPool());
|
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);
|
Q_ASSERT(rendererOutput);
|
||||||
|
|
||||||
rendererOutput->present(rendererOutput->mapToLocal(damage));
|
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);
|
Q_ASSERT(rendererOutput);
|
||||||
|
|
||||||
WaylandQPainterBufferSlot *slot = rendererOutput->acquire();
|
WaylandQPainterBufferSlot *slot = rendererOutput->acquire();
|
||||||
|
|
|
@ -83,17 +83,17 @@ public:
|
||||||
explicit WaylandQPainterBackend(WaylandBackend *b);
|
explicit WaylandQPainterBackend(WaylandBackend *b);
|
||||||
~WaylandQPainterBackend() override;
|
~WaylandQPainterBackend() override;
|
||||||
|
|
||||||
QImage *bufferForScreen(int screenId) override;
|
QImage *bufferForScreen(AbstractOutput *output) override;
|
||||||
|
|
||||||
void endFrame(int screenId, const QRegion& damage) override;
|
void endFrame(AbstractOutput *output, const QRegion& damage) override;
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createOutput(AbstractOutput *waylandOutput);
|
void createOutput(AbstractOutput *waylandOutput);
|
||||||
void frameRendered();
|
void frameRendered();
|
||||||
|
|
||||||
WaylandBackend *m_backend;
|
WaylandBackend *m_backend;
|
||||||
QVector<WaylandQPainterOutput*> m_outputs;
|
QMap<AbstractOutput *, WaylandQPainterOutput*> m_outputs;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,9 +88,9 @@ void EglBackend::screenGeometryChanged()
|
||||||
m_bufferAge = 0;
|
m_bufferAge = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegion EglBackend::beginFrame(int screenId)
|
QRegion EglBackend::beginFrame(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
Q_UNUSED(screenId)
|
Q_UNUSED(output)
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
|
|
||||||
const QSize size = screens()->size();
|
const QSize size = screens()->size();
|
||||||
|
@ -106,9 +106,9 @@ QRegion EglBackend::beginFrame(int screenId)
|
||||||
return repaint;
|
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
|
// Start the software vsync monitor. There is no any reliable way to determine when
|
||||||
// eglSwapBuffers() or eglSwapBuffersWithDamageEXT() completes.
|
// eglSwapBuffers() or eglSwapBuffersWithDamageEXT() completes.
|
||||||
|
|
|
@ -31,8 +31,8 @@ public:
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *texture) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *texture) override;
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void screenGeometryChanged();
|
void screenGeometryChanged();
|
||||||
|
|
|
@ -739,9 +739,9 @@ PlatformSurfaceTexture *GlxBackend::createPlatformSurfaceTextureX11(SurfacePixma
|
||||||
return new GlxSurfaceTextureX11(this, pixmap);
|
return new GlxSurfaceTextureX11(this, pixmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegion GlxBackend::beginFrame(int screenId)
|
QRegion GlxBackend::beginFrame(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
Q_UNUSED(screenId)
|
Q_UNUSED(output)
|
||||||
|
|
||||||
QRegion repaint;
|
QRegion repaint;
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
|
@ -758,9 +758,9 @@ QRegion GlxBackend::beginFrame(int screenId)
|
||||||
return repaint;
|
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,
|
// 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.
|
// assume that the frame will be presented at the next vblank event, this is racy.
|
||||||
|
|
|
@ -72,8 +72,8 @@ public:
|
||||||
GlxBackend(Display *display, X11StandalonePlatform *backend);
|
GlxBackend(Display *display, X11StandalonePlatform *backend);
|
||||||
~GlxBackend() override;
|
~GlxBackend() override;
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
|
||||||
bool makeCurrent() override;
|
bool makeCurrent() override;
|
||||||
void doneCurrent() override;
|
void doneCurrent() override;
|
||||||
OverlayWindow* overlayWindow() const override;
|
OverlayWindow* overlayWindow() const override;
|
||||||
|
|
|
@ -47,12 +47,13 @@ void EglX11Backend::cleanupSurfaces()
|
||||||
|
|
||||||
bool EglX11Backend::createSurfaces()
|
bool EglX11Backend::createSurfaces()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < screens()->count(); ++i) {
|
const auto &outputs = m_backend->outputs();
|
||||||
EGLSurface s = createSurface(m_backend->windowForScreen(i));
|
for (const auto &output : outputs) {
|
||||||
|
EGLSurface s = createSurface(m_backend->windowForScreen(output));
|
||||||
if (s == EGL_NO_SURFACE) {
|
if (s == EGL_NO_SURFACE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_surfaces << s;
|
m_surfaces.insert(output, s);
|
||||||
}
|
}
|
||||||
if (m_surfaces.isEmpty()) {
|
if (m_surfaces.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -61,29 +62,26 @@ bool EglX11Backend::createSurfaces()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegion EglX11Backend::beginFrame(int screenId)
|
QRegion EglX11Backend::beginFrame(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
makeContextCurrent(m_surfaces.at(screenId));
|
makeContextCurrent(m_surfaces[output]);
|
||||||
setupViewport(screenId);
|
setupViewport(output);
|
||||||
return screens()->geometry(screenId);
|
return output->geometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EglX11Backend::setupViewport(int screenId)
|
void EglX11Backend::setupViewport(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
qreal scale = screens()->scale(screenId);
|
const QSize size = output->pixelSize() * output->scale();
|
||||||
const QSize size = screens()->geometry(screenId).size() * scale;
|
|
||||||
glViewport(0, 0, size.width(), size.height());
|
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)
|
Q_UNUSED(damagedRegion)
|
||||||
|
|
||||||
X11WindowedOutput *output = static_cast<X11WindowedOutput *>(kwinApp()->platform()->findOutput(screenId));
|
static_cast<X11WindowedOutput *>(output)->vsyncMonitor()->arm();
|
||||||
output->vsyncMonitor()->arm();
|
|
||||||
|
|
||||||
const QRect &outputGeometry = screens()->geometry(screenId);
|
presentSurface(m_surfaces[output], renderedRegion, output->geometry());
|
||||||
presentSurface(m_surfaces.at(screenId), renderedRegion, outputGeometry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EglX11Backend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry)
|
void EglX11Backend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry)
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#define KWIN_EGL_X11_BACKEND_H
|
#define KWIN_EGL_X11_BACKEND_H
|
||||||
#include "eglonxbackend.h"
|
#include "eglonxbackend.h"
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -29,18 +31,18 @@ public:
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
||||||
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
||||||
void init() override;
|
void init() override;
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void cleanupSurfaces() override;
|
void cleanupSurfaces() override;
|
||||||
bool createSurfaces() override;
|
bool createSurfaces() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupViewport(int screenId);
|
void setupViewport(AbstractOutput *output);
|
||||||
void presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry);
|
void presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry);
|
||||||
|
|
||||||
QVector<EGLSurface> m_surfaces;
|
QMap<AbstractOutput *, EGLSurface> m_surfaces;
|
||||||
X11WindowedBackend *m_backend;
|
X11WindowedBackend *m_backend;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -35,32 +35,31 @@ void X11WindowedQPainterBackend::createOutputs()
|
||||||
{
|
{
|
||||||
qDeleteAll(m_outputs);
|
qDeleteAll(m_outputs);
|
||||||
m_outputs.clear();
|
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 *output = new Output;
|
||||||
output->window = m_backend->windowForScreen(i);
|
output->window = m_backend->windowForScreen(x11Output);
|
||||||
output->buffer = QImage(screens()->size(i) * screens()->scale(i), QImage::Format_RGB32);
|
output->buffer = QImage(x11Output->pixelSize() * x11Output->scale(), QImage::Format_RGB32);
|
||||||
output->buffer.fill(Qt::black);
|
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 output->geometry();
|
||||||
return screens()->geometry(screenId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11WindowedQPainterBackend::endFrame(int screenId, const QRegion &damage)
|
void X11WindowedQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage)
|
||||||
{
|
{
|
||||||
Q_UNUSED(damage)
|
Q_UNUSED(damage)
|
||||||
|
|
||||||
X11WindowedOutput *output = static_cast<X11WindowedOutput *>(kwinApp()->platform()->findOutput(screenId));
|
static_cast<X11WindowedOutput *>(output)->vsyncMonitor()->arm();
|
||||||
output->vsyncMonitor()->arm();
|
|
||||||
|
|
||||||
xcb_connection_t *c = m_backend->connection();
|
xcb_connection_t *c = m_backend->connection();
|
||||||
const xcb_window_t window = m_backend->window();
|
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);
|
xcb_create_gc(c, m_gc, window, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Output *rendererOutput = m_outputs.value(screenId);
|
Output *rendererOutput = m_outputs[output];
|
||||||
Q_ASSERT(rendererOutput);
|
Q_ASSERT(rendererOutput);
|
||||||
|
|
||||||
// TODO: only update changes?
|
// TODO: only update changes?
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
@ -29,9 +30,9 @@ public:
|
||||||
X11WindowedQPainterBackend(X11WindowedBackend *backend);
|
X11WindowedQPainterBackend(X11WindowedBackend *backend);
|
||||||
~X11WindowedQPainterBackend() override;
|
~X11WindowedQPainterBackend() override;
|
||||||
|
|
||||||
QImage *bufferForScreen(int screenId) override;
|
QImage *bufferForScreen(AbstractOutput *output) override;
|
||||||
QRegion beginFrame(int screenId) override;
|
QRegion beginFrame(AbstractOutput *output) override;
|
||||||
void endFrame(int screenId, const QRegion &damage) override;
|
void endFrame(AbstractOutput *output, const QRegion &damage) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createOutputs();
|
void createOutputs();
|
||||||
|
@ -41,7 +42,7 @@ private:
|
||||||
xcb_window_t window;
|
xcb_window_t window;
|
||||||
QImage buffer;
|
QImage buffer;
|
||||||
};
|
};
|
||||||
QVector<Output*> m_outputs;
|
QMap<AbstractOutput *, Output*> m_outputs;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -525,12 +525,17 @@ void X11WindowedBackend::warpPointer(const QPointF &globalPos)
|
||||||
xcb_flush(m_connection);
|
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 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
|
Outputs X11WindowedBackend::outputs() const
|
||||||
|
|
|
@ -47,10 +47,8 @@ public:
|
||||||
int screenNumer() const {
|
int screenNumer() const {
|
||||||
return m_screenNumber;
|
return m_screenNumber;
|
||||||
}
|
}
|
||||||
xcb_window_t window() const {
|
xcb_window_t window() const;
|
||||||
return windowForScreen(0);
|
xcb_window_t windowForScreen(AbstractOutput *output) const;
|
||||||
}
|
|
||||||
xcb_window_t windowForScreen(int screen) const;
|
|
||||||
Display *display() const {
|
Display *display() const {
|
||||||
return m_display;
|
return m_display;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "shadowitem.h"
|
#include "shadowitem.h"
|
||||||
#include "surfaceitem.h"
|
#include "surfaceitem.h"
|
||||||
#include "windowitem.h"
|
#include "windowitem.h"
|
||||||
|
#include "abstract_output.h"
|
||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
@ -342,9 +343,9 @@ void SceneOpenGL2::paintCursor(const QRegion &rendered)
|
||||||
glDisable(GL_BLEND);
|
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)
|
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)
|
RenderLoop *renderLoop)
|
||||||
{
|
{
|
||||||
if (m_resetOccurred) {
|
if (m_resetOccurred) {
|
||||||
return; // A graphics reset has occurred, do nothing.
|
return; // A graphics reset has occurred, do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
painted_screen = screenId;
|
painted_screen = output;
|
||||||
// actually paint the frame, flushed with the NEXT frame
|
// actually paint the frame, flushed with the NEXT frame
|
||||||
createStackingOrder(toplevels);
|
createStackingOrder(toplevels);
|
||||||
|
|
||||||
|
@ -373,9 +374,9 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Topleve
|
||||||
QRegion repaint;
|
QRegion repaint;
|
||||||
QRect geo;
|
QRect geo;
|
||||||
qreal scaling;
|
qreal scaling;
|
||||||
if (screenId != -1) {
|
if (output) {
|
||||||
geo = screens()->geometry(screenId);
|
geo = output->geometry();
|
||||||
scaling = screens()->scale(screenId);
|
scaling = output->scale();
|
||||||
} else {
|
} else {
|
||||||
geo = screens()->geometry();
|
geo = screens()->geometry();
|
||||||
scaling = 1;
|
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--) {
|
for (int i = stacking_order.count() - 1; i >=0; i--) {
|
||||||
Window *window = stacking_order[i];
|
Window *window = stacking_order[i];
|
||||||
Toplevel *toplevel = window->window();
|
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);
|
AbstractClient *c = dynamic_cast<AbstractClient*>(toplevel);
|
||||||
if (!c || !c->isFullScreen()) {
|
if (!c || !c->isFullScreen()) {
|
||||||
break;
|
break;
|
||||||
|
@ -420,14 +421,14 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Topleve
|
||||||
renderLoop->setFullscreenSurface(fullscreenSurface);
|
renderLoop->setFullscreenSurface(fullscreenSurface);
|
||||||
|
|
||||||
bool directScanout = false;
|
bool directScanout = false;
|
||||||
if (m_backend->directScanoutAllowed(screenId) && !static_cast<EffectsHandlerImpl*>(effects)->blocksDirectScanout()) {
|
if (m_backend->directScanoutAllowed(output) && !static_cast<EffectsHandlerImpl*>(effects)->blocksDirectScanout()) {
|
||||||
directScanout = m_backend->scanout(screenId, fullscreenSurface);
|
directScanout = m_backend->scanout(output, fullscreenSurface);
|
||||||
}
|
}
|
||||||
if (directScanout) {
|
if (directScanout) {
|
||||||
renderLoop->endFrame();
|
renderLoop->endFrame();
|
||||||
} else {
|
} else {
|
||||||
// prepare rendering makescontext current on the output
|
// prepare rendering makescontext current on the output
|
||||||
repaint = m_backend->beginFrame(screenId);
|
repaint = m_backend->beginFrame(output);
|
||||||
|
|
||||||
GLVertexBuffer::setVirtualScreenGeometry(geo);
|
GLVertexBuffer::setVirtualScreenGeometry(geo);
|
||||||
GLRenderTarget::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
|
renderLoop, projectionMatrix()); // call generic implementation
|
||||||
paintCursor(valid);
|
paintCursor(valid);
|
||||||
|
|
||||||
if (!GLPlatform::instance()->isGLES() && screenId == -1) {
|
if (!GLPlatform::instance()->isGLES() && !output) {
|
||||||
const QSize &screenSize = screens()->size();
|
const QSize &screenSize = screens()->size();
|
||||||
const QRegion displayRegion(0, 0, screenSize.width(), screenSize.height());
|
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();
|
renderLoop->endFrame();
|
||||||
|
|
||||||
GLVertexBuffer::streamingBuffer()->endOfFrame();
|
GLVertexBuffer::streamingBuffer()->endOfFrame();
|
||||||
m_backend->endFrame(screenId, valid, update);
|
m_backend->endFrame(output, valid, update);
|
||||||
GLVertexBuffer::streamingBuffer()->framePosted();
|
GLVertexBuffer::streamingBuffer()->framePosted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ public:
|
||||||
class EffectFrame;
|
class EffectFrame;
|
||||||
~SceneOpenGL() override;
|
~SceneOpenGL() override;
|
||||||
bool initFailed() const 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;
|
RenderLoop *renderLoop) override;
|
||||||
Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame) override;
|
Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame) override;
|
||||||
Shadow *createShadow(Toplevel *toplevel) override;
|
Shadow *createShadow(Toplevel *toplevel) override;
|
||||||
|
@ -62,7 +62,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
SceneOpenGL(OpenGLBackend *backend, QObject *parent = nullptr);
|
SceneOpenGL(OpenGLBackend *backend, QObject *parent = nullptr);
|
||||||
void paintBackground(const QRegion ®ion) override;
|
void paintBackground(const QRegion ®ion) override;
|
||||||
void aboutToStartPainting(int screenId, const QRegion &damage) override;
|
void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override;
|
||||||
void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen) override;
|
void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen) override;
|
||||||
QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const;
|
QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const;
|
||||||
void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data) override;
|
void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data) override;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "toplevel.h"
|
#include "toplevel.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "windowitem.h"
|
#include "windowitem.h"
|
||||||
|
#include "abstract_output.h"
|
||||||
|
|
||||||
#include <kwineffectquickview.h>
|
#include <kwineffectquickview.h>
|
||||||
// Qt
|
// Qt
|
||||||
|
@ -79,18 +80,18 @@ void SceneQPainter::paintGenericScreen(int mask, const ScreenPaintData &data)
|
||||||
m_painter->restore();
|
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)
|
RenderLoop *renderLoop)
|
||||||
{
|
{
|
||||||
Q_ASSERT(kwinApp()->platform()->isPerScreenRenderingEnabled());
|
Q_ASSERT(kwinApp()->platform()->isPerScreenRenderingEnabled());
|
||||||
painted_screen = screenId;
|
painted_screen = output;
|
||||||
|
|
||||||
createStackingOrder(toplevels);
|
createStackingOrder(toplevels);
|
||||||
|
|
||||||
const QRegion repaint = m_backend->beginFrame(screenId);
|
const QRegion repaint = m_backend->beginFrame(output);
|
||||||
const QRect geometry = screens()->geometry(screenId);
|
const QRect geometry = output->geometry();
|
||||||
|
|
||||||
QImage *buffer = m_backend->bufferForScreen(screenId);
|
QImage *buffer = m_backend->bufferForScreen(output);
|
||||||
if (buffer && !buffer->isNull()) {
|
if (buffer && !buffer->isNull()) {
|
||||||
renderLoop->beginFrame();
|
renderLoop->beginFrame();
|
||||||
m_painter->begin(buffer);
|
m_painter->begin(buffer);
|
||||||
|
@ -102,7 +103,7 @@ void SceneQPainter::paint(int screenId, const QRegion &damage, const QList<Tople
|
||||||
|
|
||||||
m_painter->end();
|
m_painter->end();
|
||||||
renderLoop->endFrame();
|
renderLoop->endFrame();
|
||||||
m_backend->endFrame(screenId, updateRegion);
|
m_backend->endFrame(output, updateRegion);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do cleanup
|
// do cleanup
|
||||||
|
@ -159,9 +160,9 @@ Shadow *SceneQPainter::createShadow(Toplevel *toplevel)
|
||||||
return new SceneQPainterShadow(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//****************************************
|
//****************************************
|
||||||
|
|
|
@ -24,7 +24,7 @@ class KWIN_EXPORT SceneQPainter : public Scene
|
||||||
public:
|
public:
|
||||||
~SceneQPainter() override;
|
~SceneQPainter() override;
|
||||||
OverlayWindow* overlayWindow() const 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;
|
RenderLoop *renderLoop) override;
|
||||||
void paintGenericScreen(int mask, const ScreenPaintData &data) override;
|
void paintGenericScreen(int mask, const ScreenPaintData &data) override;
|
||||||
CompositingType compositingType() const override;
|
CompositingType compositingType() const override;
|
||||||
|
@ -40,7 +40,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
QPainter *scenePainter() const override;
|
QPainter *scenePainter() const override;
|
||||||
QImage *qpainterRenderBuffer(int screenId) const override;
|
QImage *qpainterRenderBuffer(AbstractOutput *output) const override;
|
||||||
|
|
||||||
QPainterBackend *backend() const {
|
QPainterBackend *backend() const {
|
||||||
return m_backend.data();
|
return m_backend.data();
|
||||||
|
|
|
@ -85,11 +85,7 @@ namespace KWin
|
||||||
Scene::Scene(QObject *parent)
|
Scene::Scene(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
|
connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Scene::removeRepaints);
|
||||||
connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Scene::reallocRepaints);
|
|
||||||
connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Scene::reallocRepaints);
|
|
||||||
}
|
|
||||||
reallocRepaints();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene::~Scene()
|
Scene::~Scene()
|
||||||
|
@ -101,14 +97,10 @@ void Scene::addRepaint(const QRegion ®ion)
|
||||||
{
|
{
|
||||||
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
|
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
|
||||||
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
|
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
|
||||||
if (m_repaints.count() != outputs.count()) {
|
for (const auto &output : outputs) {
|
||||||
return; // Repaints haven't been reallocated yet, do nothing.
|
|
||||||
}
|
|
||||||
for (int screenId = 0; screenId < m_repaints.count(); ++screenId) {
|
|
||||||
AbstractOutput *output = outputs[screenId];
|
|
||||||
const QRegion dirtyRegion = region & output->geometry();
|
const QRegion dirtyRegion = region & output->geometry();
|
||||||
if (!dirtyRegion.isEmpty()) {
|
if (!dirtyRegion.isEmpty()) {
|
||||||
m_repaints[screenId] += dirtyRegion;
|
m_repaints[output] += dirtyRegion;
|
||||||
output->renderLoop()->scheduleRepaint();
|
output->renderLoop()->scheduleRepaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,27 +110,19 @@ void Scene::addRepaint(const QRegion ®ion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegion Scene::repaints(int screenId) const
|
QRegion Scene::repaints(AbstractOutput *output) const
|
||||||
{
|
{
|
||||||
const int index = screenId == -1 ? 0 : screenId;
|
return m_repaints.value(output, infiniteRegion());
|
||||||
return m_repaints[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::resetRepaints(int screenId)
|
void Scene::resetRepaints(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
const int index = screenId == -1 ? 0 : screenId;
|
m_repaints.insert(output, QRegion());
|
||||||
m_repaints[index] = QRegion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::reallocRepaints()
|
void Scene::removeRepaints(AbstractOutput *output)
|
||||||
{
|
{
|
||||||
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
|
m_repaints.remove(output);
|
||||||
m_repaints.resize(kwinApp()->platform()->enabledOutputs().count());
|
|
||||||
} else {
|
|
||||||
m_repaints.resize(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_repaints.fill(infiniteRegion());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns mask and possibly modified region
|
// returns mask and possibly modified region
|
||||||
|
@ -164,7 +148,7 @@ void Scene::paintScreen(const QRegion &damage, const QRegion &repaint,
|
||||||
|
|
||||||
QRegion region = damage;
|
QRegion region = damage;
|
||||||
|
|
||||||
auto screen = effects->findScreen(painted_screen);
|
auto screen = effects->findScreen(kwinApp()->platform()->enabledOutputs().indexOf(painted_screen));
|
||||||
ScreenPrePaintData pdata;
|
ScreenPrePaintData pdata;
|
||||||
pdata.mask = (damage == displayRegion) ? 0 : PAINT_SCREEN_REGION;
|
pdata.mask = (damage == displayRegion) ? 0 : PAINT_SCREEN_REGION;
|
||||||
pdata.paint = region;
|
pdata.paint = region;
|
||||||
|
@ -221,13 +205,13 @@ void Scene::finalPaintScreen(int mask, const QRegion ®ion, ScreenPaintData& d
|
||||||
paintSimpleScreen(mask, region);
|
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();
|
const auto childItems = item->childItems();
|
||||||
for (Item *childItem : 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);
|
*repaints += item->repaints(output);
|
||||||
item->resetRepaints(screen);
|
item->resetRepaints(output);
|
||||||
|
|
||||||
const auto childItems = item->childItems();
|
const auto childItems = item->childItems();
|
||||||
for (Item *childItem : 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 ®ion, ScreenPai
|
||||||
static_cast<EffectsHandlerImpl*>(effects)->paintDesktop(desktop, mask, region, data);
|
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)
|
Q_UNUSED(damage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,9 +538,9 @@ QPainter *Scene::scenePainter() const
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage *Scene::qpainterRenderBuffer(int screenId) const
|
QImage *Scene::qpainterRenderBuffer(AbstractOutput *output) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(screenId)
|
Q_UNUSED(output)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
src/scene.h
18
src/scene.h
|
@ -59,10 +59,10 @@ public:
|
||||||
void addRepaint(const QRegion ®ion);
|
void addRepaint(const QRegion ®ion);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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;
|
QRegion repaints(AbstractOutput *output) const;
|
||||||
void resetRepaints(int screenId);
|
void resetRepaints(AbstractOutput *output);
|
||||||
|
|
||||||
// Returns true if the ctor failed to properly initialize.
|
// Returns true if the ctor failed to properly initialize.
|
||||||
virtual bool initFailed() const = 0;
|
virtual bool initFailed() const = 0;
|
||||||
|
@ -72,7 +72,7 @@ public:
|
||||||
// The entry point for the main part of the painting pass.
|
// The entry point for the main part of the painting pass.
|
||||||
// returns the time since the last vblank signal - if there's one
|
// returns the time since the last vblank signal - if there's one
|
||||||
// ie. "what of this frame is lost to painting"
|
// 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;
|
RenderLoop *renderLoop) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,7 +159,7 @@ public:
|
||||||
* The render buffer used by a QPainter based compositor.
|
* The render buffer used by a QPainter based compositor.
|
||||||
* Default implementation returns @c nullptr.
|
* 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).
|
* 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.
|
* @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
|
// called after all effects had their paintWindow() called
|
||||||
void finalPaintWindow(EffectWindowImpl* w, int mask, const QRegion ®ion, WindowPaintData& data);
|
void finalPaintWindow(EffectWindowImpl* w, int mask, const QRegion ®ion, WindowPaintData& data);
|
||||||
// shared implementation, starts painting the window
|
// shared implementation, starts painting the window
|
||||||
|
@ -245,15 +245,15 @@ protected:
|
||||||
// The dirty region before it was unioned with repaint_region
|
// The dirty region before it was unioned with repaint_region
|
||||||
QRegion damaged_region;
|
QRegion damaged_region;
|
||||||
// The screen that is being currently painted
|
// The screen that is being currently painted
|
||||||
int painted_screen = -1;
|
AbstractOutput *painted_screen = nullptr;
|
||||||
|
|
||||||
// windows in their stacking order
|
// windows in their stacking order
|
||||||
QVector< Window* > stacking_order;
|
QVector< Window* > stacking_order;
|
||||||
private:
|
private:
|
||||||
|
void removeRepaints(AbstractOutput *output);
|
||||||
std::chrono::milliseconds m_expectedPresentTimestamp = std::chrono::milliseconds::zero();
|
std::chrono::milliseconds m_expectedPresentTimestamp = std::chrono::milliseconds::zero();
|
||||||
void reallocRepaints();
|
|
||||||
QHash< Toplevel*, Window* > m_windows;
|
QHash< Toplevel*, Window* > m_windows;
|
||||||
QVector<QRegion> m_repaints;
|
QMap<AbstractOutput *, QRegion> m_repaints;
|
||||||
// how many times finalPaintScreen() has been called
|
// how many times finalPaintScreen() has been called
|
||||||
int m_paintScreenCount = 0;
|
int m_paintScreenCount = 0;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue