tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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