platforms/drm: refactor the gbm surface
This commit is contained in:
parent
4b5571163e
commit
da71d218c8
11 changed files with 123 additions and 273 deletions
|
@ -371,13 +371,6 @@ target_link_libraries(testXkb
|
|||
add_test(NAME kwin-testXkb COMMAND testXkb)
|
||||
ecm_mark_as_test(testXkb)
|
||||
|
||||
if (HAVE_GBM)
|
||||
add_executable(testGbmSurface test_gbm_surface.cpp ../src/plugins/platforms/drm/gbm_surface.cpp)
|
||||
target_link_libraries(testGbmSurface Qt::Test)
|
||||
add_test(NAME kwin-testGbmSurface COMMAND testGbmSurface)
|
||||
ecm_mark_as_test(testGbmSurface)
|
||||
endif()
|
||||
|
||||
########################################################
|
||||
# Test FTrace
|
||||
########################################################
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "../src/plugins/platforms/drm/gbm_surface.h"
|
||||
#include <QtTest>
|
||||
|
||||
#include <gbm.h>
|
||||
|
||||
// mocking
|
||||
|
||||
struct gbm_device {
|
||||
bool surfaceShouldFail = false;
|
||||
};
|
||||
|
||||
struct gbm_surface {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t format;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct gbm_bo {
|
||||
};
|
||||
|
||||
struct gbm_surface *gbm_surface_create(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags)
|
||||
{
|
||||
if (gbm && gbm->surfaceShouldFail) {
|
||||
return nullptr;
|
||||
}
|
||||
auto ret = new gbm_surface{width, height, format, flags};
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gbm_surface_destroy(struct gbm_surface *surface)
|
||||
{
|
||||
delete surface;
|
||||
}
|
||||
|
||||
struct gbm_bo *gbm_surface_lock_front_buffer(struct gbm_surface *surface)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
return new gbm_bo;
|
||||
}
|
||||
|
||||
void gbm_surface_release_buffer(struct gbm_surface *surface, struct gbm_bo *bo)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
delete bo;
|
||||
}
|
||||
|
||||
using KWin::GbmSurface;
|
||||
|
||||
class GbmSurfaceTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private Q_SLOTS:
|
||||
void testCreate();
|
||||
void testCreateFailure();
|
||||
void testBo();
|
||||
};
|
||||
|
||||
void GbmSurfaceTest::testCreate()
|
||||
{
|
||||
GbmSurface surface(nullptr, 2, 3, 4, 5);
|
||||
gbm_surface *native = surface.surface();
|
||||
QVERIFY(surface);
|
||||
QCOMPARE(native->width, 2u);
|
||||
QCOMPARE(native->height, 3u);
|
||||
QCOMPARE(native->format, 4u);
|
||||
QCOMPARE(native->flags, 5u);
|
||||
}
|
||||
|
||||
void GbmSurfaceTest::testCreateFailure()
|
||||
{
|
||||
gbm_device dev{true};
|
||||
GbmSurface surface(&dev, 2, 3, 4, 5);
|
||||
QVERIFY(!surface);
|
||||
gbm_surface *native = surface.surface();
|
||||
QVERIFY(!native);
|
||||
}
|
||||
|
||||
void GbmSurfaceTest::testBo()
|
||||
{
|
||||
GbmSurface surface(nullptr, 2, 3, 4, 5);
|
||||
// release buffer on nullptr should not be a problem
|
||||
surface.releaseBuffer(nullptr);
|
||||
// now an actual buffer
|
||||
auto bo = surface.lockFrontBuffer();
|
||||
surface.releaseBuffer(bo);
|
||||
|
||||
// and a surface which fails
|
||||
gbm_device dev{true};
|
||||
GbmSurface surface2(&dev, 2, 3, 4, 5);
|
||||
QVERIFY(!surface2.lockFrontBuffer());
|
||||
auto bo2 = surface.lockFrontBuffer();
|
||||
// this won't do anything
|
||||
surface2.releaseBuffer(bo2);
|
||||
// so we need to clean up properly
|
||||
surface.releaseBuffer(bo2);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(GbmSurfaceTest)
|
||||
#include "test_gbm_surface.moc"
|
|
@ -25,8 +25,6 @@ public:
|
|||
|
||||
virtual bool needsModeChange(DrmBuffer *b) const {Q_UNUSED(b) return false;}
|
||||
|
||||
virtual void releaseGbm() {}
|
||||
|
||||
quint32 bufferId() const {
|
||||
return m_bufferId;
|
||||
}
|
||||
|
|
|
@ -28,15 +28,11 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
GbmBuffer::GbmBuffer(const QSharedPointer<GbmSurface> &surface)
|
||||
GbmBuffer::GbmBuffer(GbmSurface *surface, gbm_bo *bo)
|
||||
: m_surface(surface)
|
||||
, m_bo(bo)
|
||||
{
|
||||
m_bo = m_surface->lockFrontBuffer();
|
||||
if (m_bo) {
|
||||
m_stride = gbm_bo_get_stride(m_bo);
|
||||
} else {
|
||||
qCCritical(KWIN_DRM) << "failed to lock front buffer!" << strerror(errno);
|
||||
}
|
||||
m_stride = gbm_bo_get_stride(m_bo);
|
||||
}
|
||||
|
||||
GbmBuffer::GbmBuffer(gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface)
|
||||
|
@ -67,7 +63,8 @@ void GbmBuffer::releaseBuffer()
|
|||
gbm_bo_unmap(m_bo, m_mapping);
|
||||
}
|
||||
if (m_surface) {
|
||||
m_surface->releaseBuffer(m_bo);
|
||||
m_surface->releaseBuffer(this);
|
||||
m_surface = nullptr;
|
||||
} else {
|
||||
gbm_bo_destroy(m_bo);
|
||||
}
|
||||
|
@ -93,12 +90,9 @@ void GbmBuffer::clearBufferInterface()
|
|||
m_bufferInterface = nullptr;
|
||||
}
|
||||
|
||||
DrmGbmBuffer::DrmGbmBuffer(DrmGpu *gpu, const QSharedPointer<GbmSurface> &surface)
|
||||
: DrmBuffer(gpu), GbmBuffer(surface)
|
||||
DrmGbmBuffer::DrmGbmBuffer(DrmGpu *gpu, GbmSurface *surface, gbm_bo *bo)
|
||||
: DrmBuffer(gpu), GbmBuffer(surface, bo)
|
||||
{
|
||||
if (!m_bo) {
|
||||
return;
|
||||
}
|
||||
initialize();
|
||||
}
|
||||
|
||||
|
@ -117,11 +111,6 @@ DrmGbmBuffer::~DrmGbmBuffer()
|
|||
}
|
||||
}
|
||||
|
||||
void DrmGbmBuffer::releaseGbm()
|
||||
{
|
||||
releaseBuffer();
|
||||
}
|
||||
|
||||
void DrmGbmBuffer::initialize()
|
||||
{
|
||||
m_size = QSize(gbm_bo_get_width(m_bo), gbm_bo_get_height(m_bo));
|
||||
|
|
|
@ -30,7 +30,7 @@ class GbmBuffer : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GbmBuffer(const QSharedPointer<GbmSurface> &surface);
|
||||
GbmBuffer(GbmSurface *surface, gbm_bo *bo);
|
||||
GbmBuffer(gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface);
|
||||
virtual ~GbmBuffer();
|
||||
|
||||
|
@ -49,7 +49,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
QSharedPointer<GbmSurface> m_surface;
|
||||
GbmSurface *m_surface = nullptr;
|
||||
gbm_bo *m_bo = nullptr;
|
||||
KWaylandServer::BufferInterface *m_bufferInterface = nullptr;
|
||||
|
||||
|
@ -63,7 +63,7 @@ protected:
|
|||
class DrmGbmBuffer : public DrmBuffer, public GbmBuffer
|
||||
{
|
||||
public:
|
||||
DrmGbmBuffer(DrmGpu *gpu, const QSharedPointer<GbmSurface> &surface);
|
||||
DrmGbmBuffer(DrmGpu *gpu, GbmSurface *surface, gbm_bo *bo);
|
||||
DrmGbmBuffer(DrmGpu *gpu, gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface);
|
||||
~DrmGbmBuffer() override;
|
||||
|
||||
|
@ -75,8 +75,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void releaseGbm() override;
|
||||
|
||||
bool hasBo() const {
|
||||
return m_bo != nullptr;
|
||||
}
|
||||
|
|
|
@ -80,24 +80,6 @@ void DrmOutput::teardown()
|
|||
//this is needed so that the pageflipcallback handle isn't deleted
|
||||
}
|
||||
|
||||
void DrmOutput::releaseGbm()
|
||||
{
|
||||
if (auto buffer = m_crtc->current()) {
|
||||
buffer->releaseGbm();
|
||||
}
|
||||
if (auto buffer = m_crtc->next()) {
|
||||
buffer->releaseGbm();
|
||||
}
|
||||
if (m_primaryPlane) {
|
||||
if (auto buffer = m_primaryPlane->current()) {
|
||||
buffer->releaseGbm();
|
||||
}
|
||||
if (auto buffer = m_primaryPlane->next()) {
|
||||
buffer->releaseGbm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DrmOutput::hideCursor()
|
||||
{
|
||||
if (RenderLoopPrivate::get(m_renderLoop)->presentMode == RenderLoopPrivate::SyncMode::Adaptive
|
||||
|
|
|
@ -44,7 +44,6 @@ public:
|
|||
|
||||
///queues deleting the output after a page flip has completed.
|
||||
void teardown();
|
||||
void releaseGbm();
|
||||
bool showCursor(DrmDumbBuffer *buffer);
|
||||
bool showCursor();
|
||||
bool hideCursor();
|
||||
|
|
|
@ -55,27 +55,11 @@ EglGbmBackend::~EglGbmBackend()
|
|||
|
||||
void EglGbmBackend::cleanupSurfaces()
|
||||
{
|
||||
for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) {
|
||||
cleanupOutput(*it);
|
||||
}
|
||||
// shadow buffer needs context current for destruction
|
||||
makeCurrent();
|
||||
m_outputs.clear();
|
||||
}
|
||||
|
||||
void EglGbmBackend::cleanupOutput(Output &output)
|
||||
{
|
||||
if (output.shadowBuffer) {
|
||||
makeContextCurrent(output);
|
||||
output.shadowBuffer = nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
bool EglGbmBackend::initializeEgl()
|
||||
{
|
||||
initClientExtensions();
|
||||
|
@ -151,18 +135,6 @@ bool EglGbmBackend::initRenderingContext()
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
EGLSurface EglGbmBackend::createEglSurface(QSharedPointer<GbmSurface> gbmSurface) const
|
||||
{
|
||||
auto eglSurface = eglCreatePlatformWindowSurfaceEXT(eglDisplay(), config(),
|
||||
(void *)(gbmSurface->surface()), nullptr);
|
||||
if (eglSurface == EGL_NO_SURFACE) {
|
||||
qCCritical(KWIN_DRM) << "Creating EGL surface failed:" << getEglErrorString();
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
return eglSurface;
|
||||
}
|
||||
|
||||
bool EglGbmBackend::resetOutput(Output &output, DrmOutput *drmOutput)
|
||||
{
|
||||
output.output = drmOutput;
|
||||
|
@ -174,27 +146,11 @@ bool EglGbmBackend::resetOutput(Output &output, DrmOutput *drmOutput)
|
|||
} else {
|
||||
flags |= GBM_BO_USE_LINEAR;
|
||||
}
|
||||
auto gbmSurface = QSharedPointer<GbmSurface>::create(m_gpu->gbmDevice(),
|
||||
size.width(), size.height(),
|
||||
GBM_FORMAT_XRGB8888,
|
||||
flags);
|
||||
auto gbmSurface = QSharedPointer<GbmSurface>::create(m_gpu, size, GBM_FORMAT_XRGB8888, flags);
|
||||
if (!gbmSurface) {
|
||||
qCCritical(KWIN_DRM) << "Creating GBM surface failed" << strerror(errno);
|
||||
qCCritical(KWIN_DRM) << "Creating GBM surface failed:" << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
auto eglSurface = createEglSurface(gbmSurface);
|
||||
if (eglSurface == EGL_NO_SURFACE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// destroy previous surface
|
||||
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;
|
||||
output.gbmSurface = gbmSurface;
|
||||
|
||||
if (output.output->hardwareTransforms()) {
|
||||
|
@ -255,7 +211,8 @@ void EglGbmBackend::removeOutput(DrmOutput *drmOutput)
|
|||
return;
|
||||
}
|
||||
if (isPrimary()) {
|
||||
cleanupOutput(*it);
|
||||
// shadow buffer needs context current for destruction
|
||||
makeCurrent();
|
||||
} else {
|
||||
renderingBackend()->removeOutput((*it).output);
|
||||
}
|
||||
|
@ -273,19 +230,7 @@ bool EglGbmBackend::swapBuffers(DrmOutput *drmOutput)
|
|||
return false;
|
||||
}
|
||||
renderFramebufferToSurface(*it);
|
||||
auto error = eglSwapBuffers(eglDisplay(), it->eglSurface);
|
||||
if (error != EGL_TRUE) {
|
||||
qCCritical(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;
|
||||
}
|
||||
return it->gbmSurface->swapBuffers() != nullptr;
|
||||
}
|
||||
|
||||
bool EglGbmBackend::exportFramebuffer(DrmOutput *drmOutput, void *data, const QSize &size, uint32_t stride)
|
||||
|
@ -298,15 +243,15 @@ bool EglGbmBackend::exportFramebuffer(DrmOutput *drmOutput, void *data, const QS
|
|||
if (it == m_secondaryGpuOutputs.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!it->secondaryBuffer || !it->secondaryBuffer->map(GBM_BO_TRANSFER_READ)) {
|
||||
auto bo = it->gbmSurface->currentBuffer();
|
||||
if (!bo->map(GBM_BO_TRANSFER_READ)) {
|
||||
return false;
|
||||
}
|
||||
if (stride != it->secondaryBuffer->stride()) {
|
||||
if (stride != bo->stride()) {
|
||||
// shouldn't happen if formats are the same
|
||||
return false;
|
||||
}
|
||||
return memcpy(data, it->secondaryBuffer->mappedData(), size.height() * stride);
|
||||
return memcpy(data, bo->mappedData(), size.height() * stride);
|
||||
}
|
||||
|
||||
int EglGbmBackend::exportFramebufferAsDmabuf(DrmOutput *output, uint32_t *format, uint32_t *stride)
|
||||
|
@ -320,13 +265,14 @@ int EglGbmBackend::exportFramebufferAsDmabuf(DrmOutput *output, uint32_t *format
|
|||
if (it == m_secondaryGpuOutputs.end()) {
|
||||
return -1;
|
||||
}
|
||||
int fd = gbm_bo_get_fd(it->secondaryBuffer->getBo());
|
||||
auto bo = it->gbmSurface->currentBuffer()->getBo();
|
||||
int fd = gbm_bo_get_fd(bo);
|
||||
if (fd == -1) {
|
||||
qCWarning(KWIN_DRM) << "failed to export gbm_bo as dma-buf:" << strerror(errno);
|
||||
return -1;
|
||||
}
|
||||
*format = gbm_bo_get_format(it->secondaryBuffer->getBo());
|
||||
*stride = gbm_bo_get_stride(it->secondaryBuffer->getBo());
|
||||
*format = gbm_bo_get_format(bo);
|
||||
*stride = gbm_bo_get_stride(bo);
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
@ -406,11 +352,11 @@ void EglGbmBackend::renderFramebufferToSurface(Output &output)
|
|||
bool EglGbmBackend::makeContextCurrent(const Output &output) const
|
||||
{
|
||||
Q_ASSERT(isPrimary());
|
||||
const EGLSurface surface = output.eglSurface;
|
||||
if (surface == EGL_NO_SURFACE) {
|
||||
const auto surface = output.gbmSurface;
|
||||
if (!surface) {
|
||||
return false;
|
||||
}
|
||||
if (eglMakeCurrent(eglDisplay(), surface, surface, context()) == EGL_FALSE) {
|
||||
if (eglMakeCurrent(eglDisplay(), surface->eglSurface(), surface->eglSurface(), context()) == EGL_FALSE) {
|
||||
qCCritical(KWIN_DRM) << "eglMakeCurrent failed:" << getEglErrorString();
|
||||
return false;
|
||||
}
|
||||
|
@ -503,7 +449,7 @@ void EglGbmBackend::aboutToStartPainting(int screenId, const QRegion &damagedReg
|
|||
const QRegion region = damagedRegion & output.output->geometry();
|
||||
|
||||
QVector<EGLint> rects = regionToRects(region, output.output);
|
||||
const bool correct = eglSetDamageRegionKHR(eglDisplay(), output.eglSurface,
|
||||
const bool correct = eglSetDamageRegionKHR(eglDisplay(), output.gbmSurface->eglSurface(),
|
||||
rects.data(), rects.count()/4);
|
||||
if (!correct) {
|
||||
qCWarning(KWIN_DRM) << "eglSetDamageRegionKHR failed:" << getEglErrorString();
|
||||
|
@ -514,20 +460,7 @@ void EglGbmBackend::aboutToStartPainting(int screenId, const QRegion &damagedReg
|
|||
bool EglGbmBackend::presentOnOutput(Output &output, const QRegion &damagedRegion)
|
||||
{
|
||||
if (isPrimary() && !directScanoutActive(output)) {
|
||||
if (supportsSwapBuffersWithDamage()) {
|
||||
QVector<EGLint> rects = regionToRects(damagedRegion, output.output);
|
||||
if (!eglSwapBuffersWithDamageEXT(eglDisplay(), output.eglSurface,
|
||||
rects.data(), rects.count() / 4)) {
|
||||
qCCritical(KWIN_DRM) << "eglSwapBuffersWithDamageEXT() failed:" << getEglErrorString();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!eglSwapBuffers(eglDisplay(), output.eglSurface)) {
|
||||
qCCritical(KWIN_DRM) << "eglSwapBuffers() failed:" << getEglErrorString();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
output.buffer = QSharedPointer<DrmGbmBuffer>::create(m_gpu, output.gbmSurface);
|
||||
output.buffer = output.gbmSurface->swapBuffersForDrm();
|
||||
} else if (!output.buffer) {
|
||||
qCDebug(KWIN_DRM) << "imported buffer does not exist!";
|
||||
return false;
|
||||
|
@ -539,7 +472,7 @@ bool EglGbmBackend::presentOnOutput(Output &output, const QRegion &damagedRegion
|
|||
}
|
||||
|
||||
if (supportsBufferAge()) {
|
||||
eglQuerySurface(eglDisplay(), output.eglSurface, EGL_BUFFER_AGE_EXT, &output.bufferAge);
|
||||
eglQuerySurface(eglDisplay(), output.gbmSurface->eglSurface(), EGL_BUFFER_AGE_EXT, &output.bufferAge);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -83,9 +83,7 @@ private:
|
|||
struct Output {
|
||||
DrmOutput *output = nullptr;
|
||||
QSharedPointer<DrmBuffer> buffer;
|
||||
QSharedPointer<GbmBuffer> secondaryBuffer;
|
||||
QSharedPointer<GbmSurface> gbmSurface;
|
||||
EGLSurface eglSurface = EGL_NO_SURFACE;
|
||||
int bufferAge = 0;
|
||||
/**
|
||||
* @brief The damage history for the past 10 frames.
|
||||
|
@ -100,7 +98,6 @@ private:
|
|||
};
|
||||
|
||||
bool resetOutput(Output &output, DrmOutput *drmOutput);
|
||||
EGLSurface createEglSurface(QSharedPointer<GbmSurface> gbmSurface) const;
|
||||
|
||||
bool makeContextCurrent(const Output &output) const;
|
||||
void setViewport(const Output &output) const;
|
||||
|
@ -113,9 +110,6 @@ private:
|
|||
bool presentOnOutput(Output &output, const QRegion &damagedRegion);
|
||||
bool directScanoutActive(const Output &output);
|
||||
|
||||
void cleanupOutput(Output &output);
|
||||
void cleanupFramebuffer(Output &output);
|
||||
|
||||
QVector<Output> m_outputs;
|
||||
QVector<Output> m_secondaryGpuOutputs;
|
||||
|
||||
|
|
|
@ -9,36 +9,94 @@
|
|||
#include "gbm_surface.h"
|
||||
|
||||
#include <gbm.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "abstract_egl_backend.h"
|
||||
#include "drm_gpu.h"
|
||||
#include "logging.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
GbmSurface::GbmSurface(gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags)
|
||||
: m_surface(gbm_surface_create(gbm, width, height, format, flags))
|
||||
GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags)
|
||||
: m_surface(gbm_surface_create(gpu->gbmDevice(), size.width(), size.height(), format, flags))
|
||||
, m_gpu(gpu)
|
||||
{
|
||||
if (!m_surface) {
|
||||
qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno);
|
||||
return;
|
||||
}
|
||||
m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), m_gpu->eglBackend()->config(), (void *)(m_surface), nullptr);
|
||||
if (m_eglSurface == EGL_NO_SURFACE) {
|
||||
qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << eglGetError();
|
||||
}
|
||||
}
|
||||
|
||||
GbmSurface::~GbmSurface()
|
||||
{
|
||||
auto buffers = m_lockedBuffers;
|
||||
for (auto buffer : buffers) {
|
||||
buffer->releaseBuffer();
|
||||
}
|
||||
if (m_eglSurface != EGL_NO_SURFACE) {
|
||||
eglDestroySurface(m_gpu->eglDisplay(), m_eglSurface);
|
||||
}
|
||||
if (m_surface) {
|
||||
gbm_surface_destroy(m_surface);
|
||||
}
|
||||
}
|
||||
|
||||
gbm_bo *GbmSurface::lockFrontBuffer()
|
||||
QSharedPointer<DrmGbmBuffer> GbmSurface::swapBuffersForDrm()
|
||||
{
|
||||
if (!m_surface) {
|
||||
auto error = eglSwapBuffers(m_gpu->eglDisplay(), m_eglSurface);
|
||||
if (error != EGL_TRUE) {
|
||||
qCCritical(KWIN_DRM) << "an error occurred while swapping buffers" << error;
|
||||
return nullptr;
|
||||
}
|
||||
return gbm_surface_lock_front_buffer(m_surface);
|
||||
}
|
||||
|
||||
void GbmSurface::releaseBuffer(gbm_bo *bo)
|
||||
{
|
||||
if (!bo || !m_surface) {
|
||||
return;
|
||||
auto bo = gbm_surface_lock_front_buffer(m_surface);
|
||||
if (!bo) {
|
||||
return nullptr;
|
||||
}
|
||||
gbm_surface_release_buffer(m_surface, bo);
|
||||
auto buffer = QSharedPointer<DrmGbmBuffer>::create(m_gpu, this, bo);
|
||||
m_currentBuffer = buffer;
|
||||
m_lockedBuffers << m_currentBuffer.get();
|
||||
if (!buffer->bufferId()) {
|
||||
return nullptr;
|
||||
}
|
||||
m_currentDrmBuffer = buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
QSharedPointer<GbmBuffer> GbmSurface::swapBuffers()
|
||||
{
|
||||
auto error = eglSwapBuffers(m_gpu->eglDisplay(), m_eglSurface);
|
||||
if (error != EGL_TRUE) {
|
||||
qCCritical(KWIN_DRM) << "an error occurred while swapping buffers" << error;
|
||||
return nullptr;
|
||||
}
|
||||
auto bo = gbm_surface_lock_front_buffer(m_surface);
|
||||
if (!bo) {
|
||||
return nullptr;
|
||||
}
|
||||
m_currentBuffer = QSharedPointer<GbmBuffer>::create(this, bo);
|
||||
m_lockedBuffers << m_currentBuffer.get();
|
||||
return m_currentBuffer;
|
||||
}
|
||||
|
||||
void GbmSurface::releaseBuffer(GbmBuffer *buffer)
|
||||
{
|
||||
gbm_surface_release_buffer(m_surface, buffer->getBo());
|
||||
m_lockedBuffers.removeOne(buffer);
|
||||
}
|
||||
|
||||
QSharedPointer<GbmBuffer> GbmSurface::currentBuffer() const
|
||||
{
|
||||
return m_currentBuffer;
|
||||
}
|
||||
|
||||
QSharedPointer<DrmGbmBuffer> GbmSurface::currentDrmBuffer() const
|
||||
{
|
||||
return m_currentDrmBuffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,8 +10,11 @@
|
|||
#define KWIN_DRM_GBM_SURFACE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <epoxy/egl.h>
|
||||
#include <QVector>
|
||||
|
||||
#include "drm_buffer_gbm.h"
|
||||
|
||||
struct gbm_bo;
|
||||
struct gbm_device;
|
||||
struct gbm_surface;
|
||||
|
||||
|
@ -21,22 +24,33 @@ namespace KWin
|
|||
class GbmSurface
|
||||
{
|
||||
public:
|
||||
explicit GbmSurface(gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags);
|
||||
explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags);
|
||||
~GbmSurface();
|
||||
|
||||
gbm_bo *lockFrontBuffer();
|
||||
void releaseBuffer(gbm_bo *bo);
|
||||
QSharedPointer<DrmGbmBuffer> swapBuffersForDrm();
|
||||
QSharedPointer<GbmBuffer> swapBuffers();
|
||||
|
||||
operator bool() const {
|
||||
return m_surface != nullptr;
|
||||
void releaseBuffer(GbmBuffer *buffer);
|
||||
|
||||
QSharedPointer<GbmBuffer> currentBuffer() const;
|
||||
QSharedPointer<DrmGbmBuffer> currentDrmBuffer() const;
|
||||
|
||||
EGLSurface eglSurface() const {
|
||||
return m_eglSurface;
|
||||
}
|
||||
|
||||
gbm_surface* surface() const {
|
||||
return m_surface;
|
||||
bool isValid() const {
|
||||
return m_surface != nullptr && m_eglSurface != EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
private:
|
||||
gbm_surface *m_surface;
|
||||
DrmGpu *m_gpu;
|
||||
EGLSurface m_eglSurface = EGL_NO_SURFACE;
|
||||
|
||||
QSharedPointer<GbmBuffer> m_currentBuffer;
|
||||
QSharedPointer<DrmGbmBuffer> m_currentDrmBuffer;
|
||||
QVector<GbmBuffer*> m_lockedBuffers;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue