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 &region);
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 &region, 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 &region) = 0;
206     friend class EffectsHandlerImpl;
207     // called after all effects had their paintScreen() called
208     void finalPaintScreen(int mask, const QRegion &region, 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 &region);
214     // paint the background (not the desktop background - the whole background)
215     virtual void paintBackground(const QRegion &region) = 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 &region, WindowPaintData& data);
225     // shared implementation, starts painting the window
226     virtual void paintWindow(Window* w, int mask, const QRegion &region);
227     // called after all effects had their drawWindow() called
228     virtual void finalDrawWindow(EffectWindowImpl* w, int mask, const QRegion &region, 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 &region, 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 &region, 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 &region, 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