1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H
8 #define _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H
9 
10 #include <prthread.h>
11 
12 #include "gfxImageSurface.h"
13 #include "mozilla/gfx/2D.h"
14 #include "mozilla/gfx/Types.h"
15 #include "mozilla/Mutex.h"
16 #include "nsWaylandDisplay.h"
17 #include "nsWindow.h"
18 #include "WaylandShmBuffer.h"
19 #include "WindowSurface.h"
20 
21 #define BACK_BUFFER_NUM 3
22 
23 namespace mozilla::widget {
24 
25 class WindowImageSurface {
26  public:
27   void DrawToTarget(gfx::DrawTarget* aDest,
28                     LayoutDeviceIntRegion& aWaylandBufferDamage);
29   WindowImageSurface(gfx::DataSourceSurface* aImageSurface,
30                      const LayoutDeviceIntRegion& aUpdateRegion);
31   bool OverlapsSurface(class WindowImageSurface& aBottomSurface);
32 
GetUpdateRegion()33   const LayoutDeviceIntRegion* GetUpdateRegion() { return &mUpdateRegion; };
34 
35  private:
36   RefPtr<gfx::DataSourceSurface> mImageSurface;
37   const LayoutDeviceIntRegion mUpdateRegion;
38 };
39 
40 // WindowSurfaceWayland is an abstraction for wl_surface
41 // and related management
42 class WindowSurfaceWayland : public WindowSurface {
43  public:
44   explicit WindowSurfaceWayland(nsWindow* aWindow);
45 
46   // Lock() / Commit() are called by gecko when Firefox
47   // wants to display something. Lock() returns a DrawTarget
48   // where gecko paints. When gecko is done it calls Commit()
49   // and we try to send the DrawTarget (backed by wl_buffer)
50   // to wayland compositor.
51   //
52   // If we fail (wayland compositor is busy,
53   // wl_surface is not created yet) we queue the painting
54   // and we send it to wayland compositor in FrameCallbackHandler()/
55   // FlushPendingCommits().
56   already_AddRefed<gfx::DrawTarget> Lock(
57       const LayoutDeviceIntRegion& aRegion) override;
58   void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final;
59 
60   // Try to commit all queued drawings to Wayland compositor. This is usually
61   // called from other routines but can be used to explicitly flush
62   // all drawings as we do when wl_buffer is released
63   // (see WaylandShmBufferShm::Detach() for instance).
64   void FlushPendingCommits();
65 
GetWaylandDisplay()66   RefPtr<nsWaylandDisplay> GetWaylandDisplay() { return mWaylandDisplay; };
67 
68   // It's called from wayland compositor when there's the right
69   // time to send wl_buffer to display. It's no-op if there's no
70   // queued commits.
71   static void FrameCallbackHandler(void* aData, struct wl_callback* aCallback,
72                                    uint32_t aTime);
73 
74   static void BufferReleaseCallbackHandler(void* aData, wl_buffer* aBuffer);
75 
76  private:
77   ~WindowSurfaceWayland();
78 
79   WaylandShmBuffer* GetWaylandBuffer();
80   WaylandShmBuffer* SetNewWaylandBuffer();
81   WaylandShmBuffer* CreateWaylandBuffer(const LayoutDeviceIntSize& aSize);
82   WaylandShmBuffer* WaylandBufferFindAvailable(
83       const LayoutDeviceIntSize& aSize);
84 
85   already_AddRefed<gfx::DrawTarget> LockWaylandBuffer();
86 
87   already_AddRefed<gfx::DrawTarget> LockImageSurface(
88       const gfx::IntSize& aLockSize);
89 
90   void CacheImageSurface(const LayoutDeviceIntRegion& aRegion);
91   bool CommitImageCacheToWaylandBuffer();
92 
93   bool DrawDelayedImageCommits(gfx::DrawTarget* aDrawTarget,
94                                LayoutDeviceIntRegion& aWaylandBufferDamage);
95   // Return true if we need to sync Wayland events after this call.
96   bool FlushPendingCommitsLocked();
97 
98   void FrameCallbackHandler();
99   void BufferReleaseCallbackHandler(wl_buffer* aBuffer);
100 
101   // We can not hold a reference to nsWindow because nsBaseWidget
102   // is not thread-safe
103   nsWindow* mWindow;
104 
105   // Buffer screen rects helps us understand if we operate on
106   // the same window size as we're called on WindowSurfaceWayland::Lock().
107   // mMozContainerSize is MozContainer size when our wayland buffer was
108   // allocated.
109   LayoutDeviceIntSize mMozContainerSize;
110 
111   // mWLBufferRect is size of allocated wl_buffer where we paint to.
112   // It needs to match MozContainer widget size.
113   LayoutDeviceIntSize mWLBufferSize;
114   RefPtr<nsWaylandDisplay> mWaylandDisplay;
115 
116   // Actual buffer (backed by wl_buffer) where all drawings go into.
117   // Drawn areas are stored at mWaylandBufferDamage and if there's
118   // any uncommited drawings which needs to be send to wayland compositor
119   // the mWLBufferIsDirty is set.
120   RefPtr<WaylandShmBuffer> mWaylandBuffer;
121   RefPtr<WaylandShmBuffer> mShmBackupBuffer[BACK_BUFFER_NUM];
122 
123   // When mWaylandFullscreenDamage we invalidate whole surface,
124   // otherwise partial screen updates (mWaylandBufferDamage) are used.
125   bool mWaylandFullscreenDamage;
126   LayoutDeviceIntRegion mWaylandBufferDamage;
127 
128   // After every commit to wayland compositor a frame callback is requested.
129   // Any next commit to wayland compositor will happen when frame callback
130   // comes from wayland compositor back as it's the best time to do the commit.
131   wl_callback* mFrameCallback;
132   int mLastCommittedSurfaceID;
133 
134   // Cached drawings. If we can't get WaylandBuffer (wl_buffer) at
135   // WindowSurfaceWayland::Lock() we direct gecko rendering to
136   // mImageSurface.
137   // If we can't get WaylandBuffer at WindowSurfaceWayland::Commit()
138   // time, mImageSurface is moved to mDelayedImageCommits which
139   // holds all cached drawings.
140   // mDelayedImageCommits can be drawn by FrameCallbackHandler()
141   // or when WaylandBuffer is detached.
142   RefPtr<gfx::DataSourceSurface> mImageSurface;
143   AutoTArray<WindowImageSurface, 30> mDelayedImageCommits;
144 
145   int64_t mLastCommitTime;
146 
147   // Indicates that we don't have any cached drawings at mDelayedImageCommits
148   // and WindowSurfaceWayland::Lock() returned WaylandBuffer to gecko
149   // to draw into.
150   bool mDrawToWaylandBufferDirectly;
151 
152   // Set when our cached drawings (mDelayedImageCommits) contains
153   // full screen damage. That means we can safely switch WaylandBuffer
154   // at LockWaylandBuffer().
155   bool mCanSwitchWaylandBuffer;
156 
157   // Set when actual WaylandBuffer contains drawings which are not send to
158   // wayland compositor yet.
159   bool mWLBufferIsDirty;
160 
161   // We can't send WaylandBuffer (wl_buffer) to compositor when gecko
162   // is rendering into it (i.e. between WindowSurfaceWayland::Lock() /
163   // WindowSurfaceWayland::Commit()).
164   // Thus we use mBufferCommitAllowed to disable commit by
165   // FlushPendingCommits().
166   bool mBufferCommitAllowed;
167 
168   // We need to clear WaylandBuffer when entire transparent window is repainted.
169   // This typically apply to popup windows.
170   bool mBufferNeedsClear;
171 
172   typedef enum {
173     // Don't cache anything, always draw directly to wl_buffer
174     CACHE_NONE = 0,
175     // Cache only small paints (smaller than 1/2 of screen).
176     CACHE_SMALL = 1,
177     // Cache all painting except fullscreen updates.
178     CACHE_ALL = 2,
179   } RenderingCacheMode;
180 
181   // Cache all drawings except fullscreen updates.
182   // Avoid any rendering artifacts for significant performance penality.
183   unsigned int mSmoothRendering;
184 
185   int mSurfaceReadyTimerID;
186   mozilla::Mutex mSurfaceLock;
187 };
188 
189 }  // namespace mozilla::widget
190 
191 #endif  // _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H
192