1/********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>.
19*********************************************************************/
20#ifndef KWIN_EGL_WAYLAND_BACKEND_H
21#define KWIN_EGL_WAYLAND_BACKEND_H
22#include "scene_opengl.h"
23// wayland
24#include <wayland-client.h>
25#include <wayland-egl.h>
26// xcb
27#include <xcb/shm.h>
28
29class KTemporaryFile;
30struct wl_buffer;
31struct wl_shm;
32
33namespace KWin
34{
35
36namespace Wayland
37{
38class ShmPool;
39class WaylandBackend;
40
41class CursorData
42{
43public:
44 CursorData(ShmPool *pool);
45 ~CursorData();
46 bool isValid() const;
47 const QPoint &hotSpot() const;
48 const QSize &size() const;
49 wl_buffer *cursor() const;
50private:
51 bool init(ShmPool *pool);
52 wl_buffer *m_cursor;
53 QPoint m_hotSpot;
54 QSize m_size;
55 bool m_valid;
56};
57
58class X11CursorTracker : public QObject
59{
60 Q_OBJECT
61public:
62 explicit X11CursorTracker(wl_pointer *pointer, WaylandBackend *backend, QObject* parent = 0);
63 virtual ~X11CursorTracker();
64 void setEnteredSerial(uint32_t serial);
65 void resetCursor();
66private Q_SLOTS:
67 void cursorChanged(uint32_t serial);
68private:
69 void installCursor(const CursorData &cursor);
70 wl_pointer *m_pointer;
71 QHash<uint32_t, CursorData> m_cursors;
72 WaylandBackend *m_backend;
73 wl_surface *m_cursor;
74 uint32_t m_enteredSerial;
75 uint32_t m_installedCursor;
76 uint32_t m_lastX11Cursor;
77};
78
79class ShmPool
80{
81public:
82 ShmPool(wl_shm *shm);
83 ~ShmPool();
84 bool isValid() const;
85 wl_buffer *createBuffer(const QImage &image);
86private:
87 bool createPool();
88 wl_shm *m_shm;
89 wl_shm_pool *m_pool;
90 void *m_poolData;
91 size_t m_size;
92 QScopedPointer<KTemporaryFile> m_tmpFile;
93 bool m_valid;
94 int m_offset;
95};
96
97class WaylandSeat
98{
99public:
100 WaylandSeat(wl_seat *seat, WaylandBackend *backend);
101 virtual ~WaylandSeat();
102
103 void changed(uint32_t capabilities);
104 wl_seat *seat();
105 void pointerEntered(uint32_t serial);
106 void resetCursor();
107private:
108 void destroyPointer();
109 void destroyKeyboard();
110 wl_seat *m_seat;
111 wl_pointer *m_pointer;
112 wl_keyboard *m_keyboard;
113 QScopedPointer<X11CursorTracker> m_cursorTracker;
114 WaylandBackend *m_backend;
115};
116
117/**
118* @brief Class encapsulating all Wayland data structures needed by the Egl backend.
119*
120* It creates the connection to the Wayland Compositor, set's up the registry and creates
121* the Wayland surface and it's shell and egl mapping.
122*/
123class WaylandBackend : public QObject
124{
125 Q_OBJECT
126public:
127 WaylandBackend();
128 virtual ~WaylandBackend();
129 wl_display *display();
130 wl_registry *registry();
131 void setCompositor(wl_compositor *c);
132 wl_compositor *compositor();
133 void setShell(wl_shell *s);
134 wl_shell *shell();
135 wl_egl_window *overlay();
136 ShmPool *shmPool();
137 void createSeat(uint32_t name);
138 void createShm(uint32_t name);
139 void ping(uint32_t serial);
140
141 bool createSurface();
142private Q_SLOTS:
143 void readEvents();
144private:
145 wl_display *m_display;
146 wl_registry *m_registry;
147 wl_compositor *m_compositor;
148 wl_shell *m_shell;
149 wl_surface *m_surface;
150 wl_egl_window *m_overlay;
151 wl_shell_surface *m_shellSurface;
152 QScopedPointer<WaylandSeat> m_seat;
153 QScopedPointer<ShmPool> m_shm;
154};
155
156inline
157bool CursorData::isValid() const
158{
159 return m_valid;
160}
161
162inline
163const QPoint& CursorData::hotSpot() const
164{
165 return m_hotSpot;
166}
167
168inline
169wl_buffer* CursorData::cursor() const
170{
171 return m_cursor;
172}
173
174inline
175const QSize& CursorData::size() const
176{
177 return m_size;
178}
179
180inline
181wl_seat *WaylandSeat::seat()
182{
183 return m_seat;
184}
185
186inline
187bool ShmPool::isValid() const
188{
189 return m_valid;
190}
191
192inline
193wl_display *WaylandBackend::display()
194{
195 return m_display;
196}
197
198inline
199wl_registry *WaylandBackend::registry()
200{
201 return m_registry;
202}
203
204inline
205void WaylandBackend::setCompositor(wl_compositor *c)
206{
207 m_compositor = c;
208}
209
210inline
211wl_compositor *WaylandBackend::compositor()
212{
213 return m_compositor;
214}
215
216inline
217wl_egl_window *WaylandBackend::overlay()
218{
219 return m_overlay;
220}
221
222inline
223void WaylandBackend::setShell(wl_shell *s)
224{
225 m_shell = s;
226}
227
228inline
229wl_shell *WaylandBackend::shell()
230{
231 return m_shell;
232}
233
234inline
235ShmPool* WaylandBackend::shmPool()
236{
237 return m_shm.data();
238}
239
240} // namespace Wayland
241
242class Shm;
243
244/**
245 * @brief OpenGL Backend using Egl on a Wayland surface.
246 *
247 * This Backend is the basis for a session compositor running on top of a Wayland system compositor.
248 * It creates a Surface as large as the screen and maps it as a fullscreen shell surface on the
249 * system compositor. The OpenGL context is created on the Wayland surface, so for rendering X11 is
250 * not involved.
251 *
252 * At the moment the backend is still rather limited. For getting textures from pixmap it uses the
253 * XShm library. This is currently a hack and only as proof of concept till we support texture from
254 * Wayland buffers. From then on we should use XWayland for texture mapping.
255 *
256 * Also in repainting the backend is currently still rather limited. Only supported mode is fullscreen
257 * repaints, which is obviously not optimal. Best solution is probably to go for buffer_age extension
258 * and make it the only available solution next to fullscreen repaints.
259 **/
260class EglWaylandBackend : public OpenGLBackend
261{
262public:
263 EglWaylandBackend();
264 virtual ~EglWaylandBackend();
265 virtual void screenGeometryChanged(const QSize &size);
266 virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture);
267 virtual QRegion prepareRenderingFrame();
268 virtual void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion);
269 Shm *shm();
270
271protected:
272 virtual void present();
273
274private:
275 void init();
276 bool initializeEgl();
277 bool initBufferConfigs();
278 bool initRenderingContext();
279 bool makeContextCurrent();
280 EGLDisplay m_display;
281 EGLConfig m_config;
282 EGLSurface m_surface;
283 EGLContext m_context;
284 QScopedPointer<Wayland::WaylandBackend> m_wayland;
285 QScopedPointer<Shm> m_shm;
286 friend class EglWaylandTexture;
287};
288
289/**
290 * @brief Texture using an EGLImageKHR.
291 **/
292class EglWaylandTexture : public SceneOpenGL::TexturePrivate
293{
294public:
295 virtual ~EglWaylandTexture();
296 virtual void findTarget();
297 virtual bool loadTexture(const Pixmap& pix, const QSize& size, int depth);
298 virtual OpenGLBackend *backend();
299 virtual bool update(const QRegion &damage);
300
301private:
302 friend class EglWaylandBackend;
303 EglWaylandTexture(SceneOpenGL::Texture *texture, EglWaylandBackend *backend);
304 SceneOpenGL::Texture *q;
305 EglWaylandBackend *m_backend;
306 /**
307 * The Pixmap of the window content. Get's updated in loadTexture.
308 */
309 xcb_pixmap_t m_referencedPixmap;
310};
311
312/**
313 * @brief Small helper class to encapsulate SHM related functionality.
314 *
315 */
316class Shm
317{
318public:
319 Shm();
320 ~Shm();
321 int shmId() const;
322 void *buffer() const;
323 xcb_shm_seg_t segment() const;
324 bool isValid() const;
325private:
326 bool init();
327 int m_shmId;
328 void *m_buffer;
329 xcb_shm_seg_t m_segment;
330 bool m_valid;
331};
332
333inline
334void *Shm::buffer() const
335{
336 return m_buffer;
337}
338
339inline
340bool Shm::isValid() const
341{
342 return m_valid;
343}
344
345inline
346xcb_shm_seg_t Shm::segment() const
347{
348 return m_segment;
349}
350
351inline
352int Shm::shmId() const
353{
354 return m_shmId;
355}
356
357} // namespace
358
359#endif // KWIN_EGL_ON_X_BACKEND_H
360