diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 6b4a842059..493f033913 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -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 ######################################################## diff --git a/autotests/test_gbm_surface.cpp b/autotests/test_gbm_surface.cpp deleted file mode 100644 index 6d1b78f5bc..0000000000 --- a/autotests/test_gbm_surface.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2017 Martin Flöser - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "../src/plugins/platforms/drm/gbm_surface.h" -#include - -#include - -// 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" diff --git a/src/plugins/platforms/drm/drm_buffer.h b/src/plugins/platforms/drm/drm_buffer.h index 30b03e618c..1176a2c248 100644 --- a/src/plugins/platforms/drm/drm_buffer.h +++ b/src/plugins/platforms/drm/drm_buffer.h @@ -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; } diff --git a/src/plugins/platforms/drm/drm_buffer_gbm.cpp b/src/plugins/platforms/drm/drm_buffer_gbm.cpp index 1e2ecf2d1a..55dd4609d3 100644 --- a/src/plugins/platforms/drm/drm_buffer_gbm.cpp +++ b/src/plugins/platforms/drm/drm_buffer_gbm.cpp @@ -28,15 +28,11 @@ namespace KWin { -GbmBuffer::GbmBuffer(const QSharedPointer &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 &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)); diff --git a/src/plugins/platforms/drm/drm_buffer_gbm.h b/src/plugins/platforms/drm/drm_buffer_gbm.h index 64934f0295..23425a1d32 100644 --- a/src/plugins/platforms/drm/drm_buffer_gbm.h +++ b/src/plugins/platforms/drm/drm_buffer_gbm.h @@ -30,7 +30,7 @@ class GbmBuffer : public QObject { Q_OBJECT public: - GbmBuffer(const QSharedPointer &surface); + GbmBuffer(GbmSurface *surface, gbm_bo *bo); GbmBuffer(gbm_bo *buffer, KWaylandServer::BufferInterface *bufferInterface); virtual ~GbmBuffer(); @@ -49,7 +49,7 @@ public: } protected: - QSharedPointer 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 &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; } diff --git a/src/plugins/platforms/drm/drm_output.cpp b/src/plugins/platforms/drm/drm_output.cpp index e72ff1e13b..77a3b61e1f 100644 --- a/src/plugins/platforms/drm/drm_output.cpp +++ b/src/plugins/platforms/drm/drm_output.cpp @@ -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 diff --git a/src/plugins/platforms/drm/drm_output.h b/src/plugins/platforms/drm/drm_output.h index 1c2ebed884..7189085890 100644 --- a/src/plugins/platforms/drm/drm_output.h +++ b/src/plugins/platforms/drm/drm_output.h @@ -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(); diff --git a/src/plugins/platforms/drm/egl_gbm_backend.cpp b/src/plugins/platforms/drm/egl_gbm_backend.cpp index 06ba529549..45e880efea 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/src/plugins/platforms/drm/egl_gbm_backend.cpp @@ -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) 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::create(m_gpu->gbmDevice(), - size.width(), size.height(), - GBM_FORMAT_XRGB8888, - flags); + auto gbmSurface = QSharedPointer::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::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 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 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::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; } diff --git a/src/plugins/platforms/drm/egl_gbm_backend.h b/src/plugins/platforms/drm/egl_gbm_backend.h index 67017ef9b0..bff57674c2 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.h +++ b/src/plugins/platforms/drm/egl_gbm_backend.h @@ -83,9 +83,7 @@ private: struct Output { DrmOutput *output = nullptr; QSharedPointer buffer; - QSharedPointer secondaryBuffer; QSharedPointer 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) 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 m_outputs; QVector m_secondaryGpuOutputs; diff --git a/src/plugins/platforms/drm/gbm_surface.cpp b/src/plugins/platforms/drm/gbm_surface.cpp index 6357c319c5..d119338acd 100644 --- a/src/plugins/platforms/drm/gbm_surface.cpp +++ b/src/plugins/platforms/drm/gbm_surface.cpp @@ -9,36 +9,94 @@ #include "gbm_surface.h" #include +#include + +#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 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::create(m_gpu, this, bo); + m_currentBuffer = buffer; + m_lockedBuffers << m_currentBuffer.get(); + if (!buffer->bufferId()) { + return nullptr; + } + m_currentDrmBuffer = buffer; + return buffer; +} + +QSharedPointer 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::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 GbmSurface::currentBuffer() const +{ + return m_currentBuffer; +} + +QSharedPointer GbmSurface::currentDrmBuffer() const +{ + return m_currentDrmBuffer; } } diff --git a/src/plugins/platforms/drm/gbm_surface.h b/src/plugins/platforms/drm/gbm_surface.h index 5dd40b0929..052fce76fd 100644 --- a/src/plugins/platforms/drm/gbm_surface.h +++ b/src/plugins/platforms/drm/gbm_surface.h @@ -10,8 +10,11 @@ #define KWIN_DRM_GBM_SURFACE_H #include +#include +#include + +#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 swapBuffersForDrm(); + QSharedPointer swapBuffers(); - operator bool() const { - return m_surface != nullptr; + void releaseBuffer(GbmBuffer *buffer); + + QSharedPointer currentBuffer() const; + QSharedPointer 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 m_currentBuffer; + QSharedPointer m_currentDrmBuffer; + QVector m_lockedBuffers; }; }