From efedddd905c3e4998d164f7702f7cdca4f7fd160 Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Tue, 9 May 2017 21:00:33 +0200 Subject: [PATCH] [DRM plugin] Reorganize DrmBuffer Split off GBM based buffers to a separate file, which gets only included, when GBM is available. Note, that this also removes the gbmCallback, since already before this patch we did delete the buffers always without it. The plan is to later use this file for via GBM directly imported Wayland buffers as well. Test Plan: Tested with Gl and QPainter backends. Reviewers: #kwin Subscribers: kwin, #kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D5179 --- plugins/platforms/drm/CMakeLists.txt | 2 +- plugins/platforms/drm/drm_backend.cpp | 22 ++---- plugins/platforms/drm/drm_backend.h | 19 +++-- plugins/platforms/drm/drm_buffer.cpp | 73 +++++-------------- plugins/platforms/drm/drm_buffer.h | 68 ++++++++--------- plugins/platforms/drm/drm_buffer_gbm.cpp | 69 ++++++++++++++++++ plugins/platforms/drm/drm_buffer_gbm.h | 61 ++++++++++++++++ plugins/platforms/drm/drm_object_crtc.cpp | 6 +- plugins/platforms/drm/drm_object_crtc.h | 3 +- plugins/platforms/drm/drm_output.cpp | 11 ++- plugins/platforms/drm/drm_output.h | 4 +- .../drm/scene_qpainter_drm_backend.h | 4 +- 12 files changed, 217 insertions(+), 125 deletions(-) create mode 100644 plugins/platforms/drm/drm_buffer_gbm.cpp create mode 100644 plugins/platforms/drm/drm_buffer_gbm.h diff --git a/plugins/platforms/drm/CMakeLists.txt b/plugins/platforms/drm/CMakeLists.txt index 4f3a3ab3cf..a0d22c8f56 100644 --- a/plugins/platforms/drm/CMakeLists.txt +++ b/plugins/platforms/drm/CMakeLists.txt @@ -13,7 +13,7 @@ set(DRM_SOURCES ) if(HAVE_GBM) - set(DRM_SOURCES ${DRM_SOURCES} egl_gbm_backend.cpp) + set(DRM_SOURCES ${DRM_SOURCES} egl_gbm_backend.cpp drm_buffer_gbm.cpp) endif() add_library(KWinWaylandDrmBackend MODULE ${DRM_SOURCES}) diff --git a/plugins/platforms/drm/drm_backend.cpp b/plugins/platforms/drm/drm_backend.cpp index cc79aca1d7..cb15ad23e0 100644 --- a/plugins/platforms/drm/drm_backend.cpp +++ b/plugins/platforms/drm/drm_backend.cpp @@ -167,7 +167,7 @@ void DrmBackend::reactivate() } m_active = true; if (!usesSoftwareCursor()) { - DrmBuffer *c = m_cursor[(m_cursorIndex + 1) % 2]; + DrmDumbBuffer *c = m_cursor[(m_cursorIndex + 1) % 2]; const QPoint cp = Cursor::pos() - softwareCursorHotspot(); for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { DrmOutput *o = *it; @@ -608,7 +608,7 @@ void DrmBackend::initCursor() void DrmBackend::setCursor() { - DrmBuffer *c = m_cursor[m_cursorIndex]; + DrmDumbBuffer *c = m_cursor[m_cursorIndex]; m_cursorIndex = (m_cursorIndex + 1) % 2; if (m_cursorEnabled) { for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { @@ -675,42 +675,36 @@ Screens *DrmBackend::createScreens(QObject *parent) QPainterBackend *DrmBackend::createQPainterBackend() { + m_deleteBufferAfterPageFlip = false; return new DrmQPainterBackend(this); } OpenGLBackend *DrmBackend::createOpenGLBackend() { #if HAVE_GBM + m_deleteBufferAfterPageFlip = true; return new EglGbmBackend(this); #else return Platform::createOpenGLBackend(); #endif } -DrmBuffer *DrmBackend::createBuffer(const QSize &size) +DrmDumbBuffer *DrmBackend::createBuffer(const QSize &size) { - DrmBuffer *b = new DrmBuffer(this, size); - m_buffers << b; + DrmDumbBuffer *b = new DrmDumbBuffer(this, size); return b; } -DrmBuffer *DrmBackend::createBuffer(gbm_surface *surface) +DrmSurfaceBuffer *DrmBackend::createBuffer(gbm_surface *surface) { #if HAVE_GBM - DrmBuffer *b = new DrmBuffer(this, surface); - b->m_deleteAfterPageFlip = true; - m_buffers << b; + DrmSurfaceBuffer *b = new DrmSurfaceBuffer(this, surface); return b; #else return nullptr; #endif } -void DrmBackend::bufferDestroyed(DrmBuffer *b) -{ - m_buffers.removeAll(b); -} - void DrmBackend::outputDpmsChanged() { if (m_outputs.isEmpty()) { diff --git a/plugins/platforms/drm/drm_backend.h b/plugins/platforms/drm/drm_backend.h index fa056f5c86..75dbbae2f2 100644 --- a/plugins/platforms/drm/drm_backend.h +++ b/plugins/platforms/drm/drm_backend.h @@ -23,6 +23,9 @@ along with this program. If not, see . #include "input.h" #include "drm_buffer.h" +#if HAVE_GBM +#include "drm_buffer_gbm.h" +#endif #include "drm_inputeventfilter.h" #include "drm_pointer.h" @@ -74,8 +77,8 @@ public: OpenGLBackend* createOpenGLBackend() override; void init() override; - DrmBuffer *createBuffer(const QSize &size); - DrmBuffer *createBuffer(gbm_surface *surface); + DrmDumbBuffer *createBuffer(const QSize &size); + DrmSurfaceBuffer *createBuffer(gbm_surface *surface); void present(DrmBuffer *buffer, DrmOutput *output); int fd() const { @@ -84,17 +87,17 @@ public: QVector outputs() const { return m_outputs; } - QVector buffers() const { - return m_buffers; - } QVector planes() const { return m_planes; } - void bufferDestroyed(DrmBuffer *b); void outputWentOff(); void checkOutputsAreOn(); + // QPainter reuses buffers + bool deleteBufferAfterPageFlip() const { + return m_deleteBufferAfterPageFlip; + } // returns use of AMS, default is not/legacy bool atomicModeSetting() const { return m_atomicModeSetting; @@ -145,13 +148,13 @@ private: QVector m_connectors; // currently active output pipelines (planes + crtc + encoder + connector) QVector m_outputs; - DrmBuffer *m_cursor[2]; + DrmDumbBuffer *m_cursor[2]; + bool m_deleteBufferAfterPageFlip; bool m_atomicModeSetting = false; bool m_cursorEnabled = false; int m_cursorIndex = 0; int m_pageFlipsPending = 0; bool m_active = false; - QVector m_buffers; // all available planes: primarys, cursors and overlays QVector m_planes; QScopedPointer m_dpmsFilter; diff --git a/plugins/platforms/drm/drm_buffer.cpp b/plugins/platforms/drm/drm_buffer.cpp index d29059967a..a28c459423 100644 --- a/plugins/platforms/drm/drm_buffer.cpp +++ b/plugins/platforms/drm/drm_buffer.cpp @@ -27,18 +27,20 @@ along with this program. If not, see . #include // drm #include -#if HAVE_GBM -#include -#endif namespace KWin { - -DrmBuffer::DrmBuffer(DrmBackend *backend, const QSize &size) +DrmBuffer:: DrmBuffer(DrmBackend *backend) : m_backend(backend) - , m_size(size) { +} + +// DrmDumbBuffer +DrmDumbBuffer::DrmDumbBuffer(DrmBackend *backend, const QSize &size) + : DrmBuffer(backend) +{ + m_size = size; drm_mode_create_dumb createArgs; memset(&createArgs, 0, sizeof createArgs); createArgs.bpp = 32; @@ -57,46 +59,12 @@ DrmBuffer::DrmBuffer(DrmBackend *backend, const QSize &size) } } - -#if HAVE_GBM -static void gbmCallback(gbm_bo *bo, void *data) -{ - DrmBackend *backend = reinterpret_cast(data); - const auto &buffers = backend->buffers(); - for (auto buffer: buffers) { - if (buffer->gbm() == bo) { - delete buffer; - return; - } - } -} -#endif - -DrmBuffer::DrmBuffer(DrmBackend *backend, gbm_surface *surface) - : m_backend(backend) - , m_surface(surface) -{ -#if HAVE_GBM - m_bo = gbm_surface_lock_front_buffer(surface); - if (!m_bo) { - qCWarning(KWIN_DRM) << "Locking front buffer failed"; - return; - } - m_size = QSize(gbm_bo_get_width(m_bo), gbm_bo_get_height(m_bo)); - m_stride = gbm_bo_get_stride(m_bo); - if (drmModeAddFB(m_backend->fd(), m_size.width(), m_size.height(), 24, 32, m_stride, gbm_bo_get_handle(m_bo).u32, &m_bufferId) != 0) { - qCWarning(KWIN_DRM) << "drmModeAddFB failed"; - } - gbm_bo_set_user_data(m_bo, m_backend, gbmCallback); -#endif -} - -DrmBuffer::~DrmBuffer() +DrmDumbBuffer::~DrmDumbBuffer() { if (m_bufferId) { drmModeRmFB(m_backend->fd(), m_bufferId); } - m_backend->bufferDestroyed(this); + delete m_image; if (m_memory) { munmap(m_memory, m_bufferSize); @@ -106,10 +74,17 @@ DrmBuffer::~DrmBuffer() destroyArgs.handle = m_handle; drmIoctl(m_backend->fd(), DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); } - releaseGbm(); } -bool DrmBuffer::map(QImage::Format format) +bool DrmDumbBuffer::needsModeChange(DrmBuffer *b) const { + if (DrmDumbBuffer *db = dynamic_cast(b)) { + return m_stride != db->stride(); + } else { + return true; + } +} + +bool DrmDumbBuffer::map(QImage::Format format) { if (!m_handle || !m_bufferId) { return false; @@ -129,14 +104,4 @@ bool DrmBuffer::map(QImage::Format format) return !m_image->isNull(); } -void DrmBuffer::releaseGbm() -{ -#if HAVE_GBM - if (m_bo) { - gbm_surface_release_buffer(m_surface, m_bo); - m_bo = nullptr; - } -#endif -} - } diff --git a/plugins/platforms/drm/drm_buffer.h b/plugins/platforms/drm/drm_buffer.h index 0c7083d7d6..ab50f00ba6 100644 --- a/plugins/platforms/drm/drm_buffer.h +++ b/plugins/platforms/drm/drm_buffer.h @@ -23,9 +23,6 @@ along with this program. If not, see . #include #include -struct gbm_bo; -struct gbm_surface; - namespace KWin { @@ -34,50 +31,53 @@ class DrmBackend; class DrmBuffer { public: - ~DrmBuffer(); + DrmBuffer(DrmBackend *backend); + virtual ~DrmBuffer() = default; + + virtual bool needsModeChange(DrmBuffer *b) const {Q_UNUSED(b) return false;} - bool map(QImage::Format format = QImage::Format_RGB32); - QImage *image() const { - return m_image; - } - quint32 handle() const { - return m_handle; - } - const QSize &size() const { - return m_size; - } quint32 bufferId() const { return m_bufferId; } + + const QSize &size() const { + return m_size; + } + + virtual void releaseGbm() {} + +protected: + DrmBackend *m_backend; + quint32 m_bufferId = 0; + QSize m_size; +}; + +class DrmDumbBuffer : public DrmBuffer +{ +public: + DrmDumbBuffer(DrmBackend *backend, const QSize &size); + ~DrmDumbBuffer(); + + bool needsModeChange(DrmBuffer *b) const override; + + bool map(QImage::Format format = QImage::Format_RGB32); + quint32 handle() const { + return m_handle; + } + QImage *image() const { + return m_image; + } + quint32 stride() const { return m_stride; } - gbm_bo *gbm() const { - return m_bo; - } - bool isGbm() const { - return m_bo != nullptr; - } - bool deleteAfterPageFlip() const { - return m_deleteAfterPageFlip; - } - void releaseGbm(); private: - friend class DrmBackend; - DrmBuffer(DrmBackend *backend, const QSize &size); - DrmBuffer(DrmBackend *backend, gbm_surface *surface); - DrmBackend *m_backend; - gbm_surface *m_surface = nullptr; - gbm_bo *m_bo = nullptr; - QSize m_size; quint32 m_handle = 0; - quint32 m_bufferId = 0; - quint32 m_stride = 0; quint64 m_bufferSize = 0; void *m_memory = nullptr; QImage *m_image = nullptr; - bool m_deleteAfterPageFlip = false; + quint32 m_stride = 0; }; } diff --git a/plugins/platforms/drm/drm_buffer_gbm.cpp b/plugins/platforms/drm/drm_buffer_gbm.cpp new file mode 100644 index 0000000000..8cebfc0516 --- /dev/null +++ b/plugins/platforms/drm/drm_buffer_gbm.cpp @@ -0,0 +1,69 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright 2017 Roman Gilg +Copyright 2015 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "drm_backend.h" +#include "drm_buffer_gbm.h" + +#include "logging.h" + +// system +#include +#include +// drm +#include +#include + +namespace KWin +{ + +// DrmSurfaceBuffer +DrmSurfaceBuffer::DrmSurfaceBuffer(DrmBackend *backend, gbm_surface *surface) + : DrmBuffer(backend) + , m_surface(surface) +{ + m_bo = gbm_surface_lock_front_buffer(surface); + if (!m_bo) { + qCWarning(KWIN_DRM) << "Locking front buffer failed"; + return; + } + m_size = QSize(gbm_bo_get_width(m_bo), gbm_bo_get_height(m_bo)); + if (drmModeAddFB(m_backend->fd(), m_size.width(), m_size.height(), 24, 32, gbm_bo_get_stride(m_bo), gbm_bo_get_handle(m_bo).u32, &m_bufferId) != 0) { + qCWarning(KWIN_DRM) << "drmModeAddFB failed"; + } + gbm_bo_set_user_data(m_bo, this, nullptr); +} + +DrmSurfaceBuffer::~DrmSurfaceBuffer() +{ + if (m_bufferId) { + drmModeRmFB(m_backend->fd(), m_bufferId); + } + releaseGbm(); +} + +void DrmSurfaceBuffer::releaseGbm() +{ + if (m_bo) { + gbm_surface_release_buffer(m_surface, m_bo); + m_bo = nullptr; + } +} + +} diff --git a/plugins/platforms/drm/drm_buffer_gbm.h b/plugins/platforms/drm/drm_buffer_gbm.h new file mode 100644 index 0000000000..82224b116d --- /dev/null +++ b/plugins/platforms/drm/drm_buffer_gbm.h @@ -0,0 +1,61 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright 2017 Roman Gilg +Copyright 2015 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_DRM_BUFFER_GBM_H +#define KWIN_DRM_BUFFER_GBM_H + +#include "drm_buffer.h" + +struct gbm_bo; +struct gbm_surface; + +namespace KWin +{ + +class DrmBackend; + +class DrmSurfaceBuffer : public DrmBuffer +{ +public: + DrmSurfaceBuffer(DrmBackend *backend, gbm_surface *surface); + ~DrmSurfaceBuffer(); + + bool needsModeChange(DrmBuffer *b) const override { + if (DrmSurfaceBuffer *sb = dynamic_cast(b)) { + return hasBo() != sb->hasBo(); + } else { + return true; + } + } + + bool hasBo() const { + return m_bo != nullptr; + } + void releaseGbm() override; + +private: + gbm_surface *m_surface = nullptr; + gbm_bo *m_bo = nullptr; +}; + +} + +#endif + diff --git a/plugins/platforms/drm/drm_object_crtc.cpp b/plugins/platforms/drm/drm_object_crtc.cpp index ec83a3ca13..3aa3870cd4 100644 --- a/plugins/platforms/drm/drm_object_crtc.cpp +++ b/plugins/platforms/drm/drm_object_crtc.cpp @@ -69,7 +69,7 @@ bool DrmCrtc::initProps() void DrmCrtc::flipBuffer() { - if (m_currentBuffer && m_currentBuffer->deleteAfterPageFlip() && m_currentBuffer != m_nextBuffer) { + if (m_currentBuffer && m_output->m_backend->deleteBufferAfterPageFlip() && m_currentBuffer != m_nextBuffer) { delete m_currentBuffer; } m_currentBuffer = m_nextBuffer; @@ -82,7 +82,7 @@ void DrmCrtc::flipBuffer() bool DrmCrtc::blank() { if (!m_blackBuffer) { - DrmBuffer *blackBuffer = m_output->m_backend->createBuffer(m_output->pixelSize()); + DrmDumbBuffer *blackBuffer = m_output->m_backend->createBuffer(m_output->pixelSize()); if (!blackBuffer->map()) { delete blackBuffer; return false; @@ -93,7 +93,7 @@ bool DrmCrtc::blank() // TODO: Do this atomically if (m_output->setModeLegacy(m_blackBuffer)) { - if (m_currentBuffer && m_currentBuffer->deleteAfterPageFlip()) { + if (m_currentBuffer && m_output->m_backend->deleteBufferAfterPageFlip()) { delete m_currentBuffer; delete m_nextBuffer; } diff --git a/plugins/platforms/drm/drm_object_crtc.h b/plugins/platforms/drm/drm_object_crtc.h index 1179c9b6a5..789c08e4aa 100644 --- a/plugins/platforms/drm/drm_object_crtc.h +++ b/plugins/platforms/drm/drm_object_crtc.h @@ -27,6 +27,7 @@ namespace KWin class DrmBackend; class DrmBuffer; +class DrmDumbBuffer; class DrmCrtc : public DrmObject { @@ -68,7 +69,7 @@ private: DrmBuffer *m_currentBuffer = nullptr; DrmBuffer *m_nextBuffer = nullptr; - DrmBuffer *m_blackBuffer = nullptr; + DrmDumbBuffer *m_blackBuffer = nullptr; }; } diff --git a/plugins/platforms/drm/drm_output.cpp b/plugins/platforms/drm/drm_output.cpp index 034fa8a622..cd6d027bb7 100644 --- a/plugins/platforms/drm/drm_output.cpp +++ b/plugins/platforms/drm/drm_output.cpp @@ -84,7 +84,7 @@ void DrmOutput::hideCursor() drmModeSetCursor(m_backend->fd(), m_crtc->id(), 0, 0, 0); } -void DrmOutput::showCursor(DrmBuffer *c) +void DrmOutput::showCursor(DrmDumbBuffer *c) { const QSize &s = c->size(); drmModeSetCursor(m_backend->fd(), m_crtc->id(), c->handle(), s.width(), s.height()); @@ -706,7 +706,7 @@ void DrmOutput::pageFlipped() void DrmOutput::pageFlippedBufferRemover(DrmBuffer *oldbuffer, DrmBuffer *newbuffer) { - if (oldbuffer && oldbuffer->deleteAfterPageFlip() && oldbuffer != newbuffer) { + if (oldbuffer && m_backend->deleteBufferAfterPageFlip() && oldbuffer != newbuffer) { delete oldbuffer; } } @@ -841,9 +841,10 @@ bool DrmOutput::presentLegacy(DrmBuffer *buffer) } // Do we need to set a new mode first? - if (m_lastStride != buffer->stride() || m_lastGbm != buffer->isGbm()){ - if (!setModeLegacy(buffer)) + if (!m_crtc->current() || m_crtc->current()->needsModeChange(buffer)) { + if (!setModeLegacy(buffer)) { return false; + } } int errno_save = 0; const bool ok = drmModePageFlip(m_backend->fd(), m_crtc->id(), buffer->bufferId(), DRM_MODE_PAGE_FLIP_EVENT, this) == 0; @@ -861,8 +862,6 @@ bool DrmOutput::setModeLegacy(DrmBuffer *buffer) { uint32_t connId = m_conn->id(); if (drmModeSetCrtc(m_backend->fd(), m_crtc->id(), buffer->bufferId(), 0, 0, &connId, 1, &m_mode) == 0) { - m_lastStride = buffer->stride(); - m_lastGbm = buffer->isGbm(); return true; } else { qCWarning(KWIN_DRM) << "Mode setting failed"; diff --git a/plugins/platforms/drm/drm_output.h b/plugins/platforms/drm/drm_output.h index bcf193b271..f262f016b6 100644 --- a/plugins/platforms/drm/drm_output.h +++ b/plugins/platforms/drm/drm_output.h @@ -46,6 +46,7 @@ namespace KWin class DrmBackend; class DrmBuffer; +class DrmDumbBuffer; class DrmPlane; class DrmConnector; class DrmCrtc; @@ -62,7 +63,7 @@ public: }; virtual ~DrmOutput(); void releaseGbm(); - void showCursor(DrmBuffer *buffer); + void showCursor(DrmDumbBuffer *buffer); void hideCursor(); void moveCursor(const QPoint &globalPos); bool init(drmModeConnector *connector); @@ -129,7 +130,6 @@ private: DrmCrtc *m_crtc = nullptr; QPoint m_globalPos; qreal m_scale = 1; - quint32 m_lastStride = 0; bool m_lastGbm = false; drmModeModeInfo m_mode; Edid m_edid; diff --git a/plugins/platforms/drm/scene_qpainter_drm_backend.h b/plugins/platforms/drm/scene_qpainter_drm_backend.h index 9a8564f22e..1a068b4fc8 100644 --- a/plugins/platforms/drm/scene_qpainter_drm_backend.h +++ b/plugins/platforms/drm/scene_qpainter_drm_backend.h @@ -26,7 +26,7 @@ namespace KWin { class DrmBackend; -class DrmBuffer; +class DrmDumbBuffer; class DrmOutput; class DrmQPainterBackend : public QObject, public QPainterBackend @@ -47,7 +47,7 @@ public: private: void initOutput(DrmOutput *output); struct Output { - DrmBuffer *buffer[2]; + DrmDumbBuffer *buffer[2]; DrmOutput *output; int index = 0; };