From kde-commits Tue Mar 17 09:33:04 2015 From: =?utf-8?q?Martin_Gr=C3=A4=C3=9Flin?= Date: Tue, 17 Mar 2015 09:33:04 +0000 To: kde-commits Subject: [kwin] /: [scene] Add basic support for Wayland Buffer in WindowPixmap Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=142658480223774 Git commit 19d90e4e0e6611b6e474d0da4d6c6faa922362e0 by Martin Gr=C3=A4=C3= =9Flin. Committed on 09/02/2015 at 17:56. Pushed by graesslin into branch 'master'. [scene] Add basic support for Wayland Buffer in WindowPixmap The concept of Buffers do not match WindowPixmap perfectly. With X11 we had a pixmap as long as the size was the sime, then it got discarded. With Wayland we get a new Buffer whenever the window gets damaged. Furthermore the Buffer might get destroyed any time (especially if the client disconnects) or the data becomes invalid (it's a shm section after all). This adds some constraints on how the Buffer can be used. It's suggested that the implementing sub-classes do a deep copy of the Buffer's data when accessing it. For OpenGL that's rather obvious, for QPainter it needs a dedicated QImage::copy. WindowPixmap holds a pointer to the currently used Buffer, but doesn't guarantee that it stays valid. Every time the window gets damaged, the pointer needs to be updated. The QPainter based scene is the first to implement support for Buffers: on creation a deep copy is performed, on damage the changed parts are painted into the deep copy. M +37 -1 scene.cpp M +31 -2 scene.h M +32 -3 scene_qpainter.cpp http://commits.kde.org/kwin/19d90e4e0e6611b6e474d0da4d6c6faa922362e0 diff --git a/scene.cpp b/scene.cpp index 94eeba1..37e1c3a 100644 --- a/scene.cpp +++ b/scene.cpp @@ -81,6 +81,11 @@ along with this program. If not, see . #include "thumbnailitem.h" #include "workspace.h" = +#if HAVE_WAYLAND +#include +#include +#endif + namespace KWin { = @@ -928,7 +933,7 @@ WindowPixmap::WindowPixmap(Scene::Window *window) = WindowPixmap::~WindowPixmap() { - if (isValid()) { + if (isValid() && !kwinApp()->shouldUseWaylandForCompositing()) { xcb_free_pixmap(connection(), m_pixmap); } } @@ -938,6 +943,16 @@ void WindowPixmap::create() if (isValid() || toplevel()->isDeleted()) { return; } +#if HAVE_WAYLAND + if (kwinApp()->shouldUseWaylandForCompositing()) { + // use Buffer + updateBuffer(); + if (m_buffer) { + m_window->unreferencePreviousPixmap(); + } + return; + } +#endif XServerGrabber grabber; xcb_pixmap_t pix =3D xcb_generate_id(connection()); xcb_void_cookie_t namePixmapCookie =3D xcb_composite_name_window_pixma= p_checked(connection(), toplevel()->frameId(), pix); @@ -967,6 +982,27 @@ void WindowPixmap::create() m_window->unreferencePreviousPixmap(); } = +bool WindowPixmap::isValid() const +{ +#if HAVE_WAYLAND + if (kwinApp()->shouldUseWaylandForCompositing()) { + return !m_buffer.isNull(); + } +#endif + return m_pixmap !=3D XCB_PIXMAP_NONE; +} + +#if HAVE_WAYLAND +void WindowPixmap::updateBuffer() +{ + if (auto s =3D toplevel()->surface()) { + if (auto b =3D s->buffer()) { + m_buffer =3D b; + } + } +} +#endif + //**************************************** // Scene::EffectFrame //**************************************** diff --git a/scene.h b/scene.h index f6f5322..4d23660 100644 --- a/scene.h +++ b/scene.h @@ -27,6 +27,16 @@ along with this program. If not, see . = #include = +#if HAVE_WAYLAND +namespace KWayland +{ +namespace Server +{ +class BufferInterface; +} +} +#endif + namespace KWin { = @@ -345,6 +355,12 @@ public: * @return The native X11 pixmap handle */ xcb_pixmap_t pixmap() const; +#if HAVE_WAYLAND + /** + * @return The Wayland BufferInterface for this WindowPixmap. + **/ + QPointer buffer() const; +#endif /** * @brief Whether this WindowPixmap is considered as discarded. This m= eans the window has changed in a way that a new * WindowPixmap should have been created already. @@ -382,12 +398,23 @@ protected: * @return The Window this WindowPixmap belongs to */ Scene::Window *window(); + +#if HAVE_WAYLAND + /** + * Should be called by the implementing subclasses when the Wayland Bu= ffer changed and needs + * updating. + **/ + void updateBuffer(); +#endif private: Scene::Window *m_window; xcb_pixmap_t m_pixmap; QSize m_pixmapSize; bool m_discarded; QRect m_contentsRect; +#if HAVE_WAYLAND + QPointer m_buffer; +#endif }; = class Scene::EffectFrame @@ -491,11 +518,13 @@ Shadow* Scene::Window::shadow() return m_shadow; } = +#if HAVE_WAYLAND inline -bool WindowPixmap::isValid() const +QPointer WindowPixmap::buffer() const { - return m_pixmap !=3D XCB_PIXMAP_NONE; + return m_buffer; } +#endif = template inline diff --git a/scene_qpainter.cpp b/scene_qpainter.cpp index 56e7cbb..1f21755 100644 --- a/scene_qpainter.cpp +++ b/scene_qpainter.cpp @@ -30,6 +30,8 @@ along with this program. If not, see . #include #include #include +#include +#include #endif #include "workspace.h" #include "xcbutils.h" @@ -461,7 +463,7 @@ Decoration::Renderer *SceneQPainter::createDecorationRe= nderer(Decoration::Decora //**************************************** QPainterWindowPixmap::QPainterWindowPixmap(Scene::Window *window) : WindowPixmap(window) - , m_shm(new Xcb::Shm) + , m_shm(kwinApp()->shouldUseWaylandForCompositing() ? nullptr : new Xc= b::Shm) { } = @@ -471,19 +473,46 @@ QPainterWindowPixmap::~QPainterWindowPixmap() = void QPainterWindowPixmap::create() { - if (isValid() || !m_shm->isValid()) { + if (isValid()) { + return; + } + if (!kwinApp()->shouldUseWaylandForCompositing() && !m_shm->isValid())= { return; } KWin::WindowPixmap::create(); if (!isValid()) { return; } +#if HAVE_WAYLAND + if (kwinApp()->shouldUseWaylandForCompositing()) { + // performing deep copy, this could probably be improved + m_image =3D buffer()->data().copy(); + return; + } +#endif m_image =3D QImage((uchar*)m_shm->buffer(), size().width(), size().hei= ght(), QImage::Format_ARGB32_Premultiplied); } = bool QPainterWindowPixmap::update(const QRegion &damage) { - Q_UNUSED(damage) +#if HAVE_WAYLAND + if (kwinApp()->shouldUseWaylandForCompositing()) { + const auto oldBuffer =3D buffer(); + updateBuffer(); + const auto &b =3D buffer(); + if (b =3D=3D oldBuffer || b.isNull()) { + return false; + } + QPainter p(&m_image); + const QImage &data =3D b->data(); + p.setCompositionMode(QPainter::CompositionMode_Source); + for (const QRect &rect : damage.rects()) { + p.drawImage(rect, data, rect); + } + return true; + } +#endif + if (!m_shm->isValid()) { return false; }