platforms/drm: improve buffer handling with GbmBuffer
This commit is contained in:
parent
dbdc30da7b
commit
50f03ac6dc
8 changed files with 105 additions and 128 deletions
|
@ -17,9 +17,8 @@ namespace KWin
|
|||
|
||||
class DrmGpu;
|
||||
|
||||
class DrmBuffer : public QObject
|
||||
class DrmBuffer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DrmBuffer(DrmGpu *gpu);
|
||||
virtual ~DrmBuffer() = default;
|
||||
|
@ -34,8 +33,6 @@ public:
|
|||
return m_size;
|
||||
}
|
||||
|
||||
virtual void releaseGbm() {}
|
||||
|
||||
DrmGpu *gpu() const {
|
||||
return m_gpu;
|
||||
}
|
||||
|
|
|
@ -28,12 +28,44 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
// DrmSurfaceBuffer
|
||||
DrmSurfaceBuffer::DrmSurfaceBuffer(DrmGpu *gpu, const QSharedPointer<GbmSurface> &surface)
|
||||
: DrmBuffer(gpu)
|
||||
, m_surface(surface)
|
||||
GbmBuffer::GbmBuffer(const QSharedPointer<GbmSurface> &surface)
|
||||
: m_surface(surface)
|
||||
{
|
||||
m_bo = m_surface->lockFrontBuffer();
|
||||
}
|
||||
|
||||
GbmBuffer::GbmBuffer(gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface)
|
||||
: m_bo(buffer)
|
||||
, m_bufferInterface(bufferInterface)
|
||||
{
|
||||
if (m_bufferInterface) {
|
||||
m_bufferInterface->ref();
|
||||
connect(m_bufferInterface, &KWaylandServer::BufferInterface::aboutToBeDestroyed, this, &GbmBuffer::clearBufferInterface);
|
||||
}
|
||||
}
|
||||
|
||||
GbmBuffer::~GbmBuffer()
|
||||
{
|
||||
if (m_bufferInterface) {
|
||||
clearBufferInterface();
|
||||
}
|
||||
if (m_surface) {
|
||||
m_surface->releaseBuffer(m_bo);
|
||||
} else if (m_bo) {
|
||||
gbm_bo_destroy(m_bo);
|
||||
}
|
||||
}
|
||||
|
||||
void GbmBuffer::clearBufferInterface()
|
||||
{
|
||||
disconnect(m_bufferInterface, &KWaylandServer::BufferInterface::aboutToBeDestroyed, this, &DrmGbmBuffer::clearBufferInterface);
|
||||
m_bufferInterface->unref();
|
||||
m_bufferInterface = nullptr;
|
||||
}
|
||||
|
||||
DrmGbmBuffer::DrmGbmBuffer(DrmGpu *gpu, const QSharedPointer<GbmSurface> &surface)
|
||||
: DrmBuffer(gpu), GbmBuffer(surface)
|
||||
{
|
||||
if (!m_bo) {
|
||||
qCWarning(KWIN_DRM) << "Locking front buffer failed";
|
||||
return;
|
||||
|
@ -41,45 +73,20 @@ DrmSurfaceBuffer::DrmSurfaceBuffer(DrmGpu *gpu, const QSharedPointer<GbmSurface>
|
|||
initialize();
|
||||
}
|
||||
|
||||
DrmSurfaceBuffer::DrmSurfaceBuffer(DrmGpu *gpu, gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface)
|
||||
: DrmBuffer(gpu)
|
||||
, m_bo(buffer)
|
||||
, m_bufferInterface(bufferInterface)
|
||||
DrmGbmBuffer::DrmGbmBuffer(DrmGpu *gpu, gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface)
|
||||
: DrmBuffer(gpu), GbmBuffer(buffer, bufferInterface)
|
||||
{
|
||||
if (m_bufferInterface) {
|
||||
m_bufferInterface->ref();
|
||||
connect(m_bufferInterface, &KWaylandServer::BufferInterface::aboutToBeDestroyed, this, &DrmSurfaceBuffer::clearBufferInterface);
|
||||
}
|
||||
initialize();
|
||||
}
|
||||
|
||||
DrmSurfaceBuffer::~DrmSurfaceBuffer()
|
||||
DrmGbmBuffer::~DrmGbmBuffer()
|
||||
{
|
||||
if (m_bufferId) {
|
||||
drmModeRmFB(m_gpu->fd(), m_bufferId);
|
||||
}
|
||||
releaseGbm();
|
||||
if (m_bufferInterface) {
|
||||
clearBufferInterface();
|
||||
}
|
||||
}
|
||||
|
||||
void DrmSurfaceBuffer::releaseGbm()
|
||||
{
|
||||
if (m_surface) {
|
||||
m_surface->releaseBuffer(m_bo);
|
||||
}
|
||||
m_bo = nullptr;
|
||||
}
|
||||
|
||||
void DrmSurfaceBuffer::clearBufferInterface()
|
||||
{
|
||||
disconnect(m_bufferInterface, &KWaylandServer::BufferInterface::aboutToBeDestroyed, this, &DrmSurfaceBuffer::clearBufferInterface);
|
||||
m_bufferInterface->unref();
|
||||
m_bufferInterface = nullptr;
|
||||
}
|
||||
|
||||
void DrmSurfaceBuffer::initialize()
|
||||
void DrmGbmBuffer::initialize()
|
||||
{
|
||||
m_size = QSize(gbm_bo_get_width(m_bo), gbm_bo_get_height(m_bo));
|
||||
uint32_t handles[4] = { };
|
||||
|
|
|
@ -26,15 +26,35 @@ namespace KWin
|
|||
|
||||
class GbmSurface;
|
||||
|
||||
class DrmSurfaceBuffer : public DrmBuffer
|
||||
class GbmBuffer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GbmBuffer(const QSharedPointer<GbmSurface> &surface);
|
||||
GbmBuffer(gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface);
|
||||
virtual ~GbmBuffer();
|
||||
|
||||
gbm_bo* getBo() const {
|
||||
return m_bo;
|
||||
}
|
||||
|
||||
protected:
|
||||
QSharedPointer<GbmSurface> m_surface;
|
||||
gbm_bo *m_bo = nullptr;
|
||||
KWaylandServer::BufferInterface *m_bufferInterface = nullptr;
|
||||
|
||||
void clearBufferInterface();
|
||||
};
|
||||
|
||||
class DrmGbmBuffer : public DrmBuffer, public GbmBuffer
|
||||
{
|
||||
public:
|
||||
DrmSurfaceBuffer(DrmGpu *gpu, const QSharedPointer<GbmSurface> &surface);
|
||||
DrmSurfaceBuffer(DrmGpu *gpu, gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface);
|
||||
~DrmSurfaceBuffer() override;
|
||||
DrmGbmBuffer(DrmGpu *gpu, const QSharedPointer<GbmSurface> &surface);
|
||||
DrmGbmBuffer(DrmGpu *gpu, gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface);
|
||||
~DrmGbmBuffer() override;
|
||||
|
||||
bool needsModeChange(DrmBuffer *b) const override {
|
||||
if (DrmSurfaceBuffer *sb = dynamic_cast<DrmSurfaceBuffer*>(b)) {
|
||||
if (DrmGbmBuffer *sb = dynamic_cast<DrmGbmBuffer*>(b)) {
|
||||
return hasBo() != sb->hasBo();
|
||||
} else {
|
||||
return true;
|
||||
|
@ -45,18 +65,7 @@ public:
|
|||
return m_bo != nullptr;
|
||||
}
|
||||
|
||||
gbm_bo* getBo() const {
|
||||
return m_bo;
|
||||
}
|
||||
|
||||
void releaseGbm() override;
|
||||
|
||||
private:
|
||||
QSharedPointer<GbmSurface> m_surface;
|
||||
gbm_bo *m_bo = nullptr;
|
||||
KWaylandServer::BufferInterface *m_bufferInterface = nullptr;
|
||||
|
||||
void clearBufferInterface();
|
||||
void initialize();
|
||||
};
|
||||
|
||||
|
|
|
@ -45,6 +45,9 @@ public:
|
|||
QSharedPointer<DrmBuffer> next() {
|
||||
return m_nextBuffer;
|
||||
}
|
||||
void setCurrent(const QSharedPointer<DrmBuffer> &buffer) {
|
||||
m_currentBuffer = buffer;
|
||||
}
|
||||
void setNext(const QSharedPointer<DrmBuffer> &buffer) {
|
||||
m_nextBuffer = buffer;
|
||||
}
|
||||
|
|
|
@ -77,14 +77,12 @@ void DrmOutput::teardown()
|
|||
//this is needed so that the pageflipcallback handle isn't deleted
|
||||
}
|
||||
|
||||
void DrmOutput::releaseGbm()
|
||||
void DrmOutput::releaseBuffers()
|
||||
{
|
||||
if (const auto &b = m_crtc->current()) {
|
||||
b->releaseGbm();
|
||||
}
|
||||
if (m_primaryPlane && m_primaryPlane->current()) {
|
||||
m_primaryPlane->current()->releaseGbm();
|
||||
}
|
||||
m_crtc->setCurrent(nullptr);
|
||||
m_crtc->setNext(nullptr);
|
||||
m_primaryPlane->setCurrent(nullptr);
|
||||
m_primaryPlane->setNext(nullptr);
|
||||
}
|
||||
|
||||
bool DrmOutput::hideCursor()
|
||||
|
@ -566,23 +564,11 @@ void DrmOutput::pageFlipped()
|
|||
return;
|
||||
}
|
||||
if (m_gpu->atomicModeSetting()) {
|
||||
if (!m_primaryPlane->next()) {
|
||||
if (m_primaryPlane->current()) {
|
||||
m_primaryPlane->current()->releaseGbm();
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (DrmPlane *p : m_nextPlanesFlipList) {
|
||||
p->flipBuffer();
|
||||
}
|
||||
m_nextPlanesFlipList.clear();
|
||||
} else {
|
||||
if (!m_crtc->next()) {
|
||||
// on manual vt switch
|
||||
if (const auto &b = m_crtc->current()) {
|
||||
b->releaseGbm();
|
||||
}
|
||||
}
|
||||
m_crtc->flipBuffer();
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
|
||||
///queues deleting the output after a page flip has completed.
|
||||
void teardown();
|
||||
void releaseGbm();
|
||||
void releaseBuffers();
|
||||
bool showCursor(DrmDumbBuffer *buffer);
|
||||
bool showCursor();
|
||||
bool hideCursor();
|
||||
|
|
|
@ -64,20 +64,13 @@ void EglGbmBackend::cleanupFramebuffer(Output &output)
|
|||
void EglGbmBackend::cleanupOutput(Output &output)
|
||||
{
|
||||
cleanupFramebuffer(output);
|
||||
output.output->releaseGbm();
|
||||
output.output->releaseBuffers();
|
||||
|
||||
output.buffer = nullptr;
|
||||
output.secondaryBuffer = nullptr;
|
||||
if (output.eglSurface != EGL_NO_SURFACE) {
|
||||
eglDestroySurface(eglDisplay(), output.eglSurface);
|
||||
}
|
||||
if (output.secondaryGbmBo) {
|
||||
output.gbmSurface.get()->releaseBuffer(output.secondaryGbmBo);
|
||||
}
|
||||
if (output.directScanoutBuffer) {
|
||||
gbm_bo_destroy(output.directScanoutBuffer);
|
||||
}
|
||||
if (output.dmabufFd) {
|
||||
close(output.dmabufFd);
|
||||
}
|
||||
}
|
||||
|
||||
bool EglGbmBackend::initializeEgl()
|
||||
|
@ -271,30 +264,22 @@ int EglGbmBackend::getDmabufForSecondaryGpuOutput(AbstractOutput *output, uint32
|
|||
if (it == m_secondaryGpuOutputs.end()) {
|
||||
return -1;
|
||||
}
|
||||
if (it->dmabufFd) {
|
||||
close(it->dmabufFd);
|
||||
it->dmabufFd = 0;
|
||||
}
|
||||
if (it->secondaryGbmBo) {
|
||||
it->gbmSurface.get()->releaseBuffer(it->secondaryGbmBo);
|
||||
it->secondaryGbmBo = nullptr;
|
||||
}
|
||||
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->secondaryGbmBo = it->gbmSurface->lockFrontBuffer();
|
||||
int fd = gbm_bo_get_fd(it->secondaryGbmBo);
|
||||
it->secondaryBuffer = QSharedPointer<GbmBuffer>::create(it->gbmSurface);
|
||||
int fd = gbm_bo_get_fd(it->buffer->getBo());
|
||||
if (fd == -1) {
|
||||
qCDebug(KWIN_DRM) << "failed to export gbm_bo as dma-buf!";
|
||||
return -1;
|
||||
}
|
||||
it->dmabufFd = fd;
|
||||
*format = gbm_bo_get_format(it->secondaryGbmBo);
|
||||
*stride = gbm_bo_get_stride(it->secondaryGbmBo);
|
||||
return it->dmabufFd;
|
||||
*format = gbm_bo_get_format(it->buffer->getBo());
|
||||
*stride = gbm_bo_get_stride(it->buffer->getBo());
|
||||
return fd;
|
||||
}
|
||||
|
||||
QRegion EglGbmBackend::beginFrameForSecondaryGpu(AbstractOutput *output)
|
||||
|
@ -450,15 +435,13 @@ void EglGbmBackend::renderFramebufferToSurface(Output &output)
|
|||
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);
|
||||
if (!importedBuffer) {
|
||||
qCDebug(KWIN_DRM) << "failed to import dma-buf!" << strerror(errno);
|
||||
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 {
|
||||
if (output.directScanoutBuffer) {
|
||||
gbm_bo_destroy(output.directScanoutBuffer);
|
||||
}
|
||||
output.directScanoutBuffer = importedBuffer;
|
||||
qCDebug(KWIN_DRM) << "failed to import dma-buf!" << strerror(errno);
|
||||
output.buffer = nullptr;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -580,9 +563,7 @@ void EglGbmBackend::aboutToStartPainting(int screenId, const QRegion &damagedReg
|
|||
|
||||
bool EglGbmBackend::presentOnOutput(Output &output, const QRegion &damagedRegion)
|
||||
{
|
||||
if (output.directScanoutBuffer) {
|
||||
output.buffer = QSharedPointer<DrmSurfaceBuffer>::create(m_gpu, output.directScanoutBuffer, output.bufferInterface);
|
||||
} else if (isPrimary()) {
|
||||
if (isPrimary() && !directScanoutActive(output)) {
|
||||
if (supportsSwapBuffersWithDamage()) {
|
||||
QVector<EGLint> rects = regionToRects(damagedRegion, output.output);
|
||||
if (!eglSwapBuffersWithDamageEXT(eglDisplay(), output.eglSurface,
|
||||
|
@ -596,8 +577,8 @@ bool EglGbmBackend::presentOnOutput(Output &output, const QRegion &damagedRegion
|
|||
return false;
|
||||
}
|
||||
}
|
||||
output.buffer = QSharedPointer<DrmSurfaceBuffer>::create(m_gpu, output.gbmSurface);
|
||||
} else {
|
||||
output.buffer = QSharedPointer<DrmGbmBuffer>::create(m_gpu, output.gbmSurface);
|
||||
} else if (!output.buffer) {
|
||||
qCDebug(KWIN_DRM) << "imported gbm_bo does not exist!";
|
||||
return false;
|
||||
}
|
||||
|
@ -613,6 +594,11 @@ bool EglGbmBackend::presentOnOutput(Output &output, const QRegion &damagedRegion
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EglGbmBackend::directScanoutActive(const Output &output)
|
||||
{
|
||||
return output.surfaceInterface != nullptr;
|
||||
}
|
||||
|
||||
SceneOpenGLTexturePrivate *EglGbmBackend::createBackendTexture(SceneOpenGLTexture *texture)
|
||||
{
|
||||
return new EglGbmTexture(texture, this);
|
||||
|
@ -631,12 +617,7 @@ void EglGbmBackend::setViewport(const Output &output) const
|
|||
QRegion EglGbmBackend::beginFrame(int screenId)
|
||||
{
|
||||
Output &output = m_outputs[screenId];
|
||||
if (output.directScanoutBuffer) {
|
||||
gbm_bo_destroy(output.directScanoutBuffer);
|
||||
output.directScanoutBuffer = nullptr;
|
||||
output.surfaceInterface = nullptr;
|
||||
output.bufferInterface = nullptr;
|
||||
}
|
||||
output.surfaceInterface = nullptr;
|
||||
if (isPrimary()) {
|
||||
return prepareRenderingForOutput(output);
|
||||
} else {
|
||||
|
@ -757,12 +738,8 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem)
|
|||
} else {
|
||||
damage = output.output->geometry();
|
||||
}
|
||||
if (output.directScanoutBuffer) {
|
||||
gbm_bo_destroy(output.directScanoutBuffer);
|
||||
}
|
||||
output.directScanoutBuffer = importedBuffer;
|
||||
output.buffer = QSharedPointer<DrmGbmBuffer>::create(m_gpu, importedBuffer, buffer);
|
||||
output.surfaceInterface = surface;
|
||||
output.bufferInterface = buffer;
|
||||
return presentOnOutput(output, damage);
|
||||
}
|
||||
|
||||
|
@ -784,8 +761,7 @@ QSharedPointer<GLTexture> EglGbmBackend::textureForOutput(AbstractOutput *abstra
|
|||
return glTexture;
|
||||
}
|
||||
|
||||
EGLImageKHR image = eglCreateImageKHR(eglDisplay(), nullptr, EGL_NATIVE_PIXMAP_KHR,
|
||||
itOutput->directScanoutBuffer ? itOutput->directScanoutBuffer : itOutput->buffer->getBo(), nullptr);
|
||||
EGLImageKHR image = eglCreateImageKHR(eglDisplay(), nullptr, EGL_NATIVE_PIXMAP_KHR, itOutput->buffer->getBo(), nullptr);
|
||||
if (image == EGL_NO_IMAGE_KHR) {
|
||||
qCWarning(KWIN_DRM) << "Failed to record frame: Error creating EGLImageKHR - " << glGetError();
|
||||
return {};
|
||||
|
|
|
@ -25,9 +25,10 @@ namespace KWin
|
|||
{
|
||||
class AbstractOutput;
|
||||
class DrmBuffer;
|
||||
class DrmSurfaceBuffer;
|
||||
class DrmGbmBuffer;
|
||||
class DrmOutput;
|
||||
class GbmSurface;
|
||||
class GbmBuffer;
|
||||
|
||||
/**
|
||||
* @brief OpenGL Backend using Egl on a GBM surface.
|
||||
|
@ -68,7 +69,8 @@ private:
|
|||
|
||||
struct Output {
|
||||
DrmOutput *output = nullptr;
|
||||
QSharedPointer<DrmSurfaceBuffer> buffer;
|
||||
QSharedPointer<DrmGbmBuffer> buffer;
|
||||
QSharedPointer<GbmBuffer> secondaryBuffer;
|
||||
QSharedPointer<GbmSurface> gbmSurface;
|
||||
EGLSurface eglSurface = EGL_NO_SURFACE;
|
||||
int bufferAge = 0;
|
||||
|
@ -83,11 +85,7 @@ private:
|
|||
QSharedPointer<GLVertexBuffer> vbo;
|
||||
} render;
|
||||
|
||||
int dmabufFd = 0;
|
||||
gbm_bo *secondaryGbmBo = nullptr;
|
||||
gbm_bo *directScanoutBuffer = nullptr;
|
||||
KWaylandServer::SurfaceInterface *surfaceInterface = nullptr;
|
||||
KWaylandServer::BufferInterface *bufferInterface = nullptr;
|
||||
};
|
||||
|
||||
bool resetOutput(Output &output, DrmOutput *drmOutput);
|
||||
|
@ -104,6 +102,7 @@ private:
|
|||
QRegion prepareRenderingForOutput(Output &output) const;
|
||||
|
||||
bool presentOnOutput(Output &output, const QRegion &damagedRegion);
|
||||
bool directScanoutActive(const Output &output);
|
||||
|
||||
void cleanupOutput(Output &output);
|
||||
void cleanupFramebuffer(Output &output);
|
||||
|
|
Loading…
Reference in a new issue