[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.
master
Martin Gräßlin 10 years ago
parent 07c972b6d4
commit 19d90e4e0e

@ -81,6 +81,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "thumbnailitem.h"
#include "workspace.h"
#if HAVE_WAYLAND
#include <KWayland/Server/buffer_interface.h>
#include <KWayland/Server/surface_interface.h>
#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 = xcb_generate_id(connection());
xcb_void_cookie_t namePixmapCookie = xcb_composite_name_window_pixmap_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 != XCB_PIXMAP_NONE;
}
#if HAVE_WAYLAND
void WindowPixmap::updateBuffer()
{
if (auto s = toplevel()->surface()) {
if (auto b = s->buffer()) {
m_buffer = b;
}
}
}
#endif
//****************************************
// Scene::EffectFrame
//****************************************

@ -27,6 +27,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QElapsedTimer>
#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<KWayland::Server::BufferInterface> buffer() const;
#endif
/**
* @brief Whether this WindowPixmap is considered as discarded. This means 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 Buffer 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<KWayland::Server::BufferInterface> 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<KWayland::Server::BufferInterface> WindowPixmap::buffer() const
{
return m_pixmap != XCB_PIXMAP_NONE;
return m_buffer;
}
#endif
template <typename T>
inline

@ -30,6 +30,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Client/buffer.h>
#include <KWayland/Client/shm_pool.h>
#include <KWayland/Client/surface.h>
#include <KWayland/Server/buffer_interface.h>
#include <KWayland/Server/surface_interface.h>
#endif
#include "workspace.h"
#include "xcbutils.h"
@ -461,7 +463,7 @@ Decoration::Renderer *SceneQPainter::createDecorationRenderer(Decoration::Decora
//****************************************
QPainterWindowPixmap::QPainterWindowPixmap(Scene::Window *window)
: WindowPixmap(window)
, m_shm(new Xcb::Shm)
, m_shm(kwinApp()->shouldUseWaylandForCompositing() ? nullptr : new Xcb::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 = buffer()->data().copy();
return;
}
#endif
m_image = QImage((uchar*)m_shm->buffer(), size().width(), size().height(), QImage::Format_ARGB32_Premultiplied);
}
bool QPainterWindowPixmap::update(const QRegion &damage)
{
Q_UNUSED(damage)
#if HAVE_WAYLAND
if (kwinApp()->shouldUseWaylandForCompositing()) {
const auto oldBuffer = buffer();
updateBuffer();
const auto &b = buffer();
if (b == oldBuffer || b.isNull()) {
return false;
}
QPainter p(&m_image);
const QImage &data = 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;
}

Loading…
Cancel
Save