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 #include "gfxImageSurface.h" 12 #include "mozilla/gfx/2D.h" 13 #include "mozilla/gfx/Types.h" 14 #include "nsWaylandDisplay.h" 15 #include "nsWindow.h" 16 #include "WaylandDMABufSurface.h" 17 #include "WindowSurface.h" 18 19 #define BACK_BUFFER_NUM 3 20 21 namespace mozilla { 22 namespace widget { 23 24 class WindowSurfaceWayland; 25 26 // Allocates and owns shared memory for Wayland drawing surface 27 class WaylandShmPool { 28 public: 29 WaylandShmPool(nsWaylandDisplay* aDisplay, int aSize); 30 ~WaylandShmPool(); 31 32 bool Resize(int aSize); GetShmPool()33 wl_shm_pool* GetShmPool() { return mShmPool; }; GetImageData()34 void* GetImageData() { return mImageData; }; 35 void SetImageDataFromPool(class WaylandShmPool* aSourcePool, 36 int aImageDataSize); 37 38 private: 39 wl_shm_pool* mShmPool; 40 int mShmPoolFd; 41 int mAllocatedSize; 42 void* mImageData; 43 }; 44 45 // Holds actual graphics data for wl_surface 46 class WindowBackBuffer { 47 public: IsDMABufBuffer()48 virtual bool IsDMABufBuffer() { return false; }; 49 50 virtual already_AddRefed<gfx::DrawTarget> Lock() = 0; 51 virtual void Unlock() = 0; 52 virtual bool IsLocked() = 0; 53 54 void Attach(wl_surface* aSurface); 55 virtual void Detach(wl_buffer* aBuffer) = 0; 56 virtual bool IsAttached() = 0; 57 58 virtual void Clear() = 0; 59 virtual bool Resize(int aWidth, int aHeight) = 0; 60 61 virtual int GetWidth() = 0; 62 virtual int GetHeight() = 0; 63 virtual wl_buffer* GetWlBuffer() = 0; 64 virtual void SetAttached() = 0; 65 66 virtual bool SetImageDataFromBuffer( 67 class WindowBackBuffer* aSourceBuffer) = 0; 68 IsMatchingSize(int aWidth,int aHeight)69 bool IsMatchingSize(int aWidth, int aHeight) { 70 return aWidth == GetWidth() && aHeight == GetHeight(); 71 } IsMatchingSize(class WindowBackBuffer * aBuffer)72 bool IsMatchingSize(class WindowBackBuffer* aBuffer) { 73 return aBuffer->IsMatchingSize(GetWidth(), GetHeight()); 74 } 75 GetSurfaceFormat()76 static gfx::SurfaceFormat GetSurfaceFormat() { return mFormat; } 77 78 nsWaylandDisplay* GetWaylandDisplay(); 79 WindowBackBuffer(WindowSurfaceWayland * aWindowSurfaceWayland)80 WindowBackBuffer(WindowSurfaceWayland* aWindowSurfaceWayland) 81 : mWindowSurfaceWayland(aWindowSurfaceWayland){}; 82 virtual ~WindowBackBuffer() = default; 83 84 protected: 85 WindowSurfaceWayland* mWindowSurfaceWayland; 86 87 private: 88 static gfx::SurfaceFormat mFormat; 89 }; 90 91 class WindowBackBufferShm : public WindowBackBuffer { 92 public: 93 WindowBackBufferShm(WindowSurfaceWayland* aWindowSurfaceWayland, int aWidth, 94 int aHeight); 95 ~WindowBackBufferShm(); 96 97 already_AddRefed<gfx::DrawTarget> Lock(); IsLocked()98 bool IsLocked() { return mIsLocked; }; Unlock()99 void Unlock() { mIsLocked = false; }; 100 101 void Detach(wl_buffer* aBuffer); IsAttached()102 bool IsAttached() { return mAttached; } SetAttached()103 void SetAttached() { mAttached = true; }; 104 105 void Clear(); 106 bool Resize(int aWidth, int aHeight); 107 bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer); 108 GetWidth()109 int GetWidth() { return mWidth; }; GetHeight()110 int GetHeight() { return mHeight; }; 111 GetWlBuffer()112 wl_buffer* GetWlBuffer() { return mWLBuffer; }; 113 114 private: 115 void Create(int aWidth, int aHeight); 116 void ReleaseShmSurface(); 117 118 // WaylandShmPool provides actual shared memory we draw into 119 WaylandShmPool mShmPool; 120 121 // wl_buffer is a wayland object that encapsulates the shared memory 122 // and passes it to wayland compositor by wl_surface object. 123 wl_buffer* mWLBuffer; 124 int mWidth; 125 int mHeight; 126 bool mAttached; 127 bool mIsLocked; 128 }; 129 130 class WindowBackBufferDMABuf : public WindowBackBuffer { 131 public: 132 WindowBackBufferDMABuf(WindowSurfaceWayland* aWindowSurfaceWayland, 133 int aWidth, int aHeight); 134 ~WindowBackBufferDMABuf(); 135 IsDMABufBuffer()136 bool IsDMABufBuffer() { return true; }; 137 138 bool IsAttached(); 139 void SetAttached(); 140 141 int GetWidth(); 142 int GetHeight(); 143 wl_buffer* GetWlBuffer(); 144 145 bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer); 146 147 already_AddRefed<gfx::DrawTarget> Lock(); 148 bool IsLocked(); 149 void Unlock(); 150 151 void Clear(); 152 void Detach(wl_buffer* aBuffer); 153 bool Resize(int aWidth, int aHeight); 154 155 private: 156 RefPtr<WaylandDMABufSurfaceRGBA> mDMAbufSurface; 157 }; 158 159 class WindowImageSurface { 160 public: 161 static void Draw(gfx::SourceSurface* aSurface, gfx::DrawTarget* aDest, 162 const LayoutDeviceIntRegion& aRegion); 163 164 void Draw(gfx::DrawTarget* aDest, 165 LayoutDeviceIntRegion& aWaylandBufferDamage); 166 167 WindowImageSurface(gfxImageSurface* aImageSurface, 168 const LayoutDeviceIntRegion& aUpdateRegion); 169 170 bool OverlapsSurface(class WindowImageSurface& aBottomSurface); 171 GetUpdateRegion()172 const LayoutDeviceIntRegion* GetUpdateRegion() { return &mUpdateRegion; }; 173 174 private: 175 RefPtr<gfx::SourceSurface> mSurface; 176 RefPtr<gfxImageSurface> mImageSurface; 177 const LayoutDeviceIntRegion mUpdateRegion; 178 }; 179 180 // WindowSurfaceWayland is an abstraction for wl_surface 181 // and related management 182 class WindowSurfaceWayland : public WindowSurface { 183 public: 184 explicit WindowSurfaceWayland(nsWindow* aWindow); 185 ~WindowSurfaceWayland(); 186 187 // Lock() / Commit() are called by gecko when Firefox 188 // wants to display something. Lock() returns a DrawTarget 189 // where gecko paints. When gecko is done it calls Commit() 190 // and we try to send the DrawTarget (backed by wl_buffer) 191 // to wayland compositor. 192 // 193 // If we fail (wayland compositor is busy, 194 // wl_surface is not created yet) we queue the painting 195 // and we send it to wayland compositor in FrameCallbackHandler()/ 196 // DelayedCommitHandler/CommitWaylandBuffer(). 197 already_AddRefed<gfx::DrawTarget> Lock( 198 const LayoutDeviceIntRegion& aRegion) override; 199 void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final; 200 201 // It's called from wayland compositor when there's the right 202 // time to send wl_buffer to display. It's no-op if there's no 203 // queued commits. 204 void FrameCallbackHandler(); 205 206 // When a new window is created we may not have a valid wl_surface 207 // for drawing (Gtk haven't created it yet). All commits are queued 208 // and DelayedCommitHandler() is called by timer when wl_surface is ready 209 // for drawing. 210 void DelayedCommitHandler(); 211 212 // Try to commit all queued drawings to Wayland compositor. This is usually 213 // called from other routines but can be used to explicitly flush 214 // all drawings as we do when wl_buffer is released 215 // (see WindowBackBufferShm::Detach() for instance). 216 void CommitWaylandBuffer(); 217 GetWaylandDisplay()218 nsWaylandDisplay* GetWaylandDisplay() { return mWaylandDisplay; }; 219 220 // Image cache mode can be set by widget.wayland_cache_mode 221 typedef enum { 222 // Cache and clip all drawings, default. It's slowest 223 // but also without any rendered artifacts. 224 CACHE_ALL = 0, 225 // Cache drawing only when back buffer is missing. May produce 226 // some rendering artifacts and flickering when partial screen update 227 // is rendered. 228 CACHE_MISSING = 1, 229 // Don't cache anything, draw only when back buffer is available. 230 // Suitable for fullscreen content only like fullscreen video playback and 231 // may work well with dmabuf backend. 232 CACHE_NONE = 2 233 } RenderingCacheMode; 234 235 private: 236 WindowBackBuffer* GetWaylandBufferWithSwitch(); 237 WindowBackBuffer* GetWaylandBufferRecent(); 238 WindowBackBuffer* SetNewWaylandBuffer(bool aAllowDMABufBackend); 239 WindowBackBuffer* CreateWaylandBuffer(int aWidth, int aHeight, 240 bool aUseDMABufBackend); 241 WindowBackBuffer* CreateWaylandBufferInternal(int aWidth, int aHeight, 242 bool aUseDMABufBackend); 243 WindowBackBuffer* WaylandBufferFindAvailable(int aWidth, int aHeight, 244 bool aUseDMABufBackend); 245 246 already_AddRefed<gfx::DrawTarget> LockWaylandBuffer(); 247 void UnlockWaylandBuffer(); 248 249 already_AddRefed<gfx::DrawTarget> LockImageSurface( 250 const gfx::IntSize& aLockSize); 251 252 void CacheImageSurface(const LayoutDeviceIntRegion& aRegion); 253 bool CommitImageCacheToWaylandBuffer(); 254 255 void DrawDelayedImageCommits(gfx::DrawTarget* aDrawTarget, 256 LayoutDeviceIntRegion& aWaylandBufferDamage); 257 258 // TODO: Do we need to hold a reference to nsWindow object? 259 nsWindow* mWindow; 260 // Buffer screen rects helps us understand if we operate on 261 // the same window size as we're called on WindowSurfaceWayland::Lock(). 262 // mLockedScreenRect is window size when our wayland buffer was allocated. 263 LayoutDeviceIntRect mLockedScreenRect; 264 265 // mWLBufferRect is an intersection of mozcontainer widgetsize and 266 // mLockedScreenRect size. It can be different than mLockedScreenRect 267 // during resize when mBounds are updated immediately but actual 268 // GtkWidget size is updated asynchronously (see Bug 1489463). 269 LayoutDeviceIntRect mWLBufferRect; 270 nsWaylandDisplay* mWaylandDisplay; 271 272 // Actual buffer (backed by wl_buffer) where all drawings go into. 273 // Drawn areas are stored at mWaylandBufferDamage and if there's 274 // any uncommited drawings which needs to be send to wayland compositor 275 // the mBufferPendingCommit is set. 276 WindowBackBuffer* mWaylandBuffer; 277 WindowBackBuffer* mShmBackupBuffer[BACK_BUFFER_NUM]; 278 WindowBackBuffer* mDMABackupBuffer[BACK_BUFFER_NUM]; 279 280 // When mWaylandFullscreenDamage we invalidate whole surface, 281 // otherwise partial screen updates (mWaylandBufferDamage) are used. 282 bool mWaylandFullscreenDamage; 283 LayoutDeviceIntRegion mWaylandBufferDamage; 284 285 // After every commit to wayland compositor a frame callback is requested. 286 // Any next commit to wayland compositor will happen when frame callback 287 // comes from wayland compositor back as it's the best time to do the commit. 288 wl_callback* mFrameCallback; 289 wl_surface* mLastCommittedSurface; 290 291 // Registered reference to pending DelayedCommitHandler() call. 292 WindowSurfaceWayland** mDelayedCommitHandle; 293 294 // Cached drawings. If we can't get WaylandBuffer (wl_buffer) at 295 // WindowSurfaceWayland::Lock() we direct gecko rendering to 296 // mImageSurface. 297 // If we can't get WaylandBuffer at WindowSurfaceWayland::Commit() 298 // time, mImageSurface is moved to mDelayedImageCommits which 299 // holds all cached drawings. 300 // mDelayedImageCommits can be drawn by FrameCallbackHandler(), 301 // DelayedCommitHandler() or when WaylandBuffer is detached. 302 RefPtr<gfxImageSurface> mImageSurface; 303 AutoTArray<WindowImageSurface, 30> mDelayedImageCommits; 304 305 int64_t mLastCommitTime; 306 307 // Indicates that we don't have any cached drawings at mDelayedImageCommits 308 // and WindowSurfaceWayland::Lock() returned WaylandBuffer to gecko 309 // to draw into. 310 bool mDrawToWaylandBufferDirectly; 311 312 // Set when our cached drawings (mDelayedImageCommits) contains 313 // full screen damage. That means we can safely switch WaylandBuffer 314 // at LockWaylandBuffer(). 315 bool mCanSwitchWaylandBuffer; 316 317 // Set when actual WaylandBuffer contains drawings which are not send to 318 // wayland compositor yet. 319 bool mBufferPendingCommit; 320 321 // We can't send WaylandBuffer (wl_buffer) to compositor when gecko 322 // is rendering into it (i.e. between WindowSurfaceWayland::Lock() / 323 // WindowSurfaceWayland::Commit()). 324 // Thus we use mBufferCommitAllowed to disable commit by callbacks 325 // (FrameCallbackHandler(), DelayedCommitHandler()) 326 bool mBufferCommitAllowed; 327 328 // We need to clear WaylandBuffer when entire transparent window is repainted. 329 // This typically apply to popup windows. 330 bool mBufferNeedsClear; 331 332 // Cache all drawings except fullscreen updates. 333 // Avoid any rendering artifacts for significant performance penality. 334 bool mSmoothRendering; 335 336 bool mIsMainThread; 337 338 static bool UseDMABufBackend(); 339 static bool mUseDMABufInitialized; 340 static bool mUseDMABuf; 341 }; 342 343 } // namespace widget 344 } // namespace mozilla 345 346 #endif // _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H 347