platforms/drm: CPU copy for multi-gpu

Not all GPUs can scan out linear buffers, so if import with a dmabuf
fails manually copy the data into a non-linear gbm buffer instead.

BUG: 432707
This commit is contained in:
Xaver Hugl 2021-05-04 12:19:31 +02:00
parent 2d9e2f0c70
commit 7de0f1f2ad
12 changed files with 346 additions and 124 deletions

View file

@ -13,6 +13,7 @@ set(DRM_SOURCES
drm_gpu.cpp
egl_multi_backend.cpp
abstract_egl_drm_backend.cpp
dumb_swapchain.cpp
)
if (HAVE_GBM)

View file

@ -27,13 +27,24 @@ public:
virtual int screenCount() const = 0;
virtual void addOutput(DrmOutput *output) = 0;
virtual void removeOutput(DrmOutput *output) = 0;
virtual int getDmabufForSecondaryGpuOutput(AbstractOutput *output, uint32_t *format, uint32_t *stride) {
virtual bool swapBuffers(DrmOutput *output) {
Q_UNUSED(output)
return false;
}
virtual bool exportFramebuffer(DrmOutput *output, void *data, const QSize &size, uint32_t stride) {
Q_UNUSED(output)
Q_UNUSED(data)
Q_UNUSED(size)
Q_UNUSED(stride)
return false;
}
virtual int exportFramebufferAsDmabuf(DrmOutput *output, uint32_t *format, uint32_t *stride) {
Q_UNUSED(output)
Q_UNUSED(format)
Q_UNUSED(stride)
return 0;
}
virtual QRegion beginFrameForSecondaryGpu(AbstractOutput *output) {
virtual QRegion beginFrameForSecondaryGpu(DrmOutput *output) {
Q_UNUSED(output)
return QRegion();
}

View file

@ -60,7 +60,9 @@ public:
QImage *image() const {
return m_image;
}
void *data() const {
return m_memory;
}
quint32 stride() const {
return m_stride;
}

View file

@ -32,11 +32,17 @@ GbmBuffer::GbmBuffer(const QSharedPointer<GbmSurface> &surface)
: m_surface(surface)
{
m_bo = m_surface->lockFrontBuffer();
if (m_bo) {
m_stride = gbm_bo_get_stride(m_bo);
} else {
qCWarning(KWIN_DRM) << "failed to lock front buffer!" << strerror(errno);
}
}
GbmBuffer::GbmBuffer(gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface)
: m_bo(buffer)
, m_bufferInterface(bufferInterface)
, m_stride(gbm_bo_get_stride(m_bo))
{
if (m_bufferInterface) {
m_bufferInterface->ref();
@ -54,14 +60,32 @@ void GbmBuffer::releaseBuffer()
if (m_bufferInterface) {
clearBufferInterface();
}
if (m_surface && m_bo) {
if (!m_bo) {
return;
}
if (m_mapping) {
gbm_bo_unmap(m_bo, m_mapping);
}
if (m_surface) {
m_surface->releaseBuffer(m_bo);
} else if (m_bo) {
} else {
gbm_bo_destroy(m_bo);
}
m_bo = nullptr;
}
bool GbmBuffer::map(uint32_t flags)
{
if (m_data) {
return true;
}
if (!m_bo) {
return false;
}
m_data = gbm_bo_map(m_bo, 0, 0, gbm_bo_get_width(m_bo), gbm_bo_get_height(m_bo), flags, &m_stride, &m_mapping);
return m_data;
}
void GbmBuffer::clearBufferInterface()
{
disconnect(m_bufferInterface, &KWaylandServer::BufferInterface::aboutToBeDestroyed, this, &DrmGbmBuffer::clearBufferInterface);

View file

@ -40,11 +40,23 @@ public:
void releaseBuffer();
bool map(uint32_t flags);
void *mappedData() const {
return m_data;
}
uint32_t stride() const {
return m_stride;
}
protected:
QSharedPointer<GbmSurface> m_surface;
gbm_bo *m_bo = nullptr;
KWaylandServer::BufferInterface *m_bufferInterface = nullptr;
void *m_data = nullptr;
void *m_mapping = nullptr;
uint32_t m_stride = 0;
void clearBufferInterface();
};

View file

@ -0,0 +1,54 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2021 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "dumb_swapchain.h"
#include "gbm.h"
#include "drm_gpu.h"
#include "logging.h"
namespace KWin
{
DumbSwapchain::DumbSwapchain(DrmGpu *gpu, const QSize &size)
: m_size(size)
{
for (int i = 0; i < 3; i++) {
auto buffer = QSharedPointer<DrmDumbBuffer>::create(gpu, size);
if (!buffer->bufferId()) {
break;
}
if (!buffer->map()) {
break;
}
buffer->image()->fill(Qt::black);
m_buffers << buffer;
}
if (m_buffers.count() < 3) {
qCWarning(KWIN_DRM) << "Failed to create gbm buffers for swapchain!";
m_buffers.clear();
}
}
QSharedPointer<DrmDumbBuffer> DumbSwapchain::acquireBuffer()
{
if (m_buffers.isEmpty()) {
return nullptr;
}
index = (index + 1) % m_buffers.count();
return m_buffers[index];
}
QSharedPointer<DrmDumbBuffer> DumbSwapchain::currentBuffer() const
{
return m_buffers[index];
}
}

View file

@ -0,0 +1,45 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2021 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QVector>
#include <QSize>
#include <QSharedPointer>
namespace KWin
{
class DrmDumbBuffer;
class DrmGpu;
class DumbSwapchain
{
public:
DumbSwapchain(DrmGpu *gpu, const QSize &size);
QSharedPointer<DrmDumbBuffer> acquireBuffer();
QSharedPointer<DrmDumbBuffer> currentBuffer() const;
QSize size() const {
return m_size;
}
bool isEmpty() const {
return m_buffers.isEmpty();
}
private:
QSize m_size;
int index = 0;
QVector<QSharedPointer<DrmDumbBuffer>> m_buffers;
};
}

View file

@ -22,6 +22,7 @@
#include "surfaceitem_wayland.h"
#include "drm_gpu.h"
#include "linux_dmabuf.h"
#include "dumb_swapchain.h"
// kwin libs
#include <kwinglplatform.h>
#include <kwineglimagetexture.h>
@ -76,6 +77,7 @@ void EglGbmBackend::cleanupOutput(Output &output)
if (output.eglSurface != EGL_NO_SURFACE) {
// gbm buffers have to be released before destroying the egl surface
output.output->releaseGbm();
output.secondaryBuffer = nullptr;
eglDestroySurface(eglDisplay(), output.eglSurface);
}
}
@ -204,6 +206,7 @@ bool EglGbmBackend::resetOutput(Output &output, DrmOutput *drmOutput)
if (output.eglSurface != EGL_NO_SURFACE) {
// gbm buffers have to be released before destroying the egl surface
output.output->releaseGbm();
output.secondaryBuffer = nullptr;
eglDestroySurface(eglDisplay(), output.eglSurface);
}
output.eglSurface = eglSurface;
@ -261,7 +264,54 @@ void EglGbmBackend::removeOutput(DrmOutput *drmOutput)
outputs.erase(it);
}
int EglGbmBackend::getDmabufForSecondaryGpuOutput(AbstractOutput *output, uint32_t *format, uint32_t *stride)
bool EglGbmBackend::swapBuffers(DrmOutput *drmOutput)
{
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
[drmOutput] (const Output &output) {
return output.output == drmOutput;
}
);
if (it == m_secondaryGpuOutputs.end()) {
return false;
}
renderFramebufferToSurface(*it);
auto error = eglSwapBuffers(eglDisplay(), it->eglSurface);
if (error != EGL_TRUE) {
qCDebug(KWIN_DRM) << "an error occurred while swapping buffers" << error;
it->secondaryBuffer = nullptr;
return false;
}
it->secondaryBuffer = QSharedPointer<GbmBuffer>::create(it->gbmSurface);
if (it->secondaryBuffer->getBo()) {
return true;
} else {
it->secondaryBuffer = nullptr;
return false;
}
}
bool EglGbmBackend::exportFramebuffer(DrmOutput *drmOutput, void *data, const QSize &size, uint32_t stride)
{
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
[drmOutput] (const Output &output) {
return output.output == drmOutput;
}
);
if (it == m_secondaryGpuOutputs.end()) {
return false;
}
if (!it->secondaryBuffer || !it->secondaryBuffer->map(GBM_BO_TRANSFER_READ)) {
return false;
}
if (stride != it->secondaryBuffer->stride()) {
// shouldn't happen if formats are the same
return false;
}
return memcpy(data, it->secondaryBuffer->mappedData(), size.height() * stride);
}
int EglGbmBackend::exportFramebufferAsDmabuf(DrmOutput *output, uint32_t *format, uint32_t *stride)
{
DrmOutput *drmOutput = static_cast<DrmOutput*>(output);
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
@ -272,14 +322,6 @@ int EglGbmBackend::getDmabufForSecondaryGpuOutput(AbstractOutput *output, uint32
if (it == m_secondaryGpuOutputs.end()) {
return -1;
}
renderFramebufferToSurface(*it);
auto error = eglSwapBuffers(eglDisplay(), it->eglSurface);
if (error != EGL_TRUE) {
qCDebug(KWIN_DRM) << "an error occurred while swapping buffers" << error;
it->secondaryBuffer = nullptr;
return -1;
}
it->secondaryBuffer = QSharedPointer<GbmBuffer>::create(it->gbmSurface);
int fd = gbm_bo_get_fd(it->secondaryBuffer->getBo());
if (fd == -1) {
qCDebug(KWIN_DRM) << "failed to export gbm_bo as dma-buf!";
@ -290,9 +332,8 @@ int EglGbmBackend::getDmabufForSecondaryGpuOutput(AbstractOutput *output, uint32
return fd;
}
QRegion EglGbmBackend::beginFrameForSecondaryGpu(AbstractOutput *output)
QRegion EglGbmBackend::beginFrameForSecondaryGpu(DrmOutput *drmOutput)
{
DrmOutput *drmOutput = static_cast<DrmOutput*>(output);
auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
[drmOutput] (const Output &output) {
return output.output == drmOutput;
@ -304,6 +345,56 @@ QRegion EglGbmBackend::beginFrameForSecondaryGpu(AbstractOutput *output)
return prepareRenderingForOutput(*it);
}
void EglGbmBackend::importFramebuffer(Output &output) const
{
if (!renderingBackend()->swapBuffers(output.output)) {
qCWarning(KWIN_DRM) << "swapping buffers failed on output" << output.output;
return;
}
output.buffer = nullptr;
const auto size = output.output->modeSize();
if (output.importMode == ImportMode::Dmabuf) {
uint32_t stride = 0;
uint32_t format = 0;
int fd = renderingBackend()->exportFramebufferAsDmabuf(output.output, &format, &stride);
if (fd != -1) {
struct gbm_import_fd_data data = {};
data.fd = fd;
data.width = (uint32_t) size.width();
data.height = (uint32_t) size.height();
data.stride = stride;
data.format = format;
gbm_bo *importedBuffer = gbm_bo_import(m_gpu->gbmDevice(), GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR);
close(fd);
if (importedBuffer) {
auto buffer = QSharedPointer<DrmGbmBuffer>::create(m_gpu, importedBuffer, nullptr);
if (buffer->bufferId() > 0) {
output.buffer = buffer;
return;
}
}
}
qCDebug(KWIN_DRM) << "import with dmabuf failed! Switching to CPU import on output" << output.output;
output.importMode = ImportMode::DumbBuffer;
}
// ImportMode::DumbBuffer
if (!output.importSwapchain || output.importSwapchain->size() != size) {
output.importSwapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, size);
if (output.importSwapchain->isEmpty()) {
output.importSwapchain = nullptr;
}
}
if (output.importSwapchain) {
auto buffer = output.importSwapchain->acquireBuffer();
if (renderingBackend()->exportFramebuffer(output.output, buffer->data(), size, buffer->stride())) {
output.buffer = buffer;
return;
}
}
qCWarning(KWIN_DRM) << "all imports failed on output" << output.output;
// TODO turn off output?
}
const float vertices[] = {
-1.0f, 1.0f,
-1.0f, -1.0f,
@ -377,81 +468,58 @@ void EglGbmBackend::initRenderTarget(Output &output)
void EglGbmBackend::renderFramebufferToSurface(Output &output)
{
if (!output.render.framebuffer && isPrimary()) {
if (!output.render.framebuffer) {
// No additional render target.
return;
}
makeContextCurrent(output);
const auto size = output.output->modeSize();
if (isPrimary()) {
// primary GPU
makeContextCurrent(output);
glViewport(0, 0, size.width(), size.height());
glViewport(0, 0, size.width(), size.height());
auto shader = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture);
auto shader = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture);
QMatrix4x4 mvpMatrix;
QMatrix4x4 mvpMatrix;
const DrmOutput *drmOutput = output.output;
switch (drmOutput->transform()) {
case DrmOutput::Transform::Normal:
case DrmOutput::Transform::Flipped:
break;
case DrmOutput::Transform::Rotated90:
case DrmOutput::Transform::Flipped90:
mvpMatrix.rotate(90, 0, 0, 1);
break;
case DrmOutput::Transform::Rotated180:
case DrmOutput::Transform::Flipped180:
mvpMatrix.rotate(180, 0, 0, 1);
break;
case DrmOutput::Transform::Rotated270:
case DrmOutput::Transform::Flipped270:
mvpMatrix.rotate(270, 0, 0, 1);
break;
}
switch (drmOutput->transform()) {
case DrmOutput::Transform::Flipped:
case DrmOutput::Transform::Flipped90:
case DrmOutput::Transform::Flipped180:
case DrmOutput::Transform::Flipped270:
mvpMatrix.scale(-1, 1);
break;
default:
break;
}
shader->setUniform(GLShader::ModelViewProjectionMatrix, mvpMatrix);
initRenderTarget(output);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
GLRenderTarget::setKWinFramebuffer(0);
glBindTexture(GL_TEXTURE_2D, output.render.texture);
output.render.vbo->render(GL_TRIANGLES);
ShaderManager::instance()->popShader();
glBindTexture(GL_TEXTURE_2D, 0);
} else {
// secondary GPU: render on primary and import framebuffer
uint32_t stride = 0;
uint32_t format = 0;
int fd = renderingBackend()->getDmabufForSecondaryGpuOutput(output.output, &format, &stride);
if (fd != -1) {
struct gbm_import_fd_data data = {};
data.fd = fd;
data.width = (uint32_t) size.width();
data.height = (uint32_t) size.height();
data.stride = stride;
data.format = format;
if (gbm_bo *importedBuffer = gbm_bo_import(m_gpu->gbmDevice(), GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR)) {
output.buffer = QSharedPointer<DrmGbmBuffer>::create(m_gpu, importedBuffer, nullptr);
} else {
qCDebug(KWIN_DRM) << "failed to import dma-buf!" << strerror(errno);
output.buffer = nullptr;
}
close(fd);
}
const DrmOutput *drmOutput = output.output;
switch (drmOutput->transform()) {
case DrmOutput::Transform::Normal:
case DrmOutput::Transform::Flipped:
break;
case DrmOutput::Transform::Rotated90:
case DrmOutput::Transform::Flipped90:
mvpMatrix.rotate(90, 0, 0, 1);
break;
case DrmOutput::Transform::Rotated180:
case DrmOutput::Transform::Flipped180:
mvpMatrix.rotate(180, 0, 0, 1);
break;
case DrmOutput::Transform::Rotated270:
case DrmOutput::Transform::Flipped270:
mvpMatrix.rotate(270, 0, 0, 1);
break;
}
switch (drmOutput->transform()) {
case DrmOutput::Transform::Flipped:
case DrmOutput::Transform::Flipped90:
case DrmOutput::Transform::Flipped180:
case DrmOutput::Transform::Flipped270:
mvpMatrix.scale(-1, 1);
break;
default:
break;
}
shader->setUniform(GLShader::ModelViewProjectionMatrix, mvpMatrix);
initRenderTarget(output);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
GLRenderTarget::setKWinFramebuffer(0);
glBindTexture(GL_TEXTURE_2D, output.render.texture);
output.render.vbo->render(GL_TRIANGLES);
ShaderManager::instance()->popShader();
glBindTexture(GL_TEXTURE_2D, 0);
}
void EglGbmBackend::prepareRenderFramebuffer(const Output &output) const
@ -587,7 +655,7 @@ bool EglGbmBackend::presentOnOutput(Output &output, const QRegion &damagedRegion
}
output.buffer = QSharedPointer<DrmGbmBuffer>::create(m_gpu, output.gbmSurface);
} else if (!output.buffer) {
qCDebug(KWIN_DRM) << "imported gbm_bo does not exist!";
qCDebug(KWIN_DRM) << "imported buffer does not exist!";
return false;
}
@ -668,7 +736,11 @@ void EglGbmBackend::endFrame(int screenId, const QRegion &renderedRegion,
Output &output = m_outputs[screenId];
DrmOutput *drmOutput = output.output;
renderFramebufferToSurface(output);
if (isPrimary()) {
renderFramebufferToSurface(output);
} else {
importFramebuffer(output);
}
const QRegion dirty = damagedRegion.intersected(output.output->geometry());
if (!presentOnOutput(output, dirty)) {
@ -760,13 +832,20 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem)
QSharedPointer<GLTexture> EglGbmBackend::textureForOutput(AbstractOutput *abstractOutput) const
{
const QVector<KWin::EglGbmBackend::Output>::const_iterator itOutput = std::find_if(m_outputs.begin(), m_outputs.end(),
auto itOutput = std::find_if(m_outputs.begin(), m_outputs.end(),
[abstractOutput] (const auto &output) {
return output.output == abstractOutput;
}
);
if (itOutput == m_outputs.end()) {
return {};
itOutput = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(),
[abstractOutput] (const auto &output) {
return output.output == abstractOutput;
}
);
if (itOutput == m_secondaryGpuOutputs.end()) {
return {};
}
}
DrmOutput *drmOutput = itOutput->output;
@ -776,7 +855,12 @@ QSharedPointer<GLTexture> EglGbmBackend::textureForOutput(AbstractOutput *abstra
return glTexture;
}
EGLImageKHR image = eglCreateImageKHR(eglDisplay(), nullptr, EGL_NATIVE_PIXMAP_KHR, itOutput->buffer->getBo(), nullptr);
auto gbmBuffer = dynamic_cast<GbmBuffer*>(itOutput->buffer.data());
if (!gbmBuffer) {
qCWarning(KWIN_DRM) << "Failed to record frame: Dumb buffer used for presentation!";
return {};
}
EGLImageKHR image = eglCreateImageKHR(eglDisplay(), nullptr, EGL_NATIVE_PIXMAP_KHR, gbmBuffer->getBo(), nullptr);
if (image == EGL_NO_IMAGE_KHR) {
qCWarning(KWIN_DRM) << "Failed to record frame: Error creating EGLImageKHR - " << glGetError();
return {};

View file

@ -31,6 +31,7 @@ class DrmGbmBuffer;
class DrmOutput;
class GbmSurface;
class GbmBuffer;
class DumbSwapchain;
/**
* @brief OpenGL Backend using Egl on a GBM surface.
@ -58,8 +59,10 @@ public:
void addOutput(DrmOutput *output) override;
void removeOutput(DrmOutput *output) override;
int getDmabufForSecondaryGpuOutput(AbstractOutput *output, uint32_t *format, uint32_t *stride) override;
QRegion beginFrameForSecondaryGpu(AbstractOutput *output) override;
bool swapBuffers(DrmOutput *output) override;
bool exportFramebuffer(DrmOutput *output, void *data, const QSize &size, uint32_t stride) override;
int exportFramebufferAsDmabuf(DrmOutput *output, uint32_t *format, uint32_t *stride) override;
QRegion beginFrameForSecondaryGpu(DrmOutput *output) override;
bool directScanoutAllowed(int screen) const override;
@ -72,9 +75,13 @@ private:
bool initBufferConfigs();
bool initRenderingContext();
enum class ImportMode {
Dmabuf,
DumbBuffer
};
struct Output {
DrmOutput *output = nullptr;
QSharedPointer<DrmGbmBuffer> buffer;
QSharedPointer<DrmBuffer> buffer;
QSharedPointer<GbmBuffer> secondaryBuffer;
QSharedPointer<GbmSurface> gbmSurface;
EGLSurface eglSurface = EGL_NO_SURFACE;
@ -91,6 +98,8 @@ private:
} render;
KWaylandServer::SurfaceInterface *surfaceInterface = nullptr;
ImportMode importMode = ImportMode::Dmabuf;
QSharedPointer<DumbSwapchain> importSwapchain;
};
bool resetOutput(Output &output, DrmOutput *drmOutput);
@ -105,6 +114,7 @@ private:
void prepareRenderFramebuffer(const Output &output) const;
void renderFramebufferToSurface(Output &output);
QRegion prepareRenderingForOutput(Output &output) const;
void importFramebuffer(Output &output) const;
bool presentOnOutput(Output &output, const QRegion &damagedRegion);
bool directScanoutActive(const Output &output);

View file

@ -97,14 +97,8 @@ PlatformSurfaceTexture *EglMultiBackend::createPlatformSurfaceTextureWayland(Sur
QSharedPointer<GLTexture> EglMultiBackend::textureForOutput(AbstractOutput *requestedOutput) const
{
// this assumes that the wrong backends return {}
for (auto backend : qAsConst(m_backends)) {
auto texture = backend->textureForOutput(requestedOutput);
if (!texture.isNull()) {
return texture;
}
}
return {};
// this assumes that all outputs are rendered on backend 0
return m_backends[0]->textureForOutput(requestedOutput);
}
void EglMultiBackend::screenGeometryChanged(const QSize &size)

View file

@ -44,12 +44,9 @@ DrmQPainterBackend::DrmQPainterBackend(DrmBackend *backend, DrmGpu *gpu)
void DrmQPainterBackend::initOutput(DrmOutput *output)
{
Output o;
auto initBuffer = [&o, output, this] (int index) {
o.buffer[index] = QSharedPointer<DrmDumbBuffer>::create(m_gpu, output->pixelSize());
if (o.buffer[index]->map()) {
o.buffer[index]->image()->fill(Qt::black);
}
};
o.swapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, output->pixelSize());
o.output = output;
m_outputs << o;
connect(output, &DrmOutput::modeChanged, this,
[output, this] {
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
@ -60,26 +57,14 @@ void DrmQPainterBackend::initOutput(DrmOutput *output)
if (it == m_outputs.end()) {
return;
}
auto initBuffer = [it, output, this] (int index) {
it->buffer[index] = QSharedPointer<DrmDumbBuffer>::create(m_gpu, output->pixelSize());
if (it->buffer[index]->map()) {
it->buffer[index]->image()->fill(Qt::black);
}
};
initBuffer(0);
initBuffer(1);
it->swapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, output->pixelSize());
}
);
initBuffer(0);
initBuffer(1);
o.output = output;
m_outputs << o;
}
QImage *DrmQPainterBackend::bufferForScreen(int screenId)
{
const Output &o = m_outputs.at(screenId);
return o.buffer[o.index]->image();
return m_outputs[screenId].swapchain->currentBuffer()->image();
}
bool DrmQPainterBackend::needsFullRepaint(int screenId) const
@ -90,8 +75,7 @@ bool DrmQPainterBackend::needsFullRepaint(int screenId) const
void DrmQPainterBackend::beginFrame(int screenId)
{
Output &rendererOutput = m_outputs[screenId];
rendererOutput.index = (rendererOutput.index + 1) % 2;
m_outputs[screenId].swapchain->acquireBuffer();
}
void DrmQPainterBackend::endFrame(int screenId, int mask, const QRegion &damage)
@ -102,7 +86,7 @@ void DrmQPainterBackend::endFrame(int screenId, int mask, const QRegion &damage)
const Output &rendererOutput = m_outputs[screenId];
DrmOutput *drmOutput = rendererOutput.output;
if (!drmOutput->present(rendererOutput.buffer[rendererOutput.index])) {
if (!drmOutput->present(rendererOutput.swapchain->currentBuffer())) {
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop());
renderLoopPrivate->notifyFrameFailed();
}

View file

@ -14,6 +14,8 @@
#include <QVector>
#include <QSharedPointer>
#include "dumb_swapchain.h"
namespace KWin
{
@ -36,9 +38,8 @@ public:
private:
void initOutput(DrmOutput *output);
struct Output {
QSharedPointer<DrmDumbBuffer> buffer[2];
DrmOutput *output;
int index = 0;
QSharedPointer<DumbSwapchain> swapchain;
};
QVector<Output> m_outputs;
DrmBackend *m_backend;