1 /*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #ifndef KWIN_SCENE_H
11 #define KWIN_SCENE_H
12
13 #include "toplevel.h"
14 #include "utils.h"
15 #include "kwineffects.h"
16
17 #include <QElapsedTimer>
18 #include <QMatrix4x4>
19
20 namespace KWin
21 {
22
23 namespace Decoration
24 {
25 class DecoratedClientImpl;
26 }
27
28 class AbstractOutput;
29 class DecorationRenderer;
30 class Deleted;
31 class EffectFrameImpl;
32 class EffectWindowImpl;
33 class GLTexture;
34 class Item;
35 class OverlayWindow;
36 class PlatformSurfaceTexture;
37 class RenderLoop;
38 class Shadow;
39 class ShadowItem;
40 class SurfaceItem;
41 class SurfacePixmapInternal;
42 class SurfacePixmapWayland;
43 class SurfacePixmapX11;
44 class WindowItem;
45
46 // The base class for compositing backends.
47 class KWIN_EXPORT Scene : public QObject
48 {
49 Q_OBJECT
50 public:
51 explicit Scene(QObject *parent = nullptr);
52 ~Scene() override = 0;
53 class EffectFrame;
54 class Window;
55
56 /**
57 * Schedules a repaint for the specified @a region.
58 */
59 void addRepaint(const QRegion ®ion);
60
61 /**
62 * Returns the repaints region for output with the specified @a output.
63 */
64 QRegion repaints(AbstractOutput *output) const;
65 void resetRepaints(AbstractOutput *output);
66
67 // Returns true if the ctor failed to properly initialize.
68 virtual bool initFailed() const = 0;
69 virtual CompositingType compositingType() const = 0;
70
71 // Repaints the given screen areas, windows provides the stacking order.
72 // The entry point for the main part of the painting pass.
73 // returns the time since the last vblank signal - if there's one
74 // ie. "what of this frame is lost to painting"
75 virtual void paint(AbstractOutput *output, const QRegion &damage, const QList<Toplevel *> &windows,
76 RenderLoop *renderLoop) = 0;
77
78
79 void paintScreen(AbstractOutput *output, const QList<Toplevel *> &toplevels);
80
81 /**
82 * Adds the Toplevel to the Scene.
83 *
84 * If the toplevel gets deleted, then the scene will try automatically
85 * to re-bind an underlying scene window to the corresponding Deleted.
86 *
87 * @param toplevel The window to be added.
88 * @note You can add a toplevel to scene only once.
89 */
90 void addToplevel(Toplevel *toplevel);
91
92 /**
93 * Removes the Toplevel from the Scene.
94 *
95 * @param toplevel The window to be removed.
96 * @note You can remove a toplevel from the scene only once.
97 */
98 void removeToplevel(Toplevel *toplevel);
99
100 /**
101 * @brief Creates the Scene backend of an EffectFrame.
102 *
103 * @param frame The EffectFrame this Scene::EffectFrame belongs to.
104 */
105 virtual Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame) = 0;
106 /**
107 * @brief Creates the Scene specific Shadow subclass.
108 *
109 * An implementing class has to create a proper instance. It is not allowed to
110 * return @c null.
111 *
112 * @param toplevel The Toplevel for which the Shadow needs to be created.
113 */
114 virtual Shadow *createShadow(Toplevel *toplevel) = 0;
115 // Flags controlling how painting is done.
116 enum {
117 // Window (or at least part of it) will be painted opaque.
118 PAINT_WINDOW_OPAQUE = 1 << 0,
119 // Window (or at least part of it) will be painted translucent.
120 PAINT_WINDOW_TRANSLUCENT = 1 << 1,
121 // Window will be painted with transformed geometry.
122 PAINT_WINDOW_TRANSFORMED = 1 << 2,
123 // Paint only a region of the screen (can be optimized, cannot
124 // be used together with TRANSFORMED flags).
125 PAINT_SCREEN_REGION = 1 << 3,
126 // Whole screen will be painted with transformed geometry.
127 PAINT_SCREEN_TRANSFORMED = 1 << 4,
128 // At least one window will be painted with transformed geometry.
129 PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS = 1 << 5,
130 // Clear whole background as the very first step, without optimizing it
131 PAINT_SCREEN_BACKGROUND_FIRST = 1 << 6,
132 // PAINT_DECORATION_ONLY = 1 << 7 has been removed
133 // Window will be painted with a lanczos filter.
134 PAINT_WINDOW_LANCZOS = 1 << 8
135 // PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_WITHOUT_FULL_REPAINTS = 1 << 9 has been removed
136 };
137 virtual OverlayWindow* overlayWindow() const = 0;
138
139 virtual bool makeOpenGLContextCurrent();
140 virtual void doneOpenGLContextCurrent();
141 virtual bool supportsNativeFence() const;
142
143 virtual QMatrix4x4 screenProjectionMatrix() const;
144
145 virtual DecorationRenderer *createDecorationRenderer(Decoration::DecoratedClientImpl *) = 0;
146
147 /**
148 * Whether the Scene is able to drive animations.
149 * This is used as a hint to the effects system which effects can be supported.
150 * If the Scene performs software rendering it is supposed to return @c false,
151 * if rendering is hardware accelerated it should return @c true.
152 */
153 virtual bool animationsSupported() const = 0;
154
155 /**
156 * The QPainter used by a QPainter based compositor scene.
157 * Default implementation returns @c nullptr;
158 */
159 virtual QPainter *scenePainter() const;
160
161 /**
162 * The render buffer used by a QPainter based compositor.
163 * Default implementation returns @c nullptr.
164 */
165 virtual QImage *qpainterRenderBuffer(AbstractOutput *output) const;
166
167 /**
168 * The backend specific extensions (e.g. EGL/GLX extensions).
169 *
170 * Not the OpenGL (ES) extension!
171 *
172 * Default implementation returns empty list
173 */
174 virtual QVector<QByteArray> openGLPlatformInterfaceExtensions() const;
175
textureForOutput(AbstractOutput * output)176 virtual QSharedPointer<GLTexture> textureForOutput(AbstractOutput *output) const {
177 Q_UNUSED(output);
178 return {};
179 }
180
181 virtual PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap);
182 virtual PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap);
183 virtual PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap);
184
185 virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data);
186
187 static QMatrix4x4 createProjectionMatrix(const QRect &rect);
188
189 Q_SIGNALS:
190 void frameRendered();
191 void resetCompositing();
192
193 public Q_SLOTS:
194 // a window has been closed
195 void windowClosed(KWin::Toplevel* c, KWin::Deleted* deleted);
196 protected:
197 virtual Window *createWindow(Toplevel *toplevel) = 0;
198 void createStackingOrder(const QList<Toplevel *> &toplevels);
199 void clearStackingOrder();
200 // shared implementation, starts painting the screen
201 void paintScreen(const QRegion &damage, const QRegion &repaint,
202 QRegion *updateRegion, QRegion *validRegion, RenderLoop *renderLoop,
203 const QMatrix4x4 &projection = QMatrix4x4());
204 // Render cursor texture in case hardware cursor is disabled/non-applicable
205 virtual void paintCursor(const QRegion ®ion) = 0;
206 friend class EffectsHandlerImpl;
207 // called after all effects had their paintScreen() called
208 void finalPaintScreen(int mask, const QRegion ®ion, ScreenPaintData& data);
209 // shared implementation of painting the screen in the generic
210 // (unoptimized) way
211 virtual void paintGenericScreen(int mask, const ScreenPaintData &data);
212 // shared implementation of painting the screen in an optimized way
213 virtual void paintSimpleScreen(int mask, const QRegion ®ion);
214 // paint the background (not the desktop background - the whole background)
215 virtual void paintBackground(const QRegion ®ion) = 0;
216
217 /**
218 * Notifies about starting to paint.
219 *
220 * @p damage contains the reported damage as suggested by windows and effects on prepaint calls.
221 */
222 virtual void aboutToStartPainting(AbstractOutput *output, const QRegion &damage);
223 // called after all effects had their paintWindow() called
224 void finalPaintWindow(EffectWindowImpl* w, int mask, const QRegion ®ion, WindowPaintData& data);
225 // shared implementation, starts painting the window
226 virtual void paintWindow(Window* w, int mask, const QRegion ®ion);
227 // called after all effects had their drawWindow() called
228 virtual void finalDrawWindow(EffectWindowImpl* w, int mask, const QRegion ®ion, WindowPaintData& data);
229 // let the scene decide whether it's better to paint more of the screen, eg. in order to allow a buffer swap
230 // the default is NOOP
231 virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen);
232
233 virtual void paintEffectQuickView(EffectQuickView *w) = 0;
234
235 // saved data for 2nd pass of optimized screen painting
236 struct Phase2Data {
237 Window *window = nullptr;
238 QRegion region;
239 QRegion clip;
240 int mask = 0;
241 };
242 // The region which actually has been painted by paintScreen() and should be
243 // copied from the buffer to the screen. I.e. the region returned from Scene::paintScreen().
244 // Since prePaintWindow() can extend areas to paint, these changes would have to propagate
245 // up all the way from paintSimpleScreen() up to paintScreen(), so save them here rather
246 // than propagate them up in arguments.
247 QRegion painted_region;
248 // Additional damage that needs to be repaired to bring a reused back buffer up to date
249 QRegion repaint_region;
250 // The dirty region before it was unioned with repaint_region
251 QRegion damaged_region;
252 // The screen that is being currently painted
253 AbstractOutput *painted_screen = nullptr;
254
255 // windows in their stacking order
256 QVector< Window* > stacking_order;
257 private:
258 void removeRepaints(AbstractOutput *output);
259 std::chrono::milliseconds m_expectedPresentTimestamp = std::chrono::milliseconds::zero();
260 QHash< Toplevel*, Window* > m_windows;
261 QMap<AbstractOutput *, QRegion> m_repaints;
262 // how many times finalPaintScreen() has been called
263 int m_paintScreenCount = 0;
264 };
265
266 /**
267 * Factory class to create a Scene. Needs to be implemented by the plugins.
268 */
269 class KWIN_EXPORT SceneFactory : public QObject
270 {
271 Q_OBJECT
272 public:
273 ~SceneFactory() override;
274
275 /**
276 * @returns The created Scene, may be @c nullptr.
277 */
278 virtual Scene *create(QObject *parent = nullptr) const = 0;
279
280 protected:
281 explicit SceneFactory(QObject *parent);
282 };
283
284 // The base class for windows representations in composite backends
285 class Scene::Window : public QObject
286 {
287 Q_OBJECT
288
289 public:
290 explicit Window(Toplevel *client, QObject *parent = nullptr);
291 ~Window() override;
292 // perform the actual painting of the window
293 virtual void performPaint(int mask, const QRegion ®ion, const WindowPaintData &data) = 0;
294 int x() const;
295 int y() const;
296 int width() const;
297 int height() const;
298 QRect geometry() const;
299 QPoint pos() const;
300 QSize size() const;
301 QRect rect() const;
302 // access to the internal window class
303 // TODO eventually get rid of this
304 Toplevel* window() const;
305 // should the window be painted
306 bool isPaintingEnabled() const;
307 void resetPaintingEnabled();
308 // Flags explaining why painting should be disabled
309 enum {
310 // Window will not be painted
311 PAINT_DISABLED = 1 << 0,
312 // Window will not be painted because it is deleted
313 PAINT_DISABLED_BY_DELETE = 1 << 1,
314 // Window will not be painted because of which desktop it's on
315 PAINT_DISABLED_BY_DESKTOP = 1 << 2,
316 // Window will not be painted because it is minimized
317 PAINT_DISABLED_BY_MINIMIZE = 1 << 3,
318 // Window will not be painted because it's not on the current activity
319 PAINT_DISABLED_BY_ACTIVITY = 1 << 5
320 };
321 void enablePainting(int reason);
322 void disablePainting(int reason);
323 // is the window visible at all
324 bool isVisible() const;
325 // is the window fully opaque
326 bool isOpaque() const;
327 QRegion decorationShape() const;
328 void updateToplevel(Deleted *deleted);
329 void referencePreviousPixmap();
330 void unreferencePreviousPixmap();
331 WindowItem *windowItem() const;
332 SurfaceItem *surfaceItem() const;
333 ShadowItem *shadowItem() const;
334
windowTexture()335 virtual QSharedPointer<GLTexture> windowTexture() {
336 return {};
337 }
338
339 protected:
340 Toplevel* toplevel;
341 private:
342 void referencePreviousPixmap_helper(SurfaceItem *item);
343 void unreferencePreviousPixmap_helper(SurfaceItem *item);
344
345 void updateWindowPosition();
346
347 int disable_painting;
348 QScopedPointer<WindowItem> m_windowItem;
349 Q_DISABLE_COPY(Window)
350 };
351
352 class Scene::EffectFrame
353 {
354 public:
355 EffectFrame(EffectFrameImpl* frame);
356 virtual ~EffectFrame();
357 virtual void render(const QRegion ®ion, double opacity, double frameOpacity) = 0;
358 virtual void free() = 0;
359 virtual void freeIconFrame() = 0;
360 virtual void freeTextFrame() = 0;
361 virtual void freeSelection() = 0;
362 virtual void crossFadeIcon() = 0;
363 virtual void crossFadeText() = 0;
364
365 protected:
366 EffectFrameImpl* m_effectFrame;
367 };
368
369 inline
x()370 int Scene::Window::x() const
371 {
372 return toplevel->x();
373 }
374
375 inline
y()376 int Scene::Window::y() const
377 {
378 return toplevel->y();
379 }
380
381 inline
width()382 int Scene::Window::width() const
383 {
384 return toplevel->width();
385 }
386
387 inline
height()388 int Scene::Window::height() const
389 {
390 return toplevel->height();
391 }
392
393 inline
geometry()394 QRect Scene::Window::geometry() const
395 {
396 return toplevel->frameGeometry();
397 }
398
399 inline
size()400 QSize Scene::Window::size() const
401 {
402 return toplevel->size();
403 }
404
405 inline
pos()406 QPoint Scene::Window::pos() const
407 {
408 return toplevel->pos();
409 }
410
411 inline
rect()412 QRect Scene::Window::rect() const
413 {
414 return toplevel->rect();
415 }
416
417 inline
window()418 Toplevel* Scene::Window::window() const
419 {
420 return toplevel;
421 }
422
423 } // namespace
424
425 Q_DECLARE_INTERFACE(KWin::SceneFactory, "org.kde.kwin.Scene")
426
427 #endif
428