tor-browser

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

WebRenderImageHost.cpp (14371B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "WebRenderImageHost.h"
      8 
      9 #include <utility>
     10 
     11 #include "mozilla/ScopeExit.h"
     12 #include "mozilla/gfx/gfxVars.h"
     13 #include "mozilla/layers/AsyncImagePipelineManager.h"
     14 #include "mozilla/layers/CompositorThread.h"
     15 #include "mozilla/layers/CompositorVsyncScheduler.h"  // for CompositorVsyncScheduler
     16 #include "mozilla/layers/KnowsCompositor.h"
     17 #include "mozilla/layers/RemoteTextureHostWrapper.h"
     18 #include "mozilla/layers/RemoteTextureMap.h"
     19 #include "mozilla/layers/WebRenderBridgeParent.h"
     20 #include "mozilla/layers/WebRenderTextureHost.h"
     21 #include "mozilla/ProfilerMarkers.h"
     22 #include "mozilla/StaticPrefs_gfx.h"
     23 #include "mozilla/StaticPrefs_webgl.h"
     24 #include "nsAString.h"
     25 #include "nsDebug.h"          // for NS_WARNING, NS_ASSERTION
     26 #include "nsPrintfCString.h"  // for nsPrintfCString
     27 #include "nsString.h"         // for nsAutoCString
     28 
     29 #if XP_WIN
     30 #  include "mozilla/layers/GpuProcessD3D11TextureMap.h"
     31 #  include "mozilla/layers/TextureHostWrapperD3D11.h"
     32 #endif
     33 
     34 namespace mozilla {
     35 
     36 using namespace gfx;
     37 
     38 namespace layers {
     39 
     40 class ISurfaceAllocator;
     41 
     42 WebRenderImageHost::WebRenderImageHost(const TextureInfo& aTextureInfo)
     43    : CompositableHost(aTextureInfo), mCurrentAsyncImageManager(nullptr) {}
     44 
     45 WebRenderImageHost::~WebRenderImageHost() {
     46  MOZ_ASSERT(mPendingRemoteTextureWrappers.empty());
     47  MOZ_ASSERT(mWrBridges.empty());
     48 }
     49 
     50 void WebRenderImageHost::OnReleased() {
     51  ImageComposite::ClearImages();
     52  if (!mPendingRemoteTextureWrappers.empty()) {
     53    mPendingRemoteTextureWrappers.clear();
     54  }
     55  SetCurrentTextureHost(nullptr);
     56 }
     57 
     58 void WebRenderImageHost::UseTextureHost(
     59    const nsTArray<TimedTexture>& aTextures) {
     60  CompositableHost::UseTextureHost(aTextures);
     61  MOZ_ASSERT(aTextures.Length() >= 1);
     62 
     63  if (!mPendingRemoteTextureWrappers.empty()) {
     64    mPendingRemoteTextureWrappers.clear();
     65  }
     66 
     67  if (mCurrentTextureHost &&
     68      mCurrentTextureHost->AsRemoteTextureHostWrapper()) {
     69    mCurrentTextureHost = nullptr;
     70  }
     71 
     72  nsTArray<TimedImage> newImages;
     73 
     74  for (uint32_t i = 0; i < aTextures.Length(); ++i) {
     75    const TimedTexture& t = aTextures[i];
     76    MOZ_ASSERT(t.mTexture);
     77    if (i + 1 < aTextures.Length() && t.mProducerID == mLastProducerID &&
     78        t.mFrameID < mLastFrameID) {
     79      // Ignore frames before a frame that we already composited. We don't
     80      // ever want to display these frames. This could be important if
     81      // the frame producer adjusts timestamps (e.g. to track the audio clock)
     82      // and the new frame times are earlier.
     83      continue;
     84    }
     85    TimedImage& img = *newImages.AppendElement();
     86    img.mTextureHost = t.mTexture;
     87    img.mTimeStamp = t.mTimeStamp;
     88    img.mPictureRect = t.mPictureRect;
     89    img.mFrameID = t.mFrameID;
     90    img.mProducerID = t.mProducerID;
     91    img.mTextureHost->SetCropRect(img.mPictureRect);
     92  }
     93 
     94  SetImages(std::move(newImages));
     95 
     96  if (GetAsyncRef()) {
     97    for (const auto& it : mWrBridges) {
     98      RefPtr<WebRenderBridgeParent> wrBridge = it.second->WrBridge();
     99      if (wrBridge && wrBridge->CompositorScheduler()) {
    100        wrBridge->CompositorScheduler()->ScheduleComposition(
    101            wr::RenderReasons::ASYNC_IMAGE);
    102      }
    103    }
    104  }
    105 
    106  // Video producers generally send replacement images with the same frameID but
    107  // slightly different timestamps in order to sync with the audio clock. This
    108  // means that any CompositeUntil() call we made in Composite() may no longer
    109  // guarantee that we'll composite until the next frame is ready. Fix that
    110  // here.
    111  if (mLastFrameID >= 0 && !mWrBridges.empty()) {
    112    for (const auto& img : Images()) {
    113      bool frameComesAfter =
    114          img.mFrameID > mLastFrameID || img.mProducerID != mLastProducerID;
    115      if (frameComesAfter && !img.mTimeStamp.IsNull()) {
    116        for (const auto& it : mWrBridges) {
    117          RefPtr<WebRenderBridgeParent> wrBridge = it.second->WrBridge();
    118          if (wrBridge) {
    119            wrBridge->AsyncImageManager()->CompositeUntil(
    120                img.mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
    121          }
    122        }
    123        break;
    124      }
    125    }
    126  }
    127 }
    128 
    129 void WebRenderImageHost::PushPendingRemoteTexture(
    130    const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
    131    const base::ProcessId aForPid, const gfx::IntSize aSize,
    132    const TextureFlags aFlags) {
    133  // Ensure aOwnerId is the same as RemoteTextureOwnerId of pending
    134  // RemoteTextures.
    135  if (!mPendingRemoteTextureWrappers.empty()) {
    136    auto* wrapper =
    137        mPendingRemoteTextureWrappers.front()->AsRemoteTextureHostWrapper();
    138    MOZ_ASSERT(wrapper);
    139    if (wrapper->mOwnerId != aOwnerId || wrapper->mForPid != aForPid) {
    140      // Clear when RemoteTextureOwner is different.
    141      mPendingRemoteTextureWrappers.clear();
    142      mWaitingReadyCallback = false;
    143      mWaitForRemoteTextureOwner = true;
    144    }
    145  }
    146 
    147  // Check if waiting for remote texture owner is allowed.
    148  if (!(aFlags & TextureFlags::WAIT_FOR_REMOTE_TEXTURE_OWNER)) {
    149    mWaitForRemoteTextureOwner = false;
    150  }
    151 
    152  RefPtr<TextureHost> texture =
    153      RemoteTextureMap::Get()->GetOrCreateRemoteTextureHostWrapper(
    154          aTextureId, aOwnerId, aForPid, aSize, aFlags);
    155  MOZ_ASSERT(texture);
    156  mPendingRemoteTextureWrappers.push_back(
    157      CompositableTextureHostRef(texture.get()));
    158 }
    159 
    160 void WebRenderImageHost::UseRemoteTexture() {
    161  if (mPendingRemoteTextureWrappers.empty()) {
    162    return;
    163  }
    164 
    165  const bool useReadyCallback = bool(GetAsyncRef());
    166  CompositableTextureHostRef texture;
    167 
    168  if (useReadyCallback) {
    169    if (mWaitingReadyCallback) {
    170      return;
    171    }
    172    MOZ_ASSERT(!mWaitingReadyCallback);
    173 
    174    auto readyCallback = [self = RefPtr<WebRenderImageHost>(this)](
    175                             const RemoteTextureInfo aInfo) {
    176      RefPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
    177          "WebRenderImageHost::UseRemoteTexture",
    178          [self = std::move(self), aInfo]() {
    179            MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    180 
    181            if (self->mPendingRemoteTextureWrappers.empty()) {
    182              return;
    183            }
    184 
    185            auto* wrapper = self->mPendingRemoteTextureWrappers.front()
    186                                ->AsRemoteTextureHostWrapper();
    187            MOZ_ASSERT(wrapper);
    188            if (wrapper->mOwnerId != aInfo.mOwnerId ||
    189                wrapper->mForPid != aInfo.mForPid) {
    190              // obsoleted callback
    191              return;
    192            }
    193 
    194            self->mWaitingReadyCallback = false;
    195            self->UseRemoteTexture();
    196          });
    197 
    198      CompositorThread()->Dispatch(runnable.forget());
    199    };
    200 
    201    // Check which of the pending remote textures is the most recent and ready.
    202    while (!mPendingRemoteTextureWrappers.empty()) {
    203      auto* wrapper =
    204          mPendingRemoteTextureWrappers.front()->AsRemoteTextureHostWrapper();
    205 
    206      if (mWaitForRemoteTextureOwner) {
    207        // XXX remove sync wait
    208        RemoteTextureMap::Get()->WaitForRemoteTextureOwner(wrapper);
    209      }
    210      mWaitingReadyCallback = !RemoteTextureMap::Get()->CheckRemoteTextureReady(
    211          wrapper->GetRemoteTextureInfo(), readyCallback);
    212      if (mWaitingReadyCallback) {
    213        break;
    214      }
    215      RemoteTextureMap::Get()->GetRemoteTexture(wrapper);
    216      texture = mPendingRemoteTextureWrappers.front();
    217      mPendingRemoteTextureWrappers.pop_front();
    218    }
    219  } else {
    220    texture = mPendingRemoteTextureWrappers.front();
    221    auto* wrapper = texture->AsRemoteTextureHostWrapper();
    222    mPendingRemoteTextureWrappers.pop_front();
    223    MOZ_ASSERT(mPendingRemoteTextureWrappers.empty());
    224 
    225    if (mWaitForRemoteTextureOwner) {
    226      if (StaticPrefs::gfx_remote_texture_wait_owner_at_image_host()) {
    227        RemoteTextureMap::Get()->WaitForRemoteTextureOwner(wrapper);
    228      } else {
    229        wrapper->EnableWaitForRemoteTextureOwner(true);
    230      }
    231    }
    232    mWaitForRemoteTextureOwner = false;
    233  }
    234 
    235  if (!texture ||
    236      (GetAsyncRef() &&
    237       !texture->AsRemoteTextureHostWrapper()->IsReadyForRendering())) {
    238    return;
    239  }
    240 
    241  SetCurrentTextureHost(texture);
    242 
    243  if (GetAsyncRef()) {
    244    for (const auto& it : mWrBridges) {
    245      RefPtr<WebRenderBridgeParent> wrBridge = it.second->WrBridge();
    246      if (wrBridge && wrBridge->CompositorScheduler()) {
    247        wrBridge->CompositorScheduler()->ScheduleComposition(
    248            wr::RenderReasons::ASYNC_IMAGE);
    249      }
    250    }
    251  }
    252 }
    253 
    254 void WebRenderImageHost::CleanupResources() {
    255  ImageComposite::ClearImages();
    256  SetCurrentTextureHost(nullptr);
    257 }
    258 
    259 void WebRenderImageHost::RemoveTextureHost(TextureHost* aTexture) {
    260  RemoveImagesWithTextureHost(aTexture);
    261 }
    262 
    263 void WebRenderImageHost::ClearImages(ClearImagesType aType) {
    264  ImageComposite::ClearImages();
    265  if (aType == ClearImagesType::All) {
    266    if (!mPendingRemoteTextureWrappers.empty()) {
    267      mPendingRemoteTextureWrappers.clear();
    268    }
    269    SetCurrentTextureHost(nullptr);
    270 
    271    if (GetAsyncRef()) {
    272      for (const auto& it : mWrBridges) {
    273        RefPtr<WebRenderBridgeParent> wrBridge = it.second->WrBridge();
    274        if (wrBridge && wrBridge->CompositorScheduler()) {
    275          wrBridge->CompositorScheduler()->ScheduleComposition(
    276              wr::RenderReasons::ASYNC_IMAGE);
    277        }
    278      }
    279    }
    280  }
    281 }
    282 
    283 TimeStamp WebRenderImageHost::GetCompositionTime() const {
    284  TimeStamp time;
    285 
    286  MOZ_ASSERT(mCurrentAsyncImageManager);
    287  if (mCurrentAsyncImageManager) {
    288    time = mCurrentAsyncImageManager->GetCompositionTime();
    289  }
    290  return time;
    291 }
    292 
    293 CompositionOpportunityId WebRenderImageHost::GetCompositionOpportunityId()
    294    const {
    295  CompositionOpportunityId id;
    296 
    297  MOZ_ASSERT(mCurrentAsyncImageManager);
    298  if (mCurrentAsyncImageManager) {
    299    id = mCurrentAsyncImageManager->GetCompositionOpportunityId();
    300  }
    301  return id;
    302 }
    303 
    304 void WebRenderImageHost::AppendImageCompositeNotification(
    305    const ImageCompositeNotificationInfo& aInfo) const {
    306  if (mCurrentAsyncImageManager) {
    307    mCurrentAsyncImageManager->AppendImageCompositeNotification(aInfo);
    308  }
    309 }
    310 
    311 TextureHost* WebRenderImageHost::GetAsTextureHostForComposite(
    312    AsyncImagePipelineManager* aAsyncImageManager) {
    313  MOZ_ASSERT(aAsyncImageManager);
    314 
    315  if (mCurrentTextureHost &&
    316      mCurrentTextureHost->AsRemoteTextureHostWrapper()) {
    317    return mCurrentTextureHost;
    318  }
    319 
    320  mCurrentAsyncImageManager = aAsyncImageManager;
    321  const auto onExit =
    322      mozilla::MakeScopeExit([&]() { mCurrentAsyncImageManager = nullptr; });
    323 
    324  int imageIndex = ChooseImageIndex();
    325  if (imageIndex < 0) {
    326    SetCurrentTextureHost(nullptr);
    327    return nullptr;
    328  }
    329 
    330  if (uint32_t(imageIndex) + 1 < ImagesCount()) {
    331    mCurrentAsyncImageManager->CompositeUntil(
    332        GetImage(imageIndex + 1)->mTimeStamp +
    333        TimeDuration::FromMilliseconds(BIAS_TIME_MS));
    334  }
    335 
    336  const TimedImage* img = GetImage(imageIndex);
    337 
    338  RefPtr<TextureHost> texture = img->mTextureHost.get();
    339 #if XP_WIN
    340  // Convert YUV BufferTextureHost to TextureHostWrapperD3D11 if possible
    341  if (texture->AsBufferTextureHost()) {
    342    auto identifier = aAsyncImageManager->GetTextureFactoryIdentifier();
    343    const bool tryConvertToNV12 =
    344        StaticPrefs::gfx_video_convert_yuv_to_nv12_image_host_win() &&
    345        identifier.mSupportsD3D11NV12 &&
    346        KnowsCompositor::SupportsD3D11(identifier) &&
    347        texture->GetFormat() == gfx::SurfaceFormat::YUV420;
    348    if (tryConvertToNV12) {
    349      PROFILER_MARKER_TEXT("WebRenderImageHost", GRAPHICS, {},
    350                           "Try ConvertToNV12"_ns);
    351 
    352      if (!mTextureAllocator) {
    353        mTextureAllocator = new TextureWrapperD3D11Allocator();
    354      }
    355      RefPtr<TextureHost> textureWrapper =
    356          TextureHostWrapperD3D11::CreateFromBufferTexture(mTextureAllocator,
    357                                                           texture);
    358      if (textureWrapper) {
    359        texture = textureWrapper;
    360      }
    361    } else if (profiler_thread_is_being_profiled_for_markers() &&
    362               StaticPrefs::gfx_video_convert_yuv_to_nv12_image_host_win() &&
    363               texture->GetFormat() == gfx::SurfaceFormat::YUV420) {
    364      nsPrintfCString str("No ConvertToNV12 D3D11 %d NV12 %d",
    365                          KnowsCompositor::SupportsD3D11(identifier),
    366                          identifier.mSupportsD3D11NV12);
    367      PROFILER_MARKER_TEXT("WebRenderImageHost", GRAPHICS, {}, str);
    368    }
    369  }
    370 #endif
    371  SetCurrentTextureHost(texture);
    372 
    373  if (mCurrentAsyncImageManager->GetCompositionTime()) {
    374    // We are in a composition. Send ImageCompositeNotifications.
    375    OnFinishRendering(imageIndex, img, mAsyncRef.mProcessId, mAsyncRef.mHandle);
    376  }
    377 
    378  return mCurrentTextureHost;
    379 }
    380 
    381 void WebRenderImageHost::SetCurrentTextureHost(TextureHost* aTexture) {
    382  if (aTexture == mCurrentTextureHost.get()) {
    383    return;
    384  }
    385  mCurrentTextureHost = aTexture;
    386 }
    387 
    388 void WebRenderImageHost::Dump(std::stringstream& aStream, const char* aPrefix,
    389                              bool aDumpHtml) {
    390  for (const auto& img : Images()) {
    391    aStream << aPrefix;
    392    aStream << (aDumpHtml ? "<ul><li>TextureHost: " : "TextureHost: ");
    393    DumpTextureHost(aStream, img.mTextureHost);
    394    aStream << (aDumpHtml ? " </li></ul> " : " ");
    395  }
    396 }
    397 
    398 void WebRenderImageHost::SetWrBridge(const wr::PipelineId& aPipelineId,
    399                                     WebRenderBridgeParent* aWrBridge) {
    400  MOZ_ASSERT(aWrBridge);
    401  MOZ_ASSERT(!mCurrentAsyncImageManager);
    402 #ifdef DEBUG
    403  const auto it = mWrBridges.find(wr::AsUint64(aPipelineId));
    404  MOZ_ASSERT(it == mWrBridges.end());
    405 #endif
    406  RefPtr<WebRenderBridgeParentRef> ref =
    407      aWrBridge->GetWebRenderBridgeParentRef();
    408  mWrBridges.emplace(wr::AsUint64(aPipelineId), ref);
    409 }
    410 
    411 void WebRenderImageHost::ClearWrBridge(const wr::PipelineId& aPipelineId,
    412                                       WebRenderBridgeParent* aWrBridge) {
    413  MOZ_ASSERT(aWrBridge);
    414  MOZ_ASSERT(!mCurrentAsyncImageManager);
    415 
    416  const auto it = mWrBridges.find(wr::AsUint64(aPipelineId));
    417  MOZ_ASSERT(it != mWrBridges.end());
    418  if (it == mWrBridges.end()) {
    419    gfxCriticalNote << "WrBridge mismatch happened";
    420    return;
    421  }
    422  mWrBridges.erase(it);
    423  SetCurrentTextureHost(nullptr);
    424 }
    425 
    426 }  // namespace layers
    427 }  // namespace mozilla