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