diff --git a/autotests/wayland_client/CMakeLists.txt b/autotests/wayland_client/CMakeLists.txt
index 6b50aa2494..d46327e4db 100644
--- a/autotests/wayland_client/CMakeLists.txt
+++ b/autotests/wayland_client/CMakeLists.txt
@@ -5,6 +5,7 @@ set_source_files_properties(${CMAKE_BINARY_DIR}/wayland_protocols/wayland-client
########################################################
set( testWaylandConnectionThread_SRCS
test_wayland_connection_thread.cpp
+ ${KWIN_SOURCE_DIR}/wayland_server/buffer_interface.cpp
${KWIN_SOURCE_DIR}/wayland_client/connection_thread.cpp
${KWIN_SOURCE_DIR}/wayland_server/compositor_interface.cpp
${KWIN_SOURCE_DIR}/wayland_server/display.cpp
@@ -59,6 +60,7 @@ set( testWaylandOutput_SRCS
${KWIN_SOURCE_DIR}/wayland_client/fullscreen_shell.cpp
${KWIN_SOURCE_DIR}/wayland_client/output.cpp
${CMAKE_BINARY_DIR}/wayland_protocols/wayland-client-fullscreen-shell.c
+ ${KWIN_SOURCE_DIR}/wayland_server/buffer_interface.cpp
${KWIN_SOURCE_DIR}/wayland_server/compositor_interface.cpp
${KWIN_SOURCE_DIR}/wayland_server/display.cpp
${KWIN_SOURCE_DIR}/wayland_server/output_interface.cpp
@@ -94,12 +96,15 @@ ecm_mark_as_test(testWaylandShell)
########################################################
set( testWaylandSurface_SRCS
test_wayland_surface.cpp
+ ${KWIN_SOURCE_DIR}/wayland_client/buffer.cpp
${KWIN_SOURCE_DIR}/wayland_client/compositor.cpp
${KWIN_SOURCE_DIR}/wayland_client/connection_thread.cpp
${KWIN_SOURCE_DIR}/wayland_client/registry.cpp
${KWIN_SOURCE_DIR}/wayland_client/fullscreen_shell.cpp
+ ${KWIN_SOURCE_DIR}/wayland_client/shm_pool.cpp
${KWIN_SOURCE_DIR}/wayland_client/surface.cpp
${CMAKE_BINARY_DIR}/wayland_protocols/wayland-client-fullscreen-shell.c
+ ${KWIN_SOURCE_DIR}/wayland_server/buffer_interface.cpp
${KWIN_SOURCE_DIR}/wayland_server/compositor_interface.cpp
${KWIN_SOURCE_DIR}/wayland_server/display.cpp
${KWIN_SOURCE_DIR}/wayland_server/output_interface.cpp
diff --git a/autotests/wayland_client/test_wayland_surface.cpp b/autotests/wayland_client/test_wayland_surface.cpp
index 1b480895f4..bb4a7291a3 100644
--- a/autotests/wayland_client/test_wayland_surface.cpp
+++ b/autotests/wayland_client/test_wayland_surface.cpp
@@ -19,11 +19,14 @@ along with this program. If not, see .
*********************************************************************/
// Qt
#include
+#include
// KWin
#include "../../wayland_client/compositor.h"
#include "../../wayland_client/connection_thread.h"
#include "../../wayland_client/surface.h"
#include "../../wayland_client/registry.h"
+#include "../../wayland_client/shm_pool.h"
+#include "../../wayland_server/buffer_interface.h"
#include "../../wayland_server/compositor_interface.h"
#include "../../wayland_server/display.h"
#include "../../wayland_server/surface_interface.h"
@@ -42,6 +45,7 @@ private Q_SLOTS:
void testStaticAccessor();
void testDamage();
void testFrameCallback();
+ void testAttachBuffer();
private:
KWin::WaylandServer::Display *m_display;
@@ -230,5 +234,69 @@ void TestWaylandSurface::testFrameCallback()
QVERIFY(!frameRenderedSpy.isEmpty());
}
+void TestWaylandSurface::testAttachBuffer()
+{
+ // here we need a shm pool
+ m_display->createShm();
+
+ KWin::Wayland::Registry registry;
+ QSignalSpy shmSpy(®istry, SIGNAL(shmAnnounced(quint32,quint32)));
+ registry.create(m_connection->display());
+ QVERIFY(registry.isValid());
+ registry.setup();
+ QVERIFY(shmSpy.wait());
+
+ KWin::Wayland::ShmPool pool;
+ pool.setup(registry.bindShm(shmSpy.first().first().value(), shmSpy.first().last().value()));
+ QVERIFY(pool.isValid());
+
+ // create the surface
+ QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWin::WaylandServer::SurfaceInterface*)));
+ QVERIFY(serverSurfaceCreated.isValid());
+ KWin::Wayland::Surface *s = m_compositor->createSurface();
+ QVERIFY(serverSurfaceCreated.wait());
+ KWin::WaylandServer::SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value();
+ QVERIFY(serverSurface);
+
+ // create two images
+ // TODO: test RGB32
+ QImage black(24, 24, QImage::Format_ARGB32);
+ black.fill(Qt::black);
+ QImage red(24, 24, QImage::Format_ARGB32);
+ red.fill(QColor(255, 0, 0, 128));
+
+ wl_buffer *blackBuffer = pool.createBuffer(black);
+ wl_buffer *redBuffer = pool.createBuffer(red);
+
+ s->attachBuffer(redBuffer);
+ s->attachBuffer(blackBuffer);
+ s->damage(QRect(0, 0, 24, 24));
+ s->commit(KWin::Wayland::Surface::CommitFlag::None);
+ QSignalSpy damageSpy(serverSurface, SIGNAL(damaged(QRegion)));
+ QVERIFY(damageSpy.isValid());
+ QVERIFY(damageSpy.wait());
+
+ // now the ServerSurface should have the black image attached as a buffer
+ KWin::WaylandServer::BufferInterface *buffer = serverSurface->buffer();
+ buffer->ref();
+ QVERIFY(buffer->shmBuffer());
+ QCOMPARE(buffer->data(), black);
+
+ // render another frame
+ s->attachBuffer(redBuffer);
+ s->damage(QRect(0, 0, 24, 24));
+ s->commit(KWin::Wayland::Surface::CommitFlag::None);
+ damageSpy.clear();
+ QVERIFY(damageSpy.wait());
+ KWin::WaylandServer::BufferInterface *buffer2 = serverSurface->buffer();
+ buffer2->ref();
+ QVERIFY(buffer2->shmBuffer());
+ QCOMPARE(buffer2->data(), red);
+ buffer2->unref();
+
+ // TODO: add signal test on release
+ buffer->unref();
+}
+
QTEST_MAIN(TestWaylandSurface)
#include "test_wayland_surface.moc"
diff --git a/autotests/wayland_server/CMakeLists.txt b/autotests/wayland_server/CMakeLists.txt
index bff5b51035..4589b27449 100644
--- a/autotests/wayland_server/CMakeLists.txt
+++ b/autotests/wayland_server/CMakeLists.txt
@@ -3,6 +3,7 @@
########################################################
set( testWaylandServerDisplay_SRCS
test_display.cpp
+ ${KWIN_SOURCE_DIR}/wayland_server/buffer_interface.cpp
${KWIN_SOURCE_DIR}/wayland_server/compositor_interface.cpp
${KWIN_SOURCE_DIR}/wayland_server/display.cpp
${KWIN_SOURCE_DIR}/wayland_server/output_interface.cpp
diff --git a/wayland_server/buffer_interface.cpp b/wayland_server/buffer_interface.cpp
new file mode 100644
index 0000000000..fb8e7501e2
--- /dev/null
+++ b/wayland_server/buffer_interface.cpp
@@ -0,0 +1,107 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2014 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_interface.h"
+#include "surface_interface.h"
+
+namespace KWin
+{
+namespace WaylandServer
+{
+
+BufferInterface::BufferInterface(wl_resource *resource, SurfaceInterface *parent)
+ : QObject(parent)
+ , m_buffer(resource)
+ , m_shmBuffer(wl_shm_buffer_get(m_buffer))
+ , m_surface(parent)
+ , m_refCount(0)
+{
+}
+
+BufferInterface::~BufferInterface()
+{
+ Q_ASSERT(m_refCount == 0);
+ releaseImage();
+}
+
+void BufferInterface::releaseImage()
+{
+ if (m_image.isNull()) {
+ return;
+ }
+ // first destroy it
+ m_image = QImage();
+ wl_shm_buffer_end_access(m_shmBuffer);
+}
+
+void BufferInterface::ref()
+{
+ m_refCount++;
+}
+
+void BufferInterface::unref()
+{
+ Q_ASSERT(m_refCount > 0);
+ m_refCount--;
+ if (m_refCount == 0) {
+ releaseImage();
+ wl_buffer_send_release(m_buffer);
+ deleteLater();
+ }
+}
+
+QImage::Format BufferInterface::format() const
+{
+ switch (wl_shm_buffer_get_format(m_shmBuffer)) {
+ case WL_SHM_FORMAT_ARGB8888:
+ return QImage::Format_ARGB32;
+ case WL_SHM_FORMAT_XRGB8888:
+ return QImage::Format_RGB32;
+ default:
+ return QImage::Format_Invalid;
+ }
+}
+
+QImage BufferInterface::data()
+{
+ if (m_image.isNull()) {
+ createImage();
+ }
+ return m_image;
+}
+
+void BufferInterface::createImage()
+{
+ if (!m_shmBuffer) {
+ return;
+ }
+ const QImage::Format imageFormat = format();
+ if (imageFormat == QImage::Format_Invalid) {
+ return;
+ }
+ wl_shm_buffer_begin_access(m_shmBuffer);
+ m_image = QImage((const uchar*)wl_shm_buffer_get_data(m_shmBuffer),
+ wl_shm_buffer_get_width(m_shmBuffer),
+ wl_shm_buffer_get_height(m_shmBuffer),
+ wl_shm_buffer_get_stride(m_shmBuffer),
+ imageFormat);
+}
+
+}
+}
diff --git a/wayland_server/buffer_interface.h b/wayland_server/buffer_interface.h
new file mode 100644
index 0000000000..41531c4c93
--- /dev/null
+++ b/wayland_server/buffer_interface.h
@@ -0,0 +1,72 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2014 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_SERVER_BUFFER_INTERFACE_H
+#define KWIN_WAYLAND_SERVER_BUFFER_INTERFACE_H
+
+#include
+#include
+
+struct wl_resource;
+struct wl_shm_buffer;
+
+namespace KWin
+{
+namespace WaylandServer
+{
+class SurfaceInterface;
+
+
+class BufferInterface : public QObject
+{
+ Q_OBJECT
+public:
+ virtual ~BufferInterface();
+ void ref();
+ void unref();
+ bool isReferenced() const {
+ return m_refCount > 0;
+ }
+
+ SurfaceInterface *surface() const {
+ return m_surface;
+ }
+ wl_shm_buffer *shmBuffer() {
+ return m_shmBuffer;
+ }
+
+ QImage data();
+
+private:
+ friend class SurfaceInterface;
+ explicit BufferInterface(wl_resource *resource, SurfaceInterface *parent);
+ QImage::Format format() const;
+ void createImage();
+ void releaseImage();
+ wl_resource *m_buffer;
+ wl_shm_buffer *m_shmBuffer;
+ SurfaceInterface *m_surface;
+ int m_refCount;
+ QImage m_image;
+};
+
+}
+}
+
+#endif
diff --git a/wayland_server/display.cpp b/wayland_server/display.cpp
index 06210ee33c..6778128704 100644
--- a/wayland_server/display.cpp
+++ b/wayland_server/display.cpp
@@ -131,6 +131,12 @@ CompositorInterface *Display::createCompositor(QObject *parent)
return compositor;
}
+void Display::createShm()
+{
+ Q_ASSERT(m_running);
+ wl_display_init_shm(m_display);
+}
+
void Display::removeOutput(OutputInterface *output)
{
m_outputs.removeAll(output);
diff --git a/wayland_server/display.h b/wayland_server/display.h
index d18d9c09ad..dc9633c7d0 100644
--- a/wayland_server/display.h
+++ b/wayland_server/display.h
@@ -66,6 +66,7 @@ public:
}
CompositorInterface *createCompositor(QObject *parent = nullptr);
+ void createShm();
Q_SIGNALS:
void socketNameChanged(const QString&);
diff --git a/wayland_server/surface_interface.cpp b/wayland_server/surface_interface.cpp
index ea0343c95e..8ce1d2a93f 100644
--- a/wayland_server/surface_interface.cpp
+++ b/wayland_server/surface_interface.cpp
@@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*********************************************************************/
#include "surface_interface.h"
+#include "buffer_interface.h"
#include "compositor_interface.h"
namespace KWin
@@ -87,6 +88,9 @@ void SurfaceInterface::destroy()
for (wl_resource *c : m_pending.callbacks) {
wl_resource_destroy(c);
}
+ if (m_current.buffer) {
+ m_current.buffer->unref();
+ }
if (m_surface) {
wl_resource_destroy(m_surface);
m_surface = nullptr;
@@ -102,6 +106,12 @@ void SurfaceInterface::commit()
const bool inputRegionChanged = m_current.input != m_pending.input;
const bool scaleFactorChanged = m_current.scale != m_pending.scale;
const bool transformFactorChanged = m_current.transform != m_pending.transform;
+ if (m_current.buffer) {
+ m_current.buffer->unref();
+ }
+ if (m_pending.buffer) {
+ m_pending.buffer->ref();
+ }
// copy values
m_current = m_pending;
m_pending = State{};
@@ -149,6 +159,15 @@ void SurfaceInterface::addFrameCallback(uint32_t callback)
m_pending.callbacks << r;
}
+void SurfaceInterface::attachBuffer(wl_resource *buffer, const QPoint &offset)
+{
+ m_pending.offset = offset;
+ if (m_pending.buffer) {
+ delete m_pending.buffer;
+ }
+ m_pending.buffer = new BufferInterface(buffer, this);
+}
+
void SurfaceInterface::destroyFrameCallback(wl_resource *r)
{
SurfaceInterface *s = SurfaceInterface::cast(r);
@@ -165,11 +184,7 @@ void SurfaceInterface::destroyCallback(wl_client *client, wl_resource *resource)
void SurfaceInterface::attachCallback(wl_client *client, wl_resource *resource, wl_resource *buffer, int32_t sx, int32_t sy)
{
Q_UNUSED(client)
- Q_UNUSED(resource)
- Q_UNUSED(buffer)
- Q_UNUSED(sx)
- Q_UNUSED(sy)
- // TODO: implement me
+ SurfaceInterface::cast(resource)->attachBuffer(buffer, QPoint(sx, sy));
}
void SurfaceInterface::damageCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
diff --git a/wayland_server/surface_interface.h b/wayland_server/surface_interface.h
index 659105e4e7..75e5cdc82c 100644
--- a/wayland_server/surface_interface.h
+++ b/wayland_server/surface_interface.h
@@ -31,6 +31,7 @@ namespace KWin
{
namespace WaylandServer
{
+class BufferInterface;
class CompositorInterface;
class SurfaceInterface : public QObject
@@ -70,6 +71,12 @@ public:
OutputInterface::Transform transform() const {
return m_current.transform;
}
+ BufferInterface *buffer() {
+ return m_current.buffer;
+ }
+ QPoint offset() const {
+ return m_current.offset;
+ }
Q_SIGNALS:
void damaged(const QRegion&);
@@ -86,6 +93,8 @@ private:
qint32 scale = 1;
OutputInterface::Transform transform = OutputInterface::Transform::Normal;
QList callbacks = QList();
+ QPoint offset = QPoint();
+ BufferInterface *buffer = nullptr;
};
friend class CompositorInterface;
explicit SurfaceInterface(CompositorInterface *parent);
@@ -114,6 +123,7 @@ private:
void setScale(qint32 scale);
void setTransform(OutputInterface::Transform transform);
void addFrameCallback(uint32_t callback);
+ void attachBuffer(wl_resource *buffer, const QPoint &offset);
CompositorInterface *m_compositor;
wl_resource *m_surface;
wl_client *m_client;