[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.
icc-effect-5.14.5
Martin Gräßlin 2014-08-20 15:29:38 +02:00
parent ce8c4240f7
commit 08ab2c424e
9 changed files with 435 additions and 275 deletions

View File

@ -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
)

View File

@ -28,6 +28,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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"

View File

@ -37,6 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "kwinxrenderutils.h"
#if HAVE_WAYLAND
#include "wayland_backend.h"
#include "wayland_client/shm_pool.h"
#include "wayland_client/surface.h"
#endif

View File

@ -22,18 +22,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// 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 <QAbstractEventDispatcher>
#include <QCoreApplication>
#include <QDebug>
#include <QImage>
#include <QTemporaryFile>
#include <QThread>
// xcb
#include <xcb/xtest.h>
@ -41,9 +42,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Wayland
#include <wayland-client-protocol.h>
#include <wayland-cursor.h>
// system
#include <unistd.h>
#include <sys/mman.h>
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<Buffer*>(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)

View File

@ -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<QTemporaryFile> m_tmpFile;
bool m_valid;
int m_offset;
QList<Buffer*> 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

69
wayland_client/buffer.cpp Normal file
View File

@ -0,0 +1,69 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "buffer.h"
#include "shm_pool.h"
// system
#include <string.h>
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<Buffer*>(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<uchar*>(m_shm->poolAddress()) + m_offset;
}
}
}

116
wayland_client/buffer.h Normal file
View File

@ -0,0 +1,116 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_WAYLAND_BUFFER_H
#define KWIN_WAYLAND_BUFFER_H
#include <QSize>
#include <wayland-client-protocol.h>
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

156
wayland_client/shm_pool.cpp Normal file
View File

@ -0,0 +1,156 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "shm_pool.h"
#include "buffer.h"
// Qt
#include <QDebug>
#include <QImage>
#include <QTemporaryFile>
// system
#include <unistd.h>
#include <sys/mman.h>
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;
}
}
}

87
wayland_client/shm_pool.h Normal file
View File

@ -0,0 +1,87 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_WAYLAND_SHM_POOL_H
#define KWIN_WAYLAND_SHM_POOL_H
#include <QObject>
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<QTemporaryFile> m_tmpFile;
bool m_valid;
int m_offset;
QList<Buffer*> 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