NativeLayerWayland.h (13547B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef mozilla_layers_NativeLayerWayland_h 7 #define mozilla_layers_NativeLayerWayland_h 8 9 #include <deque> 10 11 #include "mozilla/Mutex.h" 12 #include "mozilla/layers/NativeLayer.h" 13 #include "mozilla/layers/SurfacePoolWayland.h" 14 #include "mozilla/widget/DMABufFormats.h" 15 #include "nsRegion.h" 16 #include "nsTArray.h" 17 18 namespace mozilla::wr { 19 class RenderDMABUFTextureHost; 20 } // namespace mozilla::wr 21 22 namespace mozilla::widget { 23 class WaylandSurfaceLock; 24 } // namespace mozilla::widget 25 26 namespace mozilla::layers { 27 class NativeLayerWaylandExternal; 28 class NativeLayerWaylandRender; 29 30 struct LayerState { 31 // Layer is visible (has correct size/position), we should paint it 32 bool mIsVisible : 1; 33 // Layer has been rendered and it's visible 34 bool mIsRendered : 1; 35 36 // Layer visibility has been changed 37 bool mMutatedVisibility : 1; 38 // Layer stacking order was changed (layer was added/removed/mapped/unmapped) 39 bool mMutatedStackingOrder : 1; 40 // Layer placement (size/position/scale etc.) was changed 41 bool mMutatedPlacement : 1; 42 // mFrontBuffer was changed and we need to commit it to Wayland compositor 43 // to show new content. 44 bool mMutatedFrontBuffer : 1; 45 // Was rendered in last cycle. 46 bool mRenderedLastCycle : 1; 47 48 // For debugging purposse. Resets the layer state 49 // to force full init. 50 void InvalidateAll() { 51 mIsVisible = false; 52 mIsRendered = false; 53 54 mMutatedVisibility = true; 55 mMutatedStackingOrder = true; 56 mMutatedPlacement = true; 57 mMutatedFrontBuffer = true; 58 mRenderedLastCycle = false; 59 } 60 }; 61 62 class NativeLayerRootWayland final : public NativeLayerRoot { 63 public: 64 static already_AddRefed<NativeLayerRootWayland> Create( 65 RefPtr<widget::WaylandSurface> aWaylandSurface); 66 67 // Overridden methods 68 already_AddRefed<NativeLayer> CreateLayer( 69 const gfx::IntSize& aSize, bool aIsOpaque, 70 SurfacePoolHandle* aSurfacePoolHandle) override; 71 already_AddRefed<NativeLayer> CreateLayerForExternalTexture( 72 bool aIsOpaque) override; 73 74 void AppendLayer(NativeLayer* aLayer) override; 75 void RemoveLayer(NativeLayer* aLayer) override; 76 void SetLayers(const nsTArray<RefPtr<NativeLayer>>& aLayers) override; 77 78 void PrepareForCommit() override { mFrameInProcess = true; }; 79 bool CommitToScreen() override; 80 81 // Main thread only 82 GdkWindow* GetGdkWindow() const; 83 84 RefPtr<widget::WaylandSurface> GetRootWaylandSurface() { 85 return mRootSurface; 86 } 87 88 RefPtr<widget::DRMFormat> GetDRMFormat() { return mDRMFormat; } 89 90 void FrameCallbackHandler(uint32_t aTime); 91 92 RefPtr<widget::WaylandBuffer> BorrowExternalBuffer( 93 RefPtr<DMABufSurface> aDMABufSurface); 94 95 #ifdef MOZ_LOGGING 96 nsAutoCString GetDebugTag() const; 97 void* GetLoggingWidget() const; 98 #endif 99 100 void Init(); 101 void Shutdown(); 102 103 void UpdateLayersOnMainThread(); 104 void RequestUpdateOnMainThreadLocked( 105 const widget::WaylandSurfaceLock& aProofOfLock); 106 107 explicit NativeLayerRootWayland( 108 RefPtr<widget::WaylandSurface> aWaylandSurface); 109 110 void NotifyFullscreenChanged(bool aIsFullscreen) { 111 mIsFullscreen = aIsFullscreen; 112 } 113 114 private: 115 ~NativeLayerRootWayland(); 116 117 // Map NativeLayerRootWayland and all child surfaces. 118 // Returns true if we're set. 119 bool MapLocked(const widget::WaylandSurfaceLock& aProofOfLock); 120 bool IsEmptyLocked(const widget::WaylandSurfaceLock& aProofOfLock); 121 void ClearLayersLocked(const widget::WaylandSurfaceLock& aProofOfLock); 122 123 #ifdef MOZ_LOGGING 124 void LogStatsLocked(const widget::WaylandSurfaceLock& aProofOfLock); 125 #endif 126 127 #ifdef MOZ_LOGGING 128 void* mLoggingWidget = nullptr; 129 #endif 130 131 // WaylandSurface of nsWindow (our root window). 132 // This WaylandSurface is owned by nsWindow so we don't map/unmap it 133 // or handle any callbacks. 134 // We also use widget::WaylandSurfaceLock for locking whole layer for 135 // read/write. 136 RefPtr<widget::WaylandSurface> mRootSurface; 137 138 // Copy of DRM format we use to create DMABuf surfaces 139 RefPtr<widget::DRMFormat> mDRMFormat; 140 141 // Empty buffer attached to mSurface. We need to have something 142 // attached to make mSurface and all child visible. 143 RefPtr<widget::WaylandBufferSHM> mTmpBuffer; 144 145 // Child layers attached to this root, they're all on the same level 146 // so all child layers are attached to mContainer as subsurfaces. 147 // Layer visibility is sorted by Z-order, mSublayers[0] is on bottom. 148 nsTArray<RefPtr<NativeLayerWayland>> mSublayers; 149 150 // Child layers which needs to be updated on main thread, 151 // they have been added or removed. 152 nsTArray<RefPtr<NativeLayerWayland>> mMainThreadUpdateSublayers; 153 154 // Child layers which has been removed and are 155 // waiting to be unmapped. We do that in sync with root surface to avoid 156 // flickering. When unmapped they're moved to mMainThreadUpdateSublayers 157 // for final clean up at main thread. 158 nsTArray<RefPtr<NativeLayerWayland>> mRemovedSublayers; 159 160 // External buffers (DMABuf) used by the layers. 161 // We want to cache and reuse wl_buffer of external images. 162 nsTArray<widget::WaylandBufferDMABUFHolder> mExternalBuffers; 163 164 // We're between CompositorBeginFrame() / CompositorEndFrame() calls. 165 mozilla::Atomic<bool, mozilla::Relaxed> mFrameInProcess{false}; 166 167 uint32_t mLastFrameCallbackTime = 0; 168 169 // State flags used for optimizations 170 // Layers have been added/removed 171 bool mRootMutatedStackingOrder = false; 172 // All layers has been rendered 173 bool mRootAllLayersRendered = false; 174 bool mMainThreadUpdateQueued = false; 175 bool mIsFullscreen = false; 176 }; 177 178 class NativeLayerWayland : public NativeLayer { 179 public: 180 NativeLayerWayland* AsNativeLayerWayland() override { return this; } 181 virtual NativeLayerWaylandExternal* AsNativeLayerWaylandExternal() { 182 return nullptr; 183 } 184 virtual NativeLayerWaylandRender* AsNativeLayerWaylandRender() { 185 return nullptr; 186 } 187 188 // Overridden methods 189 gfx::IntSize GetSize() override; 190 void SetPosition(const gfx::IntPoint& aPosition) override; 191 gfx::IntPoint GetPosition() override; 192 void SetTransform(const gfx::Matrix4x4& aTransform) override; 193 gfx::Matrix4x4 GetTransform() override; 194 gfx::IntRect GetRect() override; 195 void SetSamplingFilter(gfx::SamplingFilter aSamplingFilter) override; 196 197 bool IsOpaque() override; 198 void SetClipRect(const Maybe<gfx::IntRect>& aClipRect) override; 199 Maybe<gfx::IntRect> ClipRect() override; 200 void SetRoundedClipRect(const Maybe<gfx::RoundedRect>& aClip) override; 201 Maybe<gfx::RoundedRect> RoundedClipRect() override; 202 gfx::IntRect CurrentSurfaceDisplayRect() override; 203 void SetSurfaceIsFlipped(bool aIsFlipped) override; 204 bool SurfaceIsFlipped() override; 205 206 void RenderLayer(double aScale); 207 // TODO 208 GpuFence* GetGpuFence() override { return nullptr; } 209 210 RefPtr<widget::WaylandSurface> GetWaylandSurface() { return mSurface; } 211 212 // Surface Map/Unamp happens on rendering thread. 213 // 214 // We can use surface right after map but we need to finish mapping 215 // on main thread to render it correctly. 216 // 217 // Also Unmap() needs to be finished on main thread. 218 bool IsMapped(); 219 bool Map(widget::WaylandSurfaceLock* aParentWaylandSurfaceLock); 220 void Unmap(); 221 222 void UpdateOnMainThread(); 223 void MainThreadMap(); 224 void MainThreadUnmap(); 225 226 void ForceCommit(); 227 228 void PlaceAbove(NativeLayerWayland* aLowerLayer); 229 230 #ifdef MOZ_LOGGING 231 nsAutoCString GetDebugTag() const; 232 #endif 233 234 void SetFrameCallbackState(bool aState); 235 236 virtual void DiscardBackbuffersLocked( 237 const widget::WaylandSurfaceLock& aProofOfLock, bool aForce = false) = 0; 238 void DiscardBackbuffers() override; 239 240 NativeLayerWayland(NativeLayerRootWayland* aRootLayer, 241 const gfx::IntSize& aSize, bool aIsOpaque); 242 243 // No need to lock as we used it when new layers are added only 244 constexpr static int sLayerClear = 0; 245 constexpr static int sLayerRemoved = 1; 246 constexpr static int sLayerAdded = 2; 247 248 void MarkClear() { mUsageCount = sLayerClear; } 249 void MarkRemoved() { mUsageCount = sLayerRemoved; } 250 void MarkAdded() { mUsageCount += sLayerAdded; } 251 252 bool IsRemoved() const { return mUsageCount == sLayerRemoved; } 253 bool IsNew() const { return mUsageCount == sLayerAdded; } 254 255 LayerState* State() { return &mState; } 256 257 protected: 258 void SetScalelocked(const widget::WaylandSurfaceLock& aProofOfLock, 259 double aScale); 260 void UpdateLayerPlacementLocked( 261 const widget::WaylandSurfaceLock& aProofOfLock); 262 virtual bool CommitFrontBufferToScreenLocked( 263 const widget::WaylandSurfaceLock& aProofOfLock) = 0; 264 virtual bool IsFrontBufferChanged() = 0; 265 266 protected: 267 ~NativeLayerWayland(); 268 269 // There's a cycle dependency here as NativeLayerRootWayland holds strong 270 // reference to NativeLayerWayland and vice versa. 271 // 272 // Shutdown sequence is: 273 // 274 // 1) NativeLayerRootWayland is released by GtkCompositorWidget 275 // 2) NativeLayerRootWayland calls childs NativeLayerWayland release code and 276 // unrefs them. 277 // 3) Child NativeLayerWayland register main thread callback to clean up 278 // and release itself. 279 // 4) Child NativeLayerWayland unref itself and parent NativeLayerRootWayland. 280 // 5) NativeLayerRootWayland is released when there isn't any 281 // NativeLayerWayland left. 282 // 283 RefPtr<NativeLayerRootWayland> mRootLayer; 284 285 RefPtr<widget::WaylandSurface> mSurface; 286 287 // Final buffer which we attach to WaylandSurface 288 RefPtr<widget::WaylandBuffer> mFrontBuffer; 289 290 const bool mIsOpaque = false; 291 292 // Used at SetLayers() when we need to identify removed layers, new layers 293 // and layers removed but returned back. 294 // We're adding respective constants to mUsageCount for each layer 295 // so removed layers have usage count 1, newly added 2 and removed+added 3. 296 int mUsageCount = 0; 297 298 gfx::IntSize mSize; 299 gfx::IntPoint mPosition; 300 gfx::Matrix4x4 mTransform; 301 gfx::IntRect mDisplayRect; 302 Maybe<gfx::IntRect> mClipRect; 303 Maybe<gfx::RoundedRect> mRoundedClipRect; 304 gfx::SamplingFilter mSamplingFilter = gfx::SamplingFilter::POINT; 305 double mScale = 1.0f; 306 LayerState mState{}; 307 bool mSurfaceIsFlipped = false; 308 bool mIsHDR = false; 309 310 enum class MainThreadUpdate { 311 None, 312 Map, 313 Unmap, 314 }; 315 316 // Indicate that we need to finish surface map/unmap 317 // on main thread. 318 // We need to perform main thread unmap even if mapping on main thread 319 // is not finished, some main thread resources are created 320 // by WaylandSurface itself. 321 Atomic<MainThreadUpdate, mozilla::Relaxed> mNeedsMainThreadUpdate{ 322 MainThreadUpdate::None}; 323 }; 324 325 class NativeLayerWaylandRender final : public NativeLayerWayland { 326 public: 327 NativeLayerWaylandRender* AsNativeLayerWaylandRender() override { 328 return this; 329 } 330 331 RefPtr<gfx::DrawTarget> NextSurfaceAsDrawTarget( 332 const gfx::IntRect& aDisplayRect, const gfx::IntRegion& aUpdateRegion, 333 gfx::BackendType aBackendType) override; 334 Maybe<GLuint> NextSurfaceAsFramebuffer(const gfx::IntRect& aDisplayRect, 335 const gfx::IntRegion& aUpdateRegion, 336 bool aNeedsDepth) override; 337 void NotifySurfaceReady() override; 338 void AttachExternalImage(wr::RenderTextureHost* aExternalImage) override; 339 bool IsFrontBufferChanged() override; 340 341 NativeLayerWaylandRender(NativeLayerRootWayland* aRootLayer, 342 const gfx::IntSize& aSize, bool aIsOpaque, 343 SurfacePoolHandleWayland* aSurfacePoolHandle); 344 345 private: 346 ~NativeLayerWaylandRender() override; 347 348 void DiscardBackbuffersLocked(const widget::WaylandSurfaceLock& aProofOfLock, 349 bool aForce) override; 350 void ReadBackFrontBuffer(const widget::WaylandSurfaceLock& aProofOfLock); 351 bool CommitFrontBufferToScreenLocked( 352 const widget::WaylandSurfaceLock& aProofOfLock) override; 353 354 const RefPtr<SurfacePoolHandleWayland> mSurfacePoolHandle; 355 RefPtr<widget::WaylandBuffer> mInProgressBuffer; 356 gfx::IntRegion mDirtyRegion; 357 }; 358 359 class NativeLayerWaylandExternal final : public NativeLayerWayland { 360 public: 361 // Overridden methods 362 NativeLayerWaylandExternal* AsNativeLayerWaylandExternal() override { 363 return this; 364 } 365 RefPtr<gfx::DrawTarget> NextSurfaceAsDrawTarget( 366 const gfx::IntRect& aDisplayRect, const gfx::IntRegion& aUpdateRegion, 367 gfx::BackendType aBackendType) override; 368 Maybe<GLuint> NextSurfaceAsFramebuffer(const gfx::IntRect& aDisplayRect, 369 const gfx::IntRegion& aUpdateRegion, 370 bool aNeedsDepth) override; 371 void NotifySurfaceReady() override {}; 372 void AttachExternalImage(wr::RenderTextureHost* aExternalImage) override; 373 bool IsFrontBufferChanged() override; 374 RefPtr<DMABufSurface> GetSurface(); 375 376 NativeLayerWaylandExternal(NativeLayerRootWayland* aRootLayer, 377 bool aIsOpaque); 378 379 private: 380 ~NativeLayerWaylandExternal() override; 381 382 void DiscardBackbuffersLocked(const widget::WaylandSurfaceLock& aProofOfLock, 383 bool aForce) override; 384 void FreeUnusedBackBuffers(); 385 bool CommitFrontBufferToScreenLocked( 386 const widget::WaylandSurfaceLock& aProofOfLock) override; 387 388 RefPtr<wr::RenderDMABUFTextureHost> mTextureHost; 389 }; 390 391 } // namespace mozilla::layers 392 393 #endif // mozilla_layers_NativeLayerWayland_h