From 08ab2c424ed00d07252d95aea4e0306b08813a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 20 Aug 2014 15:29:38 +0200 Subject: [PATCH] [kwin_wayland] Split out Buffer and ShmPool into dedicated files Moved from wayland_backend.[h|cpp] to buffer.[h|cpp] and shm_pool.[h|cpp]. Buffer is slightly adjusted to have the ShmPool passed in as a ctor argument and the ctor is private and friended with ShmPool, so that it can only be constructed from ShmPool. --- CMakeLists.txt | 2 + scene_qpainter.cpp | 2 + scene_xrender.cpp | 1 + wayland_backend.cpp | 165 +----------------------------------- wayland_backend.h | 112 ------------------------ wayland_client/buffer.cpp | 69 +++++++++++++++ wayland_client/buffer.h | 116 +++++++++++++++++++++++++ wayland_client/shm_pool.cpp | 156 ++++++++++++++++++++++++++++++++++ wayland_client/shm_pool.h | 87 +++++++++++++++++++ 9 files changed, 435 insertions(+), 275 deletions(-) create mode 100644 wayland_client/buffer.cpp create mode 100644 wayland_client/buffer.h create mode 100644 wayland_client/shm_pool.cpp create mode 100644 wayland_client/shm_pool.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bcd2c9768..6fcbf2dd80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -426,11 +426,13 @@ if(Wayland_Client_FOUND AND XKB_FOUND) set(kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} wayland_backend.cpp + wayland_client/buffer.cpp wayland_client/connection_thread.cpp wayland_client/registry.cpp wayland_client/fullscreen_shell.cpp wayland_client/output.cpp wayland_client/shell.cpp + wayland_client/shm_pool.cpp wayland_client/surface.cpp ${CMAKE_BINARY_DIR}/wayland_protocols/wayland-client-fullscreen-shell.c ) diff --git a/scene_qpainter.cpp b/scene_qpainter.cpp index f3e7f36c43..fcbb2e878c 100644 --- a/scene_qpainter.cpp +++ b/scene_qpainter.cpp @@ -28,6 +28,8 @@ along with this program. If not, see . #include "toplevel.h" #if HAVE_WAYLAND #include "wayland_backend.h" +#include "wayland_client/buffer.h" +#include "wayland_client/shm_pool.h" #include "wayland_client/surface.h" #endif #include "workspace.h" diff --git a/scene_xrender.cpp b/scene_xrender.cpp index b373e4c44b..dcaade1819 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -37,6 +37,7 @@ along with this program. If not, see . #include "kwinxrenderutils.h" #if HAVE_WAYLAND #include "wayland_backend.h" +#include "wayland_client/shm_pool.h" #include "wayland_client/surface.h" #endif diff --git a/wayland_backend.cpp b/wayland_backend.cpp index 73d6674aaf..9b8734fa3b 100644 --- a/wayland_backend.cpp +++ b/wayland_backend.cpp @@ -22,18 +22,19 @@ along with this program. If not, see . // KWin #include "cursor.h" #include "input.h" +#include "wayland_client/buffer.h" #include "wayland_client/connection_thread.h" #include "wayland_client/fullscreen_shell.h" #include "wayland_client/output.h" #include "wayland_client/registry.h" #include "wayland_client/shell.h" +#include "wayland_client/shm_pool.h" #include "wayland_client/surface.h" // Qt #include #include #include #include -#include #include // xcb #include @@ -41,9 +42,6 @@ along with this program. If not, see . // Wayland #include #include -// system -#include -#include namespace KWin { @@ -150,15 +148,6 @@ static void keyboardHandleModifiers(void *data, wl_keyboard *keyboard, uint32_t input()->processKeyboardModifiers(modsDepressed, modsLatched, modsLocked, group); } -static void bufferRelease(void *data, wl_buffer *wl_buffer) -{ - Buffer *buffer = reinterpret_cast(data); - if (buffer->buffer() != wl_buffer) { - return; - } - buffer->setReleased(true); -} - // handlers static const struct wl_pointer_listener s_pointerListener = { pointerHandleEnter, @@ -180,10 +169,6 @@ static const struct wl_seat_listener s_seatListener = { seatHandleCapabilities }; -static const struct wl_buffer_listener s_bufferListener = { - bufferRelease -}; - CursorData::CursorData() : m_valid(init()) { @@ -276,152 +261,6 @@ void X11CursorTracker::resetCursor() } } -Buffer::Buffer(wl_buffer* buffer, const QSize& size, int32_t stride, size_t offset) - : m_nativeBuffer(buffer) - , m_released(false) - , m_size(size) - , m_stride(stride) - , m_offset(offset) - , m_used(false) -{ - wl_buffer_add_listener(m_nativeBuffer, &s_bufferListener, this); -} - -Buffer::~Buffer() -{ - wl_buffer_destroy(m_nativeBuffer); -} - -void Buffer::copy(const void* src) -{ - memcpy(address(), src, m_size.height()*m_stride); -} - -uchar *Buffer::address() -{ - return (uchar*)WaylandBackend::self()->shmPool()->poolAddress() + m_offset; -} - -ShmPool::ShmPool(wl_shm *shm) - : m_shm(shm) - , m_pool(NULL) - , m_poolData(NULL) - , m_size(1024) - , m_tmpFile(new QTemporaryFile()) - , m_valid(createPool()) - , m_offset(0) -{ -} - -ShmPool::~ShmPool() -{ - qDeleteAll(m_buffers); - if (m_poolData) { - munmap(m_poolData, m_size); - } - if (m_pool) { - wl_shm_pool_destroy(m_pool); - } - if (m_shm) { - wl_shm_destroy(m_shm); - } - m_tmpFile->close(); -} - -bool ShmPool::createPool() -{ - if (!m_tmpFile->open()) { - qDebug() << "Could not open temporary file for Shm pool"; - return false; - } - if (ftruncate(m_tmpFile->handle(), m_size) < 0) { - qDebug() << "Could not set size for Shm pool file"; - return false; - } - m_poolData = mmap(NULL, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_tmpFile->handle(), 0); - m_pool = wl_shm_create_pool(m_shm, m_tmpFile->handle(), m_size); - - if (!m_poolData || !m_pool) { - qDebug() << "Creating Shm pool failed"; - return false; - } - return true; -} - -bool ShmPool::resizePool(int32_t newSize) -{ - if (ftruncate(m_tmpFile->handle(), newSize) < 0) { - qDebug() << "Could not set new size for Shm pool file"; - return false; - } - wl_shm_pool_resize(m_pool, newSize); - munmap(m_poolData, m_size); - m_poolData = mmap(NULL, newSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_tmpFile->handle(), 0); - m_size = newSize; - if (!m_poolData) { - qDebug() << "Resizing Shm pool failed"; - return false; - } - emit poolResized(); - return true; -} - -wl_buffer *ShmPool::createBuffer(const QImage& image) -{ - if (image.isNull() || !m_valid) { - return NULL; - } - Buffer *buffer = getBuffer(image.size(), image.bytesPerLine()); - if (!buffer) { - return NULL; - } - buffer->copy(image.bits()); - return buffer->buffer(); -} - -wl_buffer *ShmPool::createBuffer(const QSize &size, int32_t stride, const void *src) -{ - if (size.isNull() || !m_valid) { - return NULL; - } - Buffer *buffer = getBuffer(size, stride); - if (!buffer) { - return NULL; - } - buffer->copy(src); - return buffer->buffer(); -} - -Buffer *ShmPool::getBuffer(const QSize &size, int32_t stride) -{ - Q_FOREACH (Buffer *buffer, m_buffers) { - if (!buffer->isReleased() || buffer->isUsed()) { - continue; - } - if (buffer->size() != size || buffer->stride() != stride) { - continue; - } - buffer->setReleased(false); - return buffer; - } - const int32_t byteCount = size.height() * stride; - if (m_offset + byteCount > m_size) { - if (!resizePool(m_size + byteCount)) { - return NULL; - } - } - // we don't have a buffer which we could reuse - need to create a new one - wl_buffer *native = wl_shm_pool_create_buffer(m_pool, m_offset, size.width(), size.height(), - stride, WL_SHM_FORMAT_ARGB8888); - if (!native) { - return NULL; - } - Buffer *buffer = new Buffer(native, size, stride, m_offset); - m_offset += byteCount; - m_buffers.append(buffer); - return buffer; -} - WaylandSeat::WaylandSeat(wl_seat *seat, WaylandBackend *backend) : QObject(NULL) , m_seat(seat) diff --git a/wayland_backend.h b/wayland_backend.h index 0f5f7914f1..ba43cb066a 100644 --- a/wayland_backend.h +++ b/wayland_backend.h @@ -35,7 +35,6 @@ class QTemporaryFile; class QImage; struct wl_cursor_theme; struct wl_buffer; -struct wl_shm; struct wl_event_queue; namespace KWin @@ -87,57 +86,6 @@ private: uint32_t m_lastX11Cursor; }; -class Buffer -{ -public: - Buffer(wl_buffer *buffer, const QSize &size, int32_t stride, size_t offset); - ~Buffer(); - void copy(const void *src); - void setReleased(bool released); - void setUsed(bool used); - - wl_buffer *buffer() const; - const QSize &size() const; - int32_t stride() const; - bool isReleased() const; - bool isUsed() const; - uchar *address(); -private: - wl_buffer *m_nativeBuffer; - bool m_released; - QSize m_size; - int32_t m_stride; - size_t m_offset; - bool m_used; -}; - -class ShmPool : public QObject -{ - Q_OBJECT -public: - ShmPool(wl_shm *shm); - ~ShmPool(); - bool isValid() const; - wl_buffer *createBuffer(const QImage &image); - wl_buffer *createBuffer(const QSize &size, int32_t stride, const void *src); - void *poolAddress() const; - Buffer *getBuffer(const QSize &size, int32_t stride); - wl_shm *shm(); -Q_SIGNALS: - void poolResized(); -private: - bool createPool(); - bool resizePool(int32_t newSize); - wl_shm *m_shm; - wl_shm_pool *m_pool; - void *m_poolData; - int32_t m_size; - QScopedPointer m_tmpFile; - bool m_valid; - int m_offset; - QList m_buffers; -}; - class WaylandSeat : public QObject { Q_OBJECT @@ -243,24 +191,6 @@ wl_seat *WaylandSeat::seat() return m_seat; } -inline -bool ShmPool::isValid() const -{ - return m_valid; -} - -inline -void* ShmPool::poolAddress() const -{ - return m_poolData; -} - -inline -wl_shm *ShmPool::shm() -{ - return m_shm; -} - inline wl_display *WaylandBackend::display() { @@ -297,48 +227,6 @@ const QList< Output* >& WaylandBackend::outputs() const return m_outputs; } -inline -wl_buffer* Buffer::buffer() const -{ - return m_nativeBuffer; -} - -inline -const QSize& Buffer::size() const -{ - return m_size; -} - -inline -int32_t Buffer::stride() const -{ - return m_stride; -} - -inline -bool Buffer::isReleased() const -{ - return m_released; -} - -inline -void Buffer::setReleased(bool released) -{ - m_released = released; -} - -inline -bool Buffer::isUsed() const -{ - return m_used; -} - -inline -void Buffer::setUsed(bool used) -{ - m_used = used; -} - } // namespace Wayland } // namespace KWin diff --git a/wayland_client/buffer.cpp b/wayland_client/buffer.cpp new file mode 100644 index 0000000000..246d8c48dd --- /dev/null +++ b/wayland_client/buffer.cpp @@ -0,0 +1,69 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2013 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 "buffer.h" +#include "shm_pool.h" +// system +#include + +namespace KWin +{ +namespace Wayland +{ + +const struct wl_buffer_listener Buffer::s_listener = { + Buffer::releasedCallback +}; + +Buffer::Buffer(ShmPool *parent, wl_buffer *buffer, const QSize &size, int32_t stride, size_t offset) + : m_shm(parent) + , m_nativeBuffer(buffer) + , m_released(false) + , m_size(size) + , m_stride(stride) + , m_offset(offset) + , m_used(false) +{ + wl_buffer_add_listener(m_nativeBuffer, &s_listener, this); +} + +Buffer::~Buffer() +{ + wl_buffer_destroy(m_nativeBuffer); +} + +void Buffer::releasedCallback(void *data, wl_buffer *buffer) +{ + Buffer *b = reinterpret_cast(data); + Q_ASSERT(b->m_nativeBuffer == buffer); + b->setReleased(true); +} + +void Buffer::copy(const void *src) +{ + memcpy(address(), src, m_size.height()*m_stride); +} + +uchar *Buffer::address() +{ + return reinterpret_cast(m_shm->poolAddress()) + m_offset; +} + +} +} diff --git a/wayland_client/buffer.h b/wayland_client/buffer.h new file mode 100644 index 0000000000..42b49935ad --- /dev/null +++ b/wayland_client/buffer.h @@ -0,0 +1,116 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2013 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_WAYLAND_BUFFER_H +#define KWIN_WAYLAND_BUFFER_H + +#include + +#include + +namespace KWin +{ +namespace Wayland +{ + +class ShmPool; + +class Buffer +{ +public: + ~Buffer(); + void copy(const void *src); + void setReleased(bool released); + void setUsed(bool used); + + wl_buffer *buffer() const; + const QSize &size() const; + int32_t stride() const; + bool isReleased() const; + bool isUsed() const; + uchar *address(); + + operator wl_buffer*() { + return m_nativeBuffer; + } + operator wl_buffer*() const { + return m_nativeBuffer; + } + + static void releasedCallback(void *data, wl_buffer *wl_buffer); + +private: + friend class ShmPool; + explicit Buffer(ShmPool *parent, wl_buffer *buffer, const QSize &size, int32_t stride, size_t offset); + static const struct wl_buffer_listener s_listener; + ShmPool *m_shm; + wl_buffer *m_nativeBuffer; + bool m_released; + QSize m_size; + int32_t m_stride; + size_t m_offset; + bool m_used; +}; + +inline +wl_buffer *Buffer::buffer() const +{ + return m_nativeBuffer; +} + +inline +const QSize &Buffer::size() const +{ + return m_size; +} + +inline +int32_t Buffer::stride() const +{ + return m_stride; +} + +inline +bool Buffer::isReleased() const +{ + return m_released; +} + +inline +void Buffer::setReleased(bool released) +{ + m_released = released; +} + +inline +bool Buffer::isUsed() const +{ + return m_used; +} + +inline +void Buffer::setUsed(bool used) +{ + m_used = used; +} + +} +} + +#endif diff --git a/wayland_client/shm_pool.cpp b/wayland_client/shm_pool.cpp new file mode 100644 index 0000000000..a08f7b7b29 --- /dev/null +++ b/wayland_client/shm_pool.cpp @@ -0,0 +1,156 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2013 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 "shm_pool.h" +#include "buffer.h" +// Qt +#include +#include +#include +// system +#include +#include + +namespace KWin +{ +namespace Wayland +{ + +ShmPool::ShmPool(wl_shm *shm) + : m_shm(shm) + , m_pool(nullptr) + , m_poolData(nullptr) + , m_size(1024) + , m_tmpFile(new QTemporaryFile()) + , m_valid(createPool()) + , m_offset(0) +{ +} + +ShmPool::~ShmPool() +{ + qDeleteAll(m_buffers); + if (m_poolData) { + munmap(m_poolData, m_size); + } + if (m_pool) { + wl_shm_pool_destroy(m_pool); + } + if (m_shm) { + wl_shm_destroy(m_shm); + } + m_tmpFile->close(); +} + +bool ShmPool::createPool() +{ + if (!m_tmpFile->open()) { + qDebug() << "Could not open temporary file for Shm pool"; + return false; + } + if (ftruncate(m_tmpFile->handle(), m_size) < 0) { + qDebug() << "Could not set size for Shm pool file"; + return false; + } + m_poolData = mmap(NULL, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_tmpFile->handle(), 0); + m_pool = wl_shm_create_pool(m_shm, m_tmpFile->handle(), m_size); + + if (!m_poolData || !m_pool) { + qDebug() << "Creating Shm pool failed"; + return false; + } + return true; +} + +bool ShmPool::resizePool(int32_t newSize) +{ + if (ftruncate(m_tmpFile->handle(), newSize) < 0) { + qDebug() << "Could not set new size for Shm pool file"; + return false; + } + wl_shm_pool_resize(m_pool, newSize); + munmap(m_poolData, m_size); + m_poolData = mmap(NULL, newSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_tmpFile->handle(), 0); + m_size = newSize; + if (!m_poolData) { + qDebug() << "Resizing Shm pool failed"; + return false; + } + emit poolResized(); + return true; +} + +wl_buffer *ShmPool::createBuffer(const QImage& image) +{ + if (image.isNull() || !m_valid) { + return NULL; + } + Buffer *buffer = getBuffer(image.size(), image.bytesPerLine()); + if (!buffer) { + return NULL; + } + buffer->copy(image.bits()); + return buffer->buffer(); +} + +wl_buffer *ShmPool::createBuffer(const QSize &size, int32_t stride, const void *src) +{ + if (size.isNull() || !m_valid) { + return NULL; + } + Buffer *buffer = getBuffer(size, stride); + if (!buffer) { + return NULL; + } + buffer->copy(src); + return buffer->buffer(); +} + +Buffer *ShmPool::getBuffer(const QSize &size, int32_t stride) +{ + Q_FOREACH (Buffer *buffer, m_buffers) { + if (!buffer->isReleased() || buffer->isUsed()) { + continue; + } + if (buffer->size() != size || buffer->stride() != stride) { + continue; + } + buffer->setReleased(false); + return buffer; + } + const int32_t byteCount = size.height() * stride; + if (m_offset + byteCount > m_size) { + if (!resizePool(m_size + byteCount)) { + return NULL; + } + } + // we don't have a buffer which we could reuse - need to create a new one + wl_buffer *native = wl_shm_pool_create_buffer(m_pool, m_offset, size.width(), size.height(), + stride, WL_SHM_FORMAT_ARGB8888); + if (!native) { + return NULL; + } + Buffer *buffer = new Buffer(this, native, size, stride, m_offset); + m_offset += byteCount; + m_buffers.append(buffer); + return buffer; +} + +} +} diff --git a/wayland_client/shm_pool.h b/wayland_client/shm_pool.h new file mode 100644 index 0000000000..9b1c8ff314 --- /dev/null +++ b/wayland_client/shm_pool.h @@ -0,0 +1,87 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2013 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_WAYLAND_SHM_POOL_H +#define KWIN_WAYLAND_SHM_POOL_H + +#include + +class QImage; +class QSize; +class QTemporaryFile; + +struct wl_shm; +struct wl_buffer; +struct wl_shm_pool; + +namespace KWin +{ +namespace Wayland +{ +class Buffer; + +class ShmPool : public QObject +{ + Q_OBJECT +public: + ShmPool(wl_shm *shm); + ~ShmPool(); + bool isValid() const; + wl_buffer *createBuffer(const QImage &image); + wl_buffer *createBuffer(const QSize &size, int32_t stride, const void *src); + void *poolAddress() const; + Buffer *getBuffer(const QSize &size, int32_t stride); + wl_shm *shm(); +Q_SIGNALS: + void poolResized(); +private: + bool createPool(); + bool resizePool(int32_t newSize); + wl_shm *m_shm; + wl_shm_pool *m_pool; + void *m_poolData; + int32_t m_size; + QScopedPointer m_tmpFile; + bool m_valid; + int m_offset; + QList m_buffers; +}; + +inline +bool ShmPool::isValid() const +{ + return m_valid; +} + +inline +void* ShmPool::poolAddress() const +{ + return m_poolData; +} + +inline +wl_shm *ShmPool::shm() +{ + return m_shm; +} + +} +} + +#endif