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;
};