NativeLayerWayland.cpp (43933B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* 6 TODO: 7 - Better layers update mechanism - update only in changed layes and updated 8 properties. 9 - Create cache of mapped layers? 10 - Fix messages from SurfacePoolWayland() mPendingEntries num xxx 11 mPoolSizeLimit 25 Are we leaking pending entries? 12 - Implemented screenshotter 13 - Presentation feedback 14 - Fullscreen - handle differently 15 - Attach dmabuf feedback to dmabuf surfaces to get formats for direct scanout 16 - Don't use for tooltips/small menus etc. 17 18 Testing: 19 Mochitest test speeds 20 Fractional Scale 21 SW/HW rendering + VSync 22 */ 23 24 #include "mozilla/layers/NativeLayerWayland.h" 25 26 #include <dlfcn.h> 27 #include <utility> 28 #include <algorithm> 29 30 #include "gfxUtils.h" 31 #include "nsGtkUtils.h" 32 #include "GLContextProvider.h" 33 #include "GLBlitHelper.h" 34 #include "mozilla/gfx/DataSurfaceHelpers.h" 35 #include "mozilla/gfx/Logging.h" 36 #include "mozilla/gfx/gfxVars.h" 37 #include "mozilla/layers/SurfacePoolWayland.h" 38 #include "mozilla/StaticPrefs_widget.h" 39 #include "mozilla/webrender/RenderThread.h" 40 #include "mozilla/webrender/RenderDMABUFTextureHost.h" 41 #include "mozilla/widget/WaylandSurface.h" 42 #include "mozilla/StaticPrefs_widget.h" 43 44 #ifdef MOZ_LOGGING 45 # undef LOG 46 # undef LOGVERBOSE 47 # include "mozilla/Logging.h" 48 # include "nsTArray.h" 49 # include "Units.h" 50 extern mozilla::LazyLogModule gWidgetCompositorLog; 51 # define LOG(str, ...) \ 52 MOZ_LOG(gWidgetCompositorLog, mozilla::LogLevel::Debug, \ 53 ("%s: " str, GetDebugTag().get(), ##__VA_ARGS__)) 54 # define LOGVERBOSE(str, ...) \ 55 MOZ_LOG(gWidgetCompositorLog, mozilla::LogLevel::Verbose, \ 56 ("%s: " str, GetDebugTag().get(), ##__VA_ARGS__)) 57 # define LOGS(str, ...) \ 58 MOZ_LOG(gWidgetCompositorLog, mozilla::LogLevel::Debug, \ 59 (str, ##__VA_ARGS__)) 60 #else 61 # define LOG(args) 62 #endif /* MOZ_LOGGING */ 63 64 using namespace mozilla; 65 using namespace mozilla::widget; 66 67 namespace mozilla::layers { 68 69 using gfx::BackendType; 70 using gfx::DrawTarget; 71 using gfx::IntPoint; 72 using gfx::IntRect; 73 using gfx::IntRegion; 74 using gfx::IntSize; 75 using gfx::Matrix4x4; 76 using gfx::Point; 77 using gfx::Rect; 78 using gfx::SamplingFilter; 79 using gfx::Size; 80 81 #ifdef MOZ_LOGGING 82 nsAutoCString NativeLayerRootWayland::GetDebugTag() const { 83 nsAutoCString tag; 84 tag.AppendPrintf("W[%p]R[%p]", mLoggingWidget, this); 85 return tag; 86 } 87 88 nsAutoCString NativeLayerWayland::GetDebugTag() const { 89 nsAutoCString tag; 90 tag.AppendPrintf("W[%p]R[%p]L[%p]", mRootLayer->GetLoggingWidget(), 91 mRootLayer.get(), this); 92 return tag; 93 } 94 #endif 95 96 /* static */ 97 already_AddRefed<NativeLayerRootWayland> NativeLayerRootWayland::Create( 98 RefPtr<WaylandSurface> aWaylandSurface) { 99 return MakeAndAddRef<NativeLayerRootWayland>(std::move(aWaylandSurface)); 100 } 101 102 void NativeLayerRootWayland::Init() { 103 mTmpBuffer = widget::WaylandBufferSHM::Create(LayoutDeviceIntSize(1, 1)); 104 105 // Get DRM format for surfaces created by GBM. 106 if (!gfx::gfxVars::UseDMABufSurfaceExport()) { 107 RefPtr<DMABufFormats> formats = WaylandDisplayGet()->GetDMABufFormats(); 108 if (formats) { 109 if (!(mDRMFormat = formats->GetFormat(GBM_FORMAT_ARGB8888, 110 /* aScanoutFormat */ true))) { 111 LOGVERBOSE( 112 "NativeLayerRootWayland::Init() missing scanout format, use global " 113 "one"); 114 mDRMFormat = formats->GetFormat(GBM_FORMAT_ARGB8888, 115 /* aScanoutFormat */ false); 116 } 117 } 118 if (!mDRMFormat) { 119 LOGVERBOSE( 120 "NativeLayerRootWayland::Init() fallback to format without " 121 "modifiers"); 122 mDRMFormat = new DRMFormat(GBM_FORMAT_ARGB8888); 123 } 124 } 125 126 // Unmap all layers if nsWindow is unmapped 127 WaylandSurfaceLock lock(mRootSurface); 128 mRootSurface->SetUnmapCallbackLocked( 129 lock, [this, self = RefPtr{this}]() -> void { 130 LOG("NativeLayerRootWayland Unmap callback"); 131 WaylandSurfaceLock lock(mRootSurface); 132 for (RefPtr<NativeLayerWayland>& layer : mSublayers) { 133 if (layer->IsMapped()) { 134 layer->Unmap(); 135 layer->MainThreadUnmap(); 136 } 137 } 138 }); 139 140 mRootSurface->SetGdkCommitCallbackLocked( 141 lock, [this, self = RefPtr{this}]() -> void { 142 LOGVERBOSE("GdkCommitCallback()"); 143 // Try to update on main thread if we 144 // need it 145 UpdateLayersOnMainThread(); 146 }); 147 148 // Propagate frame callback state (enabled/disabled) to all layers 149 // to save resources. 150 mRootSurface->SetFrameCallbackStateHandlerLocked( 151 lock, [this, self = RefPtr{this}](bool aState) -> void { 152 LOGVERBOSE("FrameCallbackStateHandler()"); 153 mRootSurface->AssertCurrentThreadOwnsMutex(); 154 for (RefPtr<NativeLayerWayland>& layer : mSublayers) { 155 layer->SetFrameCallbackState(aState); 156 } 157 }); 158 159 // Get the best DMABuf format for root wl_surface. We use the same 160 // for child surfaces as we expect them to share the same window/monitor. 161 // 162 // Using suboptimal format doesn't cause any functional/visual issue 163 // but may lead to worse performance as Wayland compositor may need 164 // to convert it for direct scanout. 165 // 166 // TODO: Recreate (Unmap/Map and Dispose buffers) child surfaces 167 // if there's format table refresh. 168 // 169 // Use on nightly only as it's not implemented yet by compositors 170 // to get scanout formats for non-fullscreen surfaces. 171 #ifdef NIGHTLY_BUILD 172 if (!gfx::gfxVars::UseDMABufSurfaceExport() && 173 StaticPrefs::widget_dmabuf_feedback_enabled_AtStartup()) { 174 mRootSurface->EnableDMABufFormatsLocked(lock, [this, self = RefPtr{this}]( 175 DMABufFormats* aFormats) { 176 if (DRMFormat* format = aFormats->GetFormat(GBM_FORMAT_ARGB8888, 177 /* aScanoutFormat */ true)) { 178 LOG("NativeLayerRootWayland DMABuf format refresh: we have scanout " 179 "format."); 180 mDRMFormat = format; 181 return; 182 } 183 if (DRMFormat* format = aFormats->GetFormat(GBM_FORMAT_ARGB8888, 184 /* aScanoutFormat */ false)) { 185 LOG("NativeLayerRootWayland DMABuf format refresh: missing scanout " 186 "format, use generic one."); 187 mDRMFormat = format; 188 return; 189 } 190 LOG("NativeLayerRootWayland DMABuf format refresh: missing DRM " 191 "format!"); 192 }); 193 } 194 #endif 195 } 196 197 void NativeLayerRootWayland::Shutdown() { 198 LOG("NativeLayerRootWayland::Shutdown()"); 199 AssertIsOnMainThread(); 200 201 UpdateLayersOnMainThread(); 202 203 { 204 WaylandSurfaceLock lock(mRootSurface); 205 if (mRootSurface->IsMapped()) { 206 mRootSurface->RemoveAttachedBufferLocked(lock); 207 } 208 mRootSurface->ClearUnmapCallbackLocked(lock); 209 mRootSurface->ClearGdkCommitCallbackLocked(lock); 210 mRootSurface->DisableDMABufFormatsLocked(lock); 211 } 212 213 mRootSurface = nullptr; 214 mTmpBuffer = nullptr; 215 mDRMFormat = nullptr; 216 } 217 218 NativeLayerRootWayland::NativeLayerRootWayland( 219 RefPtr<WaylandSurface> aWaylandSurface) 220 : mRootSurface(aWaylandSurface) { 221 #ifdef MOZ_LOGGING 222 mLoggingWidget = mRootSurface->GetLoggingWidget(); 223 mRootSurface->SetLoggingWidget(this); 224 LOG("NativeLayerRootWayland::NativeLayerRootWayland() nsWindow [%p] mapped " 225 "%d", 226 mLoggingWidget, mRootSurface->IsMapped()); 227 #endif 228 if (!WaylandSurface::IsOpaqueRegionEnabled()) { 229 NS_WARNING( 230 "Wayland opaque region disabled, expect poor rendering performance!"); 231 } 232 } 233 234 NativeLayerRootWayland::~NativeLayerRootWayland() { 235 LOG("NativeLayerRootWayland::~NativeLayerRootWayland()"); 236 MOZ_DIAGNOSTIC_ASSERT( 237 !mRootSurface, 238 "NativeLayerRootWayland destroyed without Shutdown() call!"); 239 } 240 241 #ifdef MOZ_LOGGING 242 void* NativeLayerRootWayland::GetLoggingWidget() const { 243 return mLoggingWidget; 244 } 245 #endif 246 247 // Create layer for rendering to layer/surface so get blank one from 248 // surface pool. 249 already_AddRefed<NativeLayer> NativeLayerRootWayland::CreateLayer( 250 const IntSize& aSize, bool aIsOpaque, 251 SurfacePoolHandle* aSurfacePoolHandle) { 252 LOG("NativeLayerRootWayland::CreateLayer() [%d x %d] nsWindow [%p] opaque %d", 253 aSize.width, aSize.height, GetLoggingWidget(), aIsOpaque); 254 return MakeAndAddRef<NativeLayerWaylandRender>( 255 this, aSize, aIsOpaque, aSurfacePoolHandle->AsSurfacePoolHandleWayland()); 256 } 257 258 already_AddRefed<NativeLayer> 259 NativeLayerRootWayland::CreateLayerForExternalTexture(bool aIsOpaque) { 260 LOG("NativeLayerRootWayland::CreateLayerForExternalTexture() nsWindow [%p] " 261 "opaque %d", 262 GetLoggingWidget(), aIsOpaque); 263 return MakeAndAddRef<NativeLayerWaylandExternal>(this, aIsOpaque); 264 } 265 266 void NativeLayerRootWayland::AppendLayer(NativeLayer* aLayer) { 267 MOZ_CRASH("NativeLayerRootWayland::AppendLayer() not implemented."); 268 } 269 270 void NativeLayerRootWayland::RemoveLayer(NativeLayer* aLayer) { 271 MOZ_CRASH("NativeLayerRootWayland::RemoveLayer() not implemented."); 272 } 273 274 bool NativeLayerRootWayland::IsEmptyLocked( 275 const WaylandSurfaceLock& aProofOfLock) { 276 return mSublayers.IsEmpty(); 277 } 278 279 void NativeLayerRootWayland::ClearLayersLocked( 280 const widget::WaylandSurfaceLock& aProofOfLock) { 281 LOG("NativeLayerRootWayland::ClearLayersLocked() layers num [%d]", 282 (int)mRemovedSublayers.Length()); 283 for (const RefPtr<NativeLayerWayland>& layer : mRemovedSublayers) { 284 LOG(" Unmap removed child layer [%p]", layer.get()); 285 layer->Unmap(); 286 } 287 mMainThreadUpdateSublayers.AppendElements(std::move(mRemovedSublayers)); 288 RequestUpdateOnMainThreadLocked(aProofOfLock); 289 } 290 291 void NativeLayerRootWayland::SetLayers( 292 const nsTArray<RefPtr<NativeLayer>>& aLayers) { 293 // Removing all layers can destroy us so hold ref 294 RefPtr<NativeLayerRoot> kungfuDeathGrip = this; 295 296 WaylandSurfaceLock lock(mRootSurface); 297 298 // Take shortcut if all layers are removed 299 if (aLayers.IsEmpty()) { 300 mRemovedSublayers.AppendElements(std::move(mSublayers)); 301 ClearLayersLocked(lock); 302 return; 303 } 304 305 nsTArray<RefPtr<NativeLayerWayland>> newLayers(aLayers.Length()); 306 for (const RefPtr<NativeLayer>& sublayer : aLayers) { 307 RefPtr<NativeLayerWayland> layer = sublayer->AsNativeLayerWayland(); 308 layer->MarkClear(); 309 newLayers.AppendElement(std::move(layer)); 310 } 311 312 if (newLayers == mSublayers) { 313 return; 314 } 315 316 LOG("NativeLayerRootWayland::SetLayers(), old layers num %d new layers num " 317 "%d", 318 (int)mSublayers.Length(), (int)aLayers.Length()); 319 320 // newLayers (aLayers) is a mix of old (already used) and new layers. 321 // We need to go through recent layers and remove the ones missing 322 // in new layers. 323 for (const RefPtr<NativeLayerWayland>& layer : mSublayers) { 324 layer->MarkRemoved(); 325 } 326 for (const RefPtr<NativeLayerWayland>& layer : newLayers) { 327 layer->MarkAdded(); 328 } 329 330 for (const RefPtr<NativeLayerWayland>& layer : mSublayers) { 331 if (layer->IsRemoved()) { 332 LOG(" Unmap removed child layer [%p]", layer.get()); 333 mRemovedSublayers.AppendElement(layer); 334 } 335 } 336 337 // Map newly added layers only if root surface itself is mapped. 338 // We lock it to make sure root surface stays mapped. 339 lock.RequestForceCommit(); 340 341 if (mRootSurface->IsMapped()) { 342 for (const RefPtr<NativeLayerWayland>& layer : newLayers) { 343 if (layer->IsNew()) { 344 LOG(" Map new child layer [%p]", layer.get()); 345 if (!layer->Map(&lock)) { 346 continue; 347 } 348 if (layer->IsOpaque() && WaylandSurface::IsOpaqueRegionEnabled()) { 349 LOG(" adding new opaque layer [%p]", layer.get()); 350 mMainThreadUpdateSublayers.AppendElement(layer); 351 } 352 } 353 } 354 } 355 356 mSublayers = std::move(newLayers); 357 mRootMutatedStackingOrder = true; 358 359 mRootAllLayersRendered = false; 360 mRootSurface->SetCommitStateLocked(lock, mRootAllLayersRendered); 361 362 // We need to process a part of map event on main thread as we use Gdk 363 // code there. Ask for the processing now. 364 RequestUpdateOnMainThreadLocked(lock); 365 } 366 367 // Update layers on main thread. Missing the main thread update is not critical 368 // but may lead to worse performance as we tell Gdk to skip compositing opaque 369 // surfaces. 370 void NativeLayerRootWayland::UpdateLayersOnMainThread() { 371 AssertIsOnMainThread(); 372 373 // We're called after Shutdown so do nothing. 374 if (!mRootSurface) { 375 return; 376 } 377 378 LOG("NativeLayerRootWayland::UpdateLayersOnMainThread()"); 379 WaylandSurfaceLock lock(mRootSurface); 380 for (const RefPtr<NativeLayerWayland>& layer : mMainThreadUpdateSublayers) { 381 LOGVERBOSE("NativeLayerRootWayland::UpdateLayersOnMainThread() [%p]", 382 layer.get()); 383 layer->UpdateOnMainThread(); 384 } 385 mMainThreadUpdateSublayers.Clear(); 386 mMainThreadUpdateQueued = false; 387 } 388 389 void NativeLayerRootWayland::RequestUpdateOnMainThreadLocked( 390 const WaylandSurfaceLock& aProofOfLock) { 391 if (!mMainThreadUpdateSublayers.Length() || mMainThreadUpdateQueued) { 392 return; 393 } 394 mMainThreadUpdateQueued = true; 395 396 LOG("NativeLayerRootWayland::RequestUpdateOnMainThreadLocked()"); 397 nsCOMPtr<nsIRunnable> updateLayersRunnable = NewRunnableMethod<>( 398 "layers::NativeLayerRootWayland::UpdateLayersOnMainThread", this, 399 &NativeLayerRootWayland::UpdateLayersOnMainThread); 400 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThreadQueue( 401 updateLayersRunnable.forget(), EventQueuePriority::Normal)); 402 } 403 404 #ifdef MOZ_LOGGING 405 void NativeLayerRootWayland::LogStatsLocked( 406 const WaylandSurfaceLock& aProofOfLock) { 407 if (!MOZ_LOG_TEST(gWidgetCompositorLog, mozilla::LogLevel::Verbose)) { 408 return; 409 } 410 411 int layersNum = 0; 412 int layersMapped = 0; 413 int layersMappedOpaque = 0; 414 int layersMappedOpaqueSet = 0; 415 int layersBufferAttached = 0; 416 int layersVisible = 0; 417 int layersRendered = 0; 418 int layersRenderedLastCycle = 0; 419 420 for (RefPtr<NativeLayerWayland>& layer : mSublayers) { 421 layersNum++; 422 if (layer->IsMapped()) { 423 layersMapped++; 424 } 425 if (layer->GetWaylandSurface()->HasBufferAttached()) { 426 layersBufferAttached++; 427 } 428 if (layer->IsMapped() && layer->IsOpaque()) { 429 layersMappedOpaque++; 430 if (layer->GetWaylandSurface()->IsOpaqueSurfaceHandlerSet()) { 431 layersMappedOpaqueSet++; 432 } 433 } 434 if (layer->State()->mIsVisible) { 435 layersVisible++; 436 } 437 if (layer->State()->mIsRendered) { 438 layersRendered++; 439 } 440 if (layer->State()->mRenderedLastCycle) { 441 layersRenderedLastCycle++; 442 } 443 } 444 LOGVERBOSE( 445 "Rendering stats: all rendered [%d] layers [%d] mapped [%d] attached " 446 "[%d] visible [%d] " 447 "rendered [%d] last [%d] opaque [%d] opaque set [%d] fullscreen [%d]", 448 mRootAllLayersRendered, layersNum, layersMapped, layersBufferAttached, 449 layersVisible, layersRendered, layersRenderedLastCycle, 450 layersMappedOpaque, layersMappedOpaqueSet, mIsFullscreen); 451 } 452 #endif 453 454 bool NativeLayerRootWayland::CommitToScreen() { 455 WaylandSurfaceLock lock(mRootSurface); 456 457 mFrameInProcess = false; 458 459 if (!mRootSurface->IsMapped()) { 460 // TODO: Register frame callback to paint again? Are we hidden? 461 LOG("NativeLayerRootWayland::CommitToScreen() root surface is not mapped"); 462 return false; 463 } 464 465 LOG("NativeLayerRootWayland::CommitToScreen()"); 466 467 // Attach empty tmp buffer to root layer (nsWindow). 468 // We need to have any content to attach child layers to it. 469 if (!mRootSurface->HasBufferAttached()) { 470 mRootSurface->AttachLocked(lock, mTmpBuffer); 471 mRootSurface->ClearOpaqueRegionLocked(lock); 472 } 473 474 // Try to map all missing surfaces 475 for (RefPtr<NativeLayerWayland>& layer : mSublayers) { 476 if (!layer->IsMapped()) { 477 if (!layer->Map(&lock)) { 478 LOGVERBOSE( 479 "NativeLayerRootWayland::CommitToScreen() failed to map layer [%p]", 480 layer.get()); 481 continue; 482 } 483 if (layer->IsOpaque() && WaylandSurface::IsOpaqueRegionEnabled()) { 484 mMainThreadUpdateSublayers.AppendElement(layer); 485 } 486 mRootMutatedStackingOrder = true; 487 } 488 } 489 490 if (mRootMutatedStackingOrder) { 491 RequestUpdateOnMainThreadLocked(lock); 492 } 493 494 const double scale = mRootSurface->GetScale(); 495 mRootAllLayersRendered = true; 496 for (RefPtr<NativeLayerWayland>& layer : mSublayers) { 497 layer->RenderLayer(scale); 498 if (layer->State()->mMutatedStackingOrder) { 499 mRootMutatedStackingOrder = true; 500 } 501 if (layer->State()->mIsVisible && !layer->State()->mIsRendered) { 502 LOG("NativeLayerRootWayland::CommitToScreen() layer [%p] is not rendered", 503 layer.get()); 504 mRootAllLayersRendered = false; 505 } 506 } 507 508 if (mRootMutatedStackingOrder) { 509 LOGVERBOSE( 510 "NativeLayerRootWayland::CommitToScreen(): changed stacking order"); 511 NativeLayerWayland* previousWaylandSurface = nullptr; 512 for (RefPtr<NativeLayerWayland>& layer : mSublayers) { 513 if (layer->State()->mIsVisible) { 514 MOZ_DIAGNOSTIC_ASSERT(layer->IsMapped()); 515 if (previousWaylandSurface) { 516 layer->PlaceAbove(previousWaylandSurface); 517 } 518 previousWaylandSurface = layer; 519 } 520 layer->State()->mMutatedStackingOrder = false; 521 } 522 mRootMutatedStackingOrder = false; 523 } 524 525 LOGVERBOSE("NativeLayerRootWayland::CommitToScreen(): %s root commit", 526 mRootAllLayersRendered ? "enabled" : "disabled"); 527 mRootSurface->SetCommitStateLocked(lock, mRootAllLayersRendered); 528 529 #ifdef MOZ_LOGGING 530 LogStatsLocked(lock); 531 #endif 532 533 // Commit all layers changes now so we can unmap removed layers without 534 // flickering. 535 lock.Commit(); 536 537 if (mRootAllLayersRendered && !mRemovedSublayers.IsEmpty()) { 538 ClearLayersLocked(lock); 539 } 540 541 return true; 542 } 543 544 // Ready-to-paint signal from root or child surfaces. Route it to 545 // root WaylandSurface (owned by nsWindow) where it's used to fire VSync. 546 void NativeLayerRootWayland::FrameCallbackHandler(uint32_t aTime) { 547 { 548 // Child layer wl_subsurface already requested next frame callback 549 // and we need to commit to root surface too as we're in 550 // wl_subsurface synced mode. 551 WaylandSurfaceLock lock(mRootSurface); 552 } 553 554 if (aTime <= mLastFrameCallbackTime) { 555 LOGVERBOSE( 556 "NativeLayerRootWayland::FrameCallbackHandler() ignoring redundant " 557 "callback %d", 558 aTime); 559 return; 560 } 561 mLastFrameCallbackTime = aTime; 562 563 LOGVERBOSE("NativeLayerRootWayland::FrameCallbackHandler() time %d", aTime); 564 mRootSurface->FrameCallbackHandler(nullptr, aTime, 565 /* aRoutedFromChildSurface */ true); 566 } 567 568 // We don't need to lock access to GdkWindow() as we process all Gdk/Gtk 569 // events on main thread only. 570 GdkWindow* NativeLayerRootWayland::GetGdkWindow() const { 571 AssertIsOnMainThread(); 572 return mRootSurface->GetGdkWindow(); 573 } 574 575 // Try to match stored wl_buffer with provided DMABufSurface or create 576 // a new one. 577 RefPtr<WaylandBuffer> NativeLayerRootWayland::BorrowExternalBuffer( 578 RefPtr<DMABufSurface> aDMABufSurface) { 579 LOG("NativeLayerRootWayland::BorrowExternalBuffer() WaylandSurface [%p] UID " 580 "%d PID %d mExternalBuffers num %d", 581 aDMABufSurface.get(), aDMABufSurface->GetUID(), aDMABufSurface->GetPID(), 582 (int)mExternalBuffers.Length()); 583 584 RefPtr waylandBuffer = 585 widget::WaylandBufferDMABUF::CreateExternal(aDMABufSurface); 586 for (auto& b : mExternalBuffers) { 587 if (b.Matches(aDMABufSurface)) { 588 LOG("NativeLayerRootWayland::BorrowExternalBuffer() wl_buffer matches, " 589 "recycling"); 590 waylandBuffer->SetExternalWLBuffer(b.GetWLBuffer()); 591 return waylandBuffer.forget(); 592 } 593 } 594 595 wl_buffer* wlbuffer = waylandBuffer->CreateWlBuffer(); 596 if (!wlbuffer) { 597 return nullptr; 598 } 599 600 LOG("NativeLayerRootWayland::BorrowExternalBuffer() adding new wl_buffer"); 601 waylandBuffer->SetExternalWLBuffer(wlbuffer); 602 mExternalBuffers.EmplaceBack(aDMABufSurface, wlbuffer); 603 return waylandBuffer.forget(); 604 } 605 606 NativeLayerWayland::NativeLayerWayland(NativeLayerRootWayland* aRootLayer, 607 const IntSize& aSize, bool aIsOpaque) 608 : mRootLayer(aRootLayer), mIsOpaque(aIsOpaque), mSize(aSize) { 609 mSurface = new WaylandSurface(mRootLayer->GetRootWaylandSurface()); 610 #ifdef MOZ_LOGGING 611 mSurface->SetLoggingWidget(this); 612 #endif 613 LOG("NativeLayerWayland::NativeLayerWayland() WaylandSurface [%p] size [%d, " 614 "%d] opaque %d", 615 mSurface.get(), mSize.width, mSize.height, aIsOpaque); 616 617 mState.mMutatedStackingOrder = true; 618 mState.mMutatedPlacement = true; 619 } 620 621 NativeLayerWayland::~NativeLayerWayland() { 622 LOG("NativeLayerWayland::~NativeLayerWayland() IsMapped %d", 623 mSurface->IsMapped()); 624 MOZ_RELEASE_ASSERT(!mSurface->IsMapped(), "Releasing mapped surface!"); 625 } 626 627 bool NativeLayerWayland::IsMapped() { return mSurface->IsMapped(); } 628 629 void NativeLayerWayland::SetSurfaceIsFlipped(bool aIsFlipped) { 630 WaylandSurfaceLock lock(mSurface); 631 if (aIsFlipped != mSurfaceIsFlipped) { 632 mSurfaceIsFlipped = aIsFlipped; 633 mState.mMutatedPlacement = true; 634 } 635 } 636 637 bool NativeLayerWayland::SurfaceIsFlipped() { 638 WaylandSurfaceLock lock(mSurface); 639 return mSurfaceIsFlipped; 640 } 641 642 IntSize NativeLayerWayland::GetSize() { 643 WaylandSurfaceLock lock(mSurface); 644 return mSize; 645 } 646 647 void NativeLayerWayland::SetPosition(const IntPoint& aPosition) { 648 WaylandSurfaceLock lock(mSurface); 649 if (aPosition != mPosition) { 650 LOG("NativeLayerWayland::SetPosition() [%d, %d]", (int)aPosition.x, 651 (int)aPosition.y); 652 mPosition = aPosition; 653 mState.mMutatedPlacement = true; 654 } 655 } 656 657 IntPoint NativeLayerWayland::GetPosition() { 658 WaylandSurfaceLock lock(mSurface); 659 return mPosition; 660 } 661 662 void NativeLayerWayland::PlaceAbove(NativeLayerWayland* aLowerLayer) { 663 WaylandSurfaceLock lock(mSurface); 664 WaylandSurfaceLock lowerSurfacelock(aLowerLayer->mSurface); 665 666 MOZ_DIAGNOSTIC_ASSERT(IsMapped()); 667 MOZ_DIAGNOSTIC_ASSERT(aLowerLayer->IsMapped()); 668 MOZ_DIAGNOSTIC_ASSERT(this != aLowerLayer); 669 670 mSurface->PlaceAboveLocked(lock, lowerSurfacelock); 671 mState.mMutatedStackingOrder = true; 672 } 673 674 void NativeLayerWayland::SetTransform(const Matrix4x4& aTransform) { 675 WaylandSurfaceLock lock(mSurface); 676 MOZ_DIAGNOSTIC_ASSERT(aTransform.IsRectilinear()); 677 if (aTransform != mTransform) { 678 mTransform = aTransform; 679 mState.mMutatedPlacement = true; 680 } 681 } 682 683 void NativeLayerWayland::SetSamplingFilter( 684 gfx::SamplingFilter aSamplingFilter) { 685 WaylandSurfaceLock lock(mSurface); 686 if (aSamplingFilter != mSamplingFilter) { 687 mSamplingFilter = aSamplingFilter; 688 } 689 } 690 691 Matrix4x4 NativeLayerWayland::GetTransform() { 692 WaylandSurfaceLock lock(mSurface); 693 return mTransform; 694 } 695 696 IntRect NativeLayerWayland::GetRect() { 697 WaylandSurfaceLock lock(mSurface); 698 return IntRect(mPosition, mSize); 699 } 700 701 // TODO: remove lock? 702 bool NativeLayerWayland::IsOpaque() { 703 WaylandSurfaceLock lock(mSurface); 704 return mIsOpaque; 705 } 706 707 void NativeLayerWayland::SetClipRect(const Maybe<IntRect>& aClipRect) { 708 WaylandSurfaceLock lock(mSurface); 709 if (aClipRect != mClipRect) { 710 #if MOZ_LOGGING 711 if (aClipRect) { 712 gfx::IntRect rect(aClipRect.value()); 713 LOG("NativeLayerWaylandRender::SetClipRect() [%d,%d] -> [%d x %d]", 714 rect.x, rect.y, rect.width, rect.height); 715 } 716 #endif 717 mClipRect = aClipRect; 718 mState.mMutatedPlacement = true; 719 } 720 } 721 722 Maybe<IntRect> NativeLayerWayland::ClipRect() { 723 WaylandSurfaceLock lock(mSurface); 724 return mClipRect; 725 } 726 727 void NativeLayerWayland::SetRoundedClipRect( 728 const Maybe<gfx::RoundedRect>& aClip) { 729 WaylandSurfaceLock lock(mSurface); 730 if (aClip != mRoundedClipRect) { 731 // TODO(gw): Support rounded clips on wayland 732 mRoundedClipRect = aClip; 733 } 734 } 735 736 Maybe<gfx::RoundedRect> NativeLayerWayland::RoundedClipRect() { 737 WaylandSurfaceLock lock(mSurface); 738 return mRoundedClipRect; 739 } 740 741 IntRect NativeLayerWayland::CurrentSurfaceDisplayRect() { 742 WaylandSurfaceLock lock(mSurface); 743 return mDisplayRect; 744 } 745 746 void NativeLayerWayland::SetScalelocked( 747 const widget::WaylandSurfaceLock& aProofOfLock, double aScale) { 748 MOZ_DIAGNOSTIC_ASSERT(aScale > 0); 749 if (aScale != mScale) { 750 mScale = aScale; 751 mState.mMutatedPlacement = true; 752 } 753 } 754 755 void NativeLayerWayland::UpdateLayerPlacementLocked( 756 const widget::WaylandSurfaceLock& aProofOfLock) { 757 // It's possible that NativeLayerWayland is unmapped/waiting to unmap. 758 if (!IsMapped()) { 759 return; 760 } 761 762 if (!mState.mMutatedPlacement) { 763 return; 764 } 765 mState.mMutatedPlacement = false; 766 767 LOGVERBOSE("NativeLayerWayland::UpdateLayerPlacementLocked()"); 768 769 MOZ_RELEASE_ASSERT(mTransform.Is2D()); 770 auto transform2D = mTransform.As2D(); 771 772 Rect surfaceRectClipped = Rect(0, 0, (float)mSize.width, (float)mSize.height); 773 surfaceRectClipped = surfaceRectClipped.Intersect(Rect(mDisplayRect)); 774 775 transform2D.PostTranslate((float)mPosition.x, (float)mPosition.y); 776 surfaceRectClipped = transform2D.TransformBounds(surfaceRectClipped); 777 778 if (mClipRect) { 779 surfaceRectClipped = surfaceRectClipped.Intersect(Rect(mClipRect.value())); 780 } 781 782 const bool visible = !surfaceRectClipped.IsEmpty(); 783 if (mState.mIsVisible != visible) { 784 mState.mIsVisible = visible; 785 mState.mMutatedVisibility = true; 786 mState.mMutatedStackingOrder = true; 787 if (!mState.mIsVisible) { 788 LOGVERBOSE("NativeLayerWayland become hidden"); 789 mSurface->RemoveAttachedBufferLocked(aProofOfLock); 790 return; 791 } 792 LOGVERBOSE("NativeLayerWayland become visible"); 793 } 794 795 mSurface->SetTransformFlippedLocked(aProofOfLock, transform2D._11 < 0.0, 796 transform2D._22 < 0.0); 797 798 // TODO! Downscale introduces rounding errors here. 799 auto unscaledRect = 800 gfx::RoundedToInt(surfaceRectClipped / UnknownScaleFactor(mScale)); 801 auto rect = DesktopIntRect::FromUnknownRect(unscaledRect); 802 mSurface->MoveLocked(aProofOfLock, rect.TopLeft()); 803 mSurface->SetViewPortDestLocked(aProofOfLock, rect.Size()); 804 805 LOGVERBOSE( 806 "NativeLayerWayland::UpdateLayerPlacement(): destination [%d,%d] -> [%d " 807 "x %d]", 808 rect.x, rect.y, rect.width, rect.height); 809 810 auto transform2DInversed = transform2D.Inverse(); 811 Rect bufferClip = transform2DInversed.TransformBounds(surfaceRectClipped); 812 auto viewportRect = gfx::RoundedToInt( 813 bufferClip.Intersect(Rect(0, 0, mSize.width, mSize.height))); 814 815 LOGVERBOSE( 816 "NativeLayerWayland::UpdateLayerPlacement(): source [%d,%d] -> [%d x %d]", 817 viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height); 818 819 mSurface->SetViewPortSourceRectLocked( 820 aProofOfLock, DesktopIntRect::FromUnknownRect(viewportRect)); 821 } 822 823 void NativeLayerWayland::RenderLayer(double aScale) { 824 WaylandSurfaceLock lock(mSurface); 825 826 LOG("NativeLayerWayland::RenderLayer()"); 827 828 SetScalelocked(lock, aScale); 829 UpdateLayerPlacementLocked(lock); 830 831 mState.mRenderedLastCycle = false; 832 833 // Don't operate over hidden layers 834 if (!mState.mIsVisible) { 835 LOG("NativeLayerWayland::RenderLayer() quit, not visible"); 836 return; 837 } 838 839 // Return if front buffer didn't changed (or changed area is empty) 840 // and there isn't any visibility change. 841 if (!IsFrontBufferChanged() && !mState.mMutatedVisibility) { 842 LOG("NativeLayerWayland::RenderLayer() quit " 843 "IsFrontBufferChanged [%d] " 844 "mState.mMutatedVisibility [%d] rendered [%d]", 845 IsFrontBufferChanged(), mState.mMutatedVisibility, mState.mIsRendered); 846 return; 847 } 848 849 if (!mFrontBuffer) { 850 LOG("NativeLayerWayland::RenderLayer() - missing front buffer!"); 851 return; 852 } 853 854 mState.mIsRendered = mState.mRenderedLastCycle = 855 CommitFrontBufferToScreenLocked(lock); 856 857 mState.mMutatedFrontBuffer = false; 858 mState.mMutatedVisibility = false; 859 860 if (mState.mIsVisible) { 861 MOZ_DIAGNOSTIC_ASSERT(mSurface->HasBufferAttached()); 862 } 863 864 LOG("NativeLayerWayland::RenderLayer(): rendered [%d]", mState.mIsRendered); 865 } 866 867 bool NativeLayerWayland::Map(WaylandSurfaceLock* aParentWaylandSurfaceLock) { 868 WaylandSurfaceLock surfaceLock(mSurface); 869 870 if (mNeedsMainThreadUpdate == MainThreadUpdate::Unmap) { 871 LOG("NativeLayerWayland::Map() waiting to MainThreadUpdate::Unmap"); 872 return false; 873 } 874 875 LOG("NativeLayerWayland::Map() parent %p", mRootLayer.get()); 876 877 MOZ_DIAGNOSTIC_ASSERT(!mSurface->IsMapped()); 878 MOZ_DIAGNOSTIC_ASSERT(mNeedsMainThreadUpdate != MainThreadUpdate::Map); 879 880 if (!mSurface->MapLocked(surfaceLock, aParentWaylandSurfaceLock, 881 DesktopIntPoint())) { 882 gfxCriticalError() << "NativeLayerWayland::Map() failed!"; 883 return false; 884 } 885 mSurface->DisableUserInputLocked(surfaceLock); 886 mSurface->CreateViewportLocked(surfaceLock, 887 /* aFollowsSizeChanges */ false); 888 889 // Route frame-to-paint (frame callback) from child layer to root layer 890 // where it's passed to Vsync. 891 // 892 // aTime param is used to identify duplicate events. 893 // 894 mSurface->SetFrameCallbackLocked( 895 surfaceLock, 896 [this, self = RefPtr{this}](wl_callback* aCallback, 897 uint32_t aTime) -> void { 898 LOGVERBOSE("NativeLayerWayland::FrameCallbackHandler() time %d", aTime); 899 mRootLayer->FrameCallbackHandler(aTime); 900 }, 901 /* aEmulateFrameCallback */ true); 902 903 if (mIsHDR) { 904 mSurface->EnableColorManagementLocked(surfaceLock); 905 } 906 907 if (auto* external = AsNativeLayerWaylandExternal()) { 908 if (RefPtr surface = external->GetSurface()) { 909 if (auto* surfaceYUV = surface->GetAsDMABufSurfaceYUV()) { 910 mSurface->SetColorRepresentationLocked( 911 surfaceLock, surfaceYUV->GetYUVColorSpace(), 912 surfaceYUV->IsFullRange(), surfaceYUV->GetWPChromaLocation()); 913 } 914 } 915 } 916 917 mNeedsMainThreadUpdate = MainThreadUpdate::Map; 918 mState.mMutatedStackingOrder = true; 919 mState.mMutatedVisibility = true; 920 mState.mMutatedPlacement = true; 921 mState.mIsRendered = false; 922 return true; 923 } 924 925 void NativeLayerWayland::SetFrameCallbackState(bool aState) { 926 LOGVERBOSE("NativeLayerWayland::SetFrameCallbackState() %d", aState); 927 WaylandSurfaceLock lock(mSurface); 928 mSurface->SetFrameCallbackStateLocked(lock, aState); 929 } 930 931 void NativeLayerWayland::MainThreadMap() { 932 AssertIsOnMainThread(); 933 MOZ_DIAGNOSTIC_ASSERT(IsOpaque()); 934 MOZ_DIAGNOSTIC_ASSERT(mNeedsMainThreadUpdate == MainThreadUpdate::Map); 935 936 WaylandSurfaceLock lock(mSurface); 937 if (!mSurface->IsOpaqueSurfaceHandlerSet()) { 938 // Don't register commit handler, we do it for all surfaces at 939 // GdkCommitCallback() handler. 940 mSurface->AddOpaqueSurfaceHandlerLocked(lock, mRootLayer->GetGdkWindow(), 941 /* aRegisterCommitHandler */ false); 942 mSurface->SetOpaqueLocked(lock); 943 mNeedsMainThreadUpdate = MainThreadUpdate::None; 944 } 945 } 946 947 void NativeLayerWayland::Unmap() { 948 WaylandSurfaceLock surfaceLock(mSurface); 949 950 if (!mSurface->IsMapped()) { 951 return; 952 } 953 954 LOG("NativeLayerWayland::Unmap()"); 955 956 mSurface->UnmapLocked(surfaceLock); 957 // Clear reference to this added at NativeLayerWayland::Map() by 958 // callback handler. 959 mSurface->ClearFrameCallbackHandlerLocked(surfaceLock); 960 mState.mMutatedStackingOrder = true; 961 mState.mMutatedVisibility = true; 962 mState.mIsRendered = false; 963 mState.mIsVisible = false; 964 DiscardBackbuffersLocked(surfaceLock); 965 mNeedsMainThreadUpdate = MainThreadUpdate::Unmap; 966 } 967 968 void NativeLayerWayland::MainThreadUnmap() { 969 WaylandSurfaceLock lock(mSurface); 970 971 MOZ_DIAGNOSTIC_ASSERT(mNeedsMainThreadUpdate == MainThreadUpdate::Unmap); 972 AssertIsOnMainThread(); 973 974 if (mSurface->IsPendingGdkCleanup()) { 975 mSurface->GdkCleanUpLocked(lock); 976 // TODO: Do we need to clear opaque region? 977 } 978 mNeedsMainThreadUpdate = MainThreadUpdate::None; 979 } 980 981 void NativeLayerWayland::UpdateOnMainThread() { 982 AssertIsOnMainThread(); 983 if (mNeedsMainThreadUpdate == MainThreadUpdate::None) { 984 return; 985 } 986 if (mNeedsMainThreadUpdate == MainThreadUpdate::Map) { 987 MainThreadMap(); 988 } else { 989 MainThreadUnmap(); 990 } 991 } 992 993 void NativeLayerWayland::DiscardBackbuffers() { 994 WaylandSurfaceLock lock(mSurface); 995 DiscardBackbuffersLocked(lock); 996 } 997 998 void NativeLayerWayland::ForceCommit() { 999 WaylandSurfaceLock lock(mSurface); 1000 if (mSurface->IsMapped()) { 1001 mSurface->CommitLocked(lock, /* force commit */ true); 1002 } 1003 } 1004 1005 NativeLayerWaylandRender::NativeLayerWaylandRender( 1006 NativeLayerRootWayland* aRootLayer, const IntSize& aSize, bool aIsOpaque, 1007 SurfacePoolHandleWayland* aSurfacePoolHandle) 1008 : NativeLayerWayland(aRootLayer, aSize, aIsOpaque), 1009 mSurfacePoolHandle(aSurfacePoolHandle) { 1010 MOZ_RELEASE_ASSERT(mSurfacePoolHandle, 1011 "Need a non-null surface pool handle."); 1012 } 1013 1014 void NativeLayerWaylandRender::AttachExternalImage( 1015 wr::RenderTextureHost* aExternalImage) { 1016 MOZ_CRASH("NativeLayerWaylandRender::AttachExternalImage() not implemented."); 1017 } 1018 1019 bool NativeLayerWaylandRender::IsFrontBufferChanged() { 1020 return mState.mMutatedFrontBuffer && !mDirtyRegion.IsEmpty(); 1021 } 1022 1023 RefPtr<DrawTarget> NativeLayerWaylandRender::NextSurfaceAsDrawTarget( 1024 const IntRect& aDisplayRect, const IntRegion& aUpdateRegion, 1025 BackendType aBackendType) { 1026 LOG("NativeLayerWaylandRender::NextSurfaceAsDrawTarget()"); 1027 1028 WaylandSurfaceLock lock(mSurface); 1029 1030 if (!mDisplayRect.IsEqualEdges(aDisplayRect)) { 1031 mDisplayRect = aDisplayRect; 1032 mState.mMutatedPlacement = true; 1033 } 1034 mDirtyRegion = aUpdateRegion; 1035 1036 MOZ_DIAGNOSTIC_ASSERT(!mInProgressBuffer); 1037 if (mFrontBuffer && !mFrontBuffer->IsAttached()) { 1038 LOGVERBOSE( 1039 "NativeLayerWaylandRender::NextSurfaceAsDrawTarget(): use front buffer " 1040 "for rendering"); 1041 // the Wayland compositor released the buffer early, we can reuse it 1042 mInProgressBuffer = std::move(mFrontBuffer); 1043 } else { 1044 LOGVERBOSE( 1045 "NativeLayerWaylandRender::NextSurfaceAsDrawTarget(): use progress " 1046 "buffer for rendering"); 1047 mInProgressBuffer = mSurfacePoolHandle->ObtainBufferFromPool( 1048 mSize, mRootLayer->GetDRMFormat()); 1049 if (mFrontBuffer) { 1050 LOGVERBOSE( 1051 "NativeLayerWaylandRender::NextSurfaceAsDrawTarget(): read-back from " 1052 "front buffer"); 1053 ReadBackFrontBuffer(lock); 1054 mSurfacePoolHandle->ReturnBufferToPool(mFrontBuffer); 1055 mFrontBuffer = nullptr; 1056 } 1057 } 1058 MOZ_DIAGNOSTIC_ASSERT(!mFrontBuffer); 1059 1060 if (!mInProgressBuffer) { 1061 gfxCriticalError() << "Failed to obtain buffer"; 1062 wr::RenderThread::Get()->HandleWebRenderError( 1063 wr::WebRenderError::NEW_SURFACE); 1064 return nullptr; 1065 } 1066 1067 MOZ_DIAGNOSTIC_ASSERT(!mInProgressBuffer->IsAttached(), 1068 "Reusing attached buffer!"); 1069 1070 return mInProgressBuffer->Lock(); 1071 } 1072 1073 Maybe<GLuint> NativeLayerWaylandRender::NextSurfaceAsFramebuffer( 1074 const IntRect& aDisplayRect, const IntRegion& aUpdateRegion, 1075 bool aNeedsDepth) { 1076 LOG("NativeLayerWaylandRender::NextSurfaceAsFramebuffer()"); 1077 1078 WaylandSurfaceLock lock(mSurface); 1079 1080 if (!mDisplayRect.IsEqualEdges(aDisplayRect)) { 1081 mDisplayRect = aDisplayRect; 1082 mState.mMutatedPlacement = true; 1083 } 1084 mDirtyRegion = IntRegion(aUpdateRegion); 1085 1086 MOZ_DIAGNOSTIC_ASSERT(!mInProgressBuffer); 1087 if (mFrontBuffer && !mFrontBuffer->IsAttached()) { 1088 LOGVERBOSE( 1089 "NativeLayerWaylandRender::NextSurfaceAsFramebuffer(): use front " 1090 "buffer for rendering"); 1091 // the Wayland compositor released the buffer early, we can reuse it 1092 mInProgressBuffer = std::move(mFrontBuffer); 1093 } else { 1094 LOGVERBOSE( 1095 "NativeLayerWaylandRender::NextSurfaceAsFramebuffer(): use progress " 1096 "buffer for rendering"); 1097 mInProgressBuffer = mSurfacePoolHandle->ObtainBufferFromPool( 1098 mSize, mRootLayer->GetDRMFormat()); 1099 } 1100 1101 MOZ_DIAGNOSTIC_ASSERT(mInProgressBuffer, 1102 "NativeLayerWaylandRender: Failed to obtain buffer"); 1103 if (!mInProgressBuffer) { 1104 return Nothing(); 1105 } 1106 1107 MOZ_DIAGNOSTIC_ASSERT(!mInProgressBuffer->IsAttached(), 1108 "Reusing attached buffer!"); 1109 1110 // get the framebuffer before handling partial damage so we don't accidently 1111 // create one without depth buffer 1112 Maybe<GLuint> fbo = mSurfacePoolHandle->GetFramebufferForBuffer( 1113 mInProgressBuffer, aNeedsDepth); 1114 MOZ_DIAGNOSTIC_ASSERT( 1115 fbo, "NativeLayerWaylandRender: Failed to create framebuffer!"); 1116 if (!fbo) { 1117 return Nothing(); 1118 } 1119 1120 if (mFrontBuffer) { 1121 LOGVERBOSE( 1122 "NativeLayerWaylandRender::NextSurfaceAsFramebuffer(): read-back from " 1123 "front buffer"); 1124 ReadBackFrontBuffer(lock); 1125 mSurfacePoolHandle->ReturnBufferToPool(mFrontBuffer); 1126 mFrontBuffer = nullptr; 1127 } 1128 1129 return fbo; 1130 } 1131 1132 // Front buffer is still used by compositor so we can't paint into it. 1133 // Read it back to progress buffer and paint next frame to progress buffer. 1134 void NativeLayerWaylandRender::ReadBackFrontBuffer( 1135 const WaylandSurfaceLock& aProofOfLock) { 1136 IntRegion copyRegion = IntRegion(mDisplayRect); 1137 copyRegion.SubOut(mDirtyRegion); 1138 1139 LOG("NativeLayerWaylandRender::ReadBackFrontBuffer()"); 1140 1141 if (!copyRegion.IsEmpty()) { 1142 if (mSurfacePoolHandle->gl()) { 1143 mSurfacePoolHandle->gl()->MakeCurrent(); 1144 for (auto iter = copyRegion.RectIter(); !iter.Done(); iter.Next()) { 1145 gfx::IntRect r = iter.Get(); 1146 Maybe<GLuint> sourceFB = 1147 mSurfacePoolHandle->GetFramebufferForBuffer(mFrontBuffer, false); 1148 MOZ_DIAGNOSTIC_ASSERT(sourceFB, 1149 "NativeLayerWaylandRender: Failed to get " 1150 "mFrontBuffer framebuffer!"); 1151 if (!sourceFB) { 1152 return; 1153 } 1154 Maybe<GLuint> destFB = mSurfacePoolHandle->GetFramebufferForBuffer( 1155 mInProgressBuffer, false); 1156 MOZ_DIAGNOSTIC_ASSERT(destFB, 1157 "NativeLayerWaylandRender: Failed to get " 1158 "mInProgressBuffer framebuffer!"); 1159 if (!destFB) { 1160 return; 1161 } 1162 mSurfacePoolHandle->gl()->BlitHelper()->BlitFramebufferToFramebuffer( 1163 sourceFB.value(), destFB.value(), r, r, LOCAL_GL_NEAREST); 1164 } 1165 } else { 1166 RefPtr<gfx::DataSourceSurface> dataSourceSurface = 1167 gfx::CreateDataSourceSurfaceFromData( 1168 mSize, mFrontBuffer->GetSurfaceFormat(), 1169 (const uint8_t*)mFrontBuffer->GetImageData(), 1170 mSize.width * BytesPerPixel(mFrontBuffer->GetSurfaceFormat())); 1171 RefPtr<DrawTarget> dt = mInProgressBuffer->Lock(); 1172 1173 for (auto iter = copyRegion.RectIter(); !iter.Done(); iter.Next()) { 1174 IntRect r = iter.Get(); 1175 dt->CopySurface(dataSourceSurface, r, IntPoint(r.x, r.y)); 1176 } 1177 } 1178 } 1179 } 1180 1181 bool NativeLayerWaylandRender::CommitFrontBufferToScreenLocked( 1182 const WaylandSurfaceLock& aProofOfLock) { 1183 // Don't operate over hidden layers 1184 LOG("NativeLayerWaylandRender::CommitFrontBufferToScreenLocked()"); 1185 1186 if (mState.mMutatedVisibility) { 1187 mSurface->InvalidateLocked(aProofOfLock); 1188 } else { 1189 mSurface->InvalidateRegionLocked(aProofOfLock, mDirtyRegion); 1190 } 1191 mDirtyRegion.SetEmpty(); 1192 1193 auto* buffer = mFrontBuffer->AsWaylandBufferDMABUF(); 1194 if (buffer) { 1195 buffer->GetSurface()->FenceWait(); 1196 } 1197 1198 mSurface->AttachLocked(aProofOfLock, mFrontBuffer); 1199 return true; 1200 } 1201 1202 void NativeLayerWaylandRender::NotifySurfaceReady() { 1203 LOG("NativeLayerWaylandRender::NotifySurfaceReady()"); 1204 1205 WaylandSurfaceLock lock(mSurface); 1206 1207 MOZ_DIAGNOSTIC_ASSERT(!mFrontBuffer); 1208 MOZ_DIAGNOSTIC_ASSERT(mInProgressBuffer); 1209 1210 mFrontBuffer = std::move(mInProgressBuffer); 1211 if (mSurfacePoolHandle->gl()) { 1212 auto* buffer = mFrontBuffer->AsWaylandBufferDMABUF(); 1213 if (buffer) { 1214 buffer->GetSurface()->FenceSet(); 1215 } 1216 mSurfacePoolHandle->gl()->FlushIfHeavyGLCallsSinceLastFlush(); 1217 } 1218 1219 mState.mMutatedFrontBuffer = true; 1220 } 1221 1222 void NativeLayerWaylandRender::DiscardBackbuffersLocked( 1223 const WaylandSurfaceLock& aProofOfLock, bool aForce) { 1224 LOGVERBOSE( 1225 "NativeLayerWaylandRender::DiscardBackbuffersLocked() force %d progress " 1226 "%p front %p", 1227 aForce, mInProgressBuffer.get(), mFrontBuffer.get()); 1228 if (mInProgressBuffer && (!mInProgressBuffer->IsAttached() || aForce)) { 1229 mSurfacePoolHandle->ReturnBufferToPool(mInProgressBuffer); 1230 mInProgressBuffer = nullptr; 1231 } 1232 if (mFrontBuffer && (!mFrontBuffer->IsAttached() || aForce)) { 1233 mSurfacePoolHandle->ReturnBufferToPool(mFrontBuffer); 1234 mFrontBuffer = nullptr; 1235 } 1236 } 1237 1238 NativeLayerWaylandRender::~NativeLayerWaylandRender() { 1239 LOG("NativeLayerWaylandRender::~NativeLayerWaylandRender()"); 1240 WaylandSurfaceLock lock(mSurface); 1241 DiscardBackbuffersLocked(lock, /* aForce */ true); 1242 } 1243 1244 RefPtr<DMABufSurface> NativeLayerWaylandExternal::GetSurface() { 1245 return mTextureHost ? mTextureHost->GetSurface() : nullptr; 1246 } 1247 1248 NativeLayerWaylandExternal::NativeLayerWaylandExternal( 1249 NativeLayerRootWayland* aRootLayer, bool aIsOpaque) 1250 : NativeLayerWayland(aRootLayer, IntSize(), aIsOpaque) {} 1251 1252 void NativeLayerWaylandExternal::AttachExternalImage( 1253 wr::RenderTextureHost* aExternalImage) { 1254 WaylandSurfaceLock lock(mSurface); 1255 1256 wr::RenderDMABUFTextureHost* texture = 1257 aExternalImage->AsRenderDMABUFTextureHost(); 1258 MOZ_DIAGNOSTIC_ASSERT(texture); 1259 if (!texture) { 1260 LOG("NativeLayerWayland::AttachExternalImage() failed."); 1261 gfxCriticalNoteOnce << "ExternalImage is not RenderDMABUFTextureHost"; 1262 return; 1263 } 1264 1265 if (mSize != texture->GetSize(0)) { 1266 mSize = texture->GetSize(0); 1267 mDisplayRect = IntRect(IntPoint{}, mSize); 1268 mState.mMutatedPlacement = true; 1269 } 1270 1271 mState.mMutatedFrontBuffer = 1272 (!mTextureHost || mTextureHost->GetSurface() != texture->GetSurface()); 1273 if (!mState.mMutatedFrontBuffer) { 1274 return; 1275 } 1276 mTextureHost = texture; 1277 1278 auto surface = mTextureHost->GetSurface(); 1279 mIsHDR = surface->IsHDRSurface(); 1280 1281 LOG("NativeLayerWaylandExternal::AttachExternalImage() host [%p] " 1282 "DMABufSurface [%p] DMABuf UID %d [%d x %d] HDR %d Opaque %d recycle " 1283 "%d", 1284 mTextureHost.get(), mTextureHost->GetSurface().get(), 1285 mTextureHost->GetSurface()->GetUID(), mSize.width, mSize.height, mIsHDR, 1286 mIsOpaque, surface->CanRecycle()); 1287 1288 mFrontBuffer = surface->CanRecycle() 1289 ? mRootLayer->BorrowExternalBuffer(surface) 1290 : widget::WaylandBufferDMABUF::CreateExternal(surface); 1291 } 1292 1293 void NativeLayerWaylandExternal::DiscardBackbuffersLocked( 1294 const WaylandSurfaceLock& aProofOfLock, bool aForce) { 1295 LOG("NativeLayerWaylandRender::DiscardBackbuffersLocked()"); 1296 1297 // Buffers attached to compositor are still tracked by WaylandSurface 1298 // so we can release reference here. 1299 mTextureHost = nullptr; 1300 mFrontBuffer = nullptr; 1301 } 1302 1303 RefPtr<DrawTarget> NativeLayerWaylandExternal::NextSurfaceAsDrawTarget( 1304 const IntRect& aDisplayRect, const IntRegion& aUpdateRegion, 1305 BackendType aBackendType) { 1306 MOZ_CRASH( 1307 "NativeLayerWaylandExternal::NextSurfaceAsDrawTarget() not implemented!"); 1308 return nullptr; 1309 } 1310 1311 Maybe<GLuint> NativeLayerWaylandExternal::NextSurfaceAsFramebuffer( 1312 const IntRect& aDisplayRect, const IntRegion& aUpdateRegion, 1313 bool aNeedsDepth) { 1314 MOZ_CRASH( 1315 "NativeLayerWaylandExternal::NextSurfaceAsFramebuffer() " 1316 "not implemented!"); 1317 return Nothing(); 1318 } 1319 1320 bool NativeLayerWaylandExternal::IsFrontBufferChanged() { 1321 return mState.mMutatedFrontBuffer; 1322 } 1323 1324 bool NativeLayerWaylandExternal::CommitFrontBufferToScreenLocked( 1325 const WaylandSurfaceLock& aProofOfLock) { 1326 LOG("NativeLayerWaylandExternal::CommitFrontBufferToScreenLocked()"); 1327 mSurface->InvalidateLocked(aProofOfLock); 1328 mSurface->AttachLocked(aProofOfLock, mFrontBuffer); 1329 return true; 1330 } 1331 1332 NativeLayerWaylandExternal::~NativeLayerWaylandExternal() { 1333 LOG("NativeLayerWaylandExternal::~NativeLayerWaylandExternal()"); 1334 } 1335 1336 } // namespace mozilla::layers