tor-browser

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

APZSampler.cpp (7924B)


      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 "mozilla/layers/APZSampler.h"
      8 
      9 #include "AsyncPanZoomController.h"
     10 #include "mozilla/ClearOnShutdown.h"
     11 #include "mozilla/layers/APZThreadUtils.h"
     12 #include "mozilla/layers/APZUtils.h"
     13 #include "mozilla/layers/CompositorThread.h"
     14 #include "mozilla/layers/SynchronousTask.h"
     15 #include "TreeTraversal.h"
     16 #include "mozilla/webrender/WebRenderAPI.h"
     17 
     18 namespace mozilla {
     19 namespace layers {
     20 
     21 StaticMutex APZSampler::sWindowIdLock;
     22 StaticAutoPtr<std::unordered_map<uint64_t, RefPtr<APZSampler>>>
     23    APZSampler::sWindowIdMap;
     24 
     25 APZSampler::APZSampler(const RefPtr<APZCTreeManager>& aApz,
     26                       bool aIsUsingWebRender)
     27    : mApz(aApz),
     28      mIsUsingWebRender(aIsUsingWebRender),
     29      mThreadIdLock("APZSampler::mThreadIdLock"),
     30      mSampleTimeLock("APZSampler::mSampleTimeLock") {
     31  MOZ_ASSERT(aApz);
     32  mApz->SetSampler(this);
     33 }
     34 
     35 APZSampler::~APZSampler() { mApz->SetSampler(nullptr); }
     36 
     37 void APZSampler::Destroy() {
     38  StaticMutexAutoLock lock(sWindowIdLock);
     39  if (mWindowId) {
     40    MOZ_ASSERT(sWindowIdMap);
     41    sWindowIdMap->erase(wr::AsUint64(*mWindowId));
     42  }
     43 }
     44 
     45 void APZSampler::SetWebRenderWindowId(const wr::WindowId& aWindowId) {
     46  StaticMutexAutoLock lock(sWindowIdLock);
     47  MOZ_ASSERT(!mWindowId);
     48  mWindowId = Some(aWindowId);
     49  if (!sWindowIdMap) {
     50    sWindowIdMap = new std::unordered_map<uint64_t, RefPtr<APZSampler>>();
     51    NS_DispatchToMainThread(NS_NewRunnableFunction(
     52        "APZSampler::ClearOnShutdown", [] { ClearOnShutdown(&sWindowIdMap); }));
     53  }
     54  (*sWindowIdMap)[wr::AsUint64(aWindowId)] = this;
     55 }
     56 
     57 /*static*/
     58 void APZSampler::SetSamplerThread(const wr::WrWindowId& aWindowId) {
     59  if (RefPtr<APZSampler> sampler = GetSampler(aWindowId)) {
     60    MutexAutoLock lock(sampler->mThreadIdLock);
     61    sampler->mSamplerThreadId = Some(PlatformThread::CurrentId());
     62  }
     63 }
     64 
     65 /*static*/
     66 void APZSampler::SampleForWebRender(const wr::WrWindowId& aWindowId,
     67                                    const uint64_t* aGeneratedFrameId,
     68                                    wr::Transaction* aTransaction) {
     69  if (RefPtr<APZSampler> sampler = GetSampler(aWindowId)) {
     70    wr::TransactionWrapper txn(aTransaction);
     71    Maybe<VsyncId> vsyncId =
     72        aGeneratedFrameId ? Some(VsyncId{*aGeneratedFrameId}) : Nothing();
     73    sampler->SampleForWebRender(vsyncId, txn);
     74  }
     75 }
     76 
     77 void APZSampler::SetSampleTime(const SampleTime& aSampleTime) {
     78  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
     79  MutexAutoLock lock(mSampleTimeLock);
     80  // This only gets called with WR, and the time provided is going to be
     81  // the time at which the current vsync interval ends. i.e. it is the timestamp
     82  // for the next vsync that will occur.
     83  mSampleTime = aSampleTime;
     84 }
     85 
     86 void APZSampler::SampleForWebRender(const Maybe<VsyncId>& aVsyncId,
     87                                    wr::TransactionWrapper& aTxn) {
     88  AssertOnSamplerThread();
     89  SampleTime sampleTime;
     90  {  // scope lock
     91    MutexAutoLock lock(mSampleTimeLock);
     92 
     93    // If mSampleTime is null we're in a startup phase where the
     94    // WebRenderBridgeParent hasn't yet provided us with a sample time.
     95    // If we're that early there probably aren't any APZ animations happening
     96    // anyway, so using Timestamp::Now() should be fine.
     97    SampleTime now = SampleTime::FromNow();
     98    sampleTime = mSampleTime.IsNull() ? now : mSampleTime;
     99  }
    100  mApz->SampleForWebRender(aVsyncId, aTxn, sampleTime);
    101 }
    102 
    103 AsyncTransform APZSampler::GetCurrentAsyncTransform(
    104    const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
    105    AsyncTransformComponents aComponents,
    106    const MutexAutoLock& aProofOfMapLock) const {
    107  MOZ_ASSERT(!CompositorThreadHolder::IsInCompositorThread());
    108  AssertOnSamplerThread();
    109 
    110  RefPtr<AsyncPanZoomController> apzc =
    111      mApz->GetTargetAPZC(aLayersId, aScrollId, aProofOfMapLock);
    112  if (!apzc) {
    113    // It's possible that this function can get called even after the target
    114    // APZC has been already destroyed because destroying the animation which
    115    // triggers this function call is basically processed later than the APZC,
    116    // i.e. queue mCompositorAnimationsToDelete in WebRenderBridgeParent and
    117    // then remove in WebRenderBridgeParent::RemoveEpochDataPriorTo.
    118    return AsyncTransform{};
    119  }
    120 
    121  return apzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing,
    122                                        aComponents);
    123 }
    124 
    125 ParentLayerRect APZSampler::GetCompositionBounds(
    126    const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
    127    const MutexAutoLock& aProofOfMapLock) const {
    128  AssertOnSamplerThread();
    129 
    130  RefPtr<AsyncPanZoomController> apzc =
    131      mApz->GetTargetAPZC(aLayersId, aScrollId, aProofOfMapLock);
    132  if (!apzc) {
    133    // It's possible that this function can get called even after the target
    134    // APZC has been already destroyed because destroying the animation which
    135    // triggers this function call is basically processed later than the APZC
    136    // one, i.e. queue mCompositorAnimationsToDelete in WebRenderBridgeParent
    137    // and then remove them in WebRenderBridgeParent::RemoveEpochDataPriorTo.
    138    return ParentLayerRect();
    139  }
    140 
    141  return apzc->GetCompositionBounds();
    142 }
    143 
    144 Maybe<APZSampler::ScrollOffsetAndRange>
    145 APZSampler::GetCurrentScrollOffsetAndRange(
    146    const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
    147    const MutexAutoLock& aProofOfMapLock) const {
    148  // Note: This is called from OMTA Sampler thread, or Compositor thread for
    149  // testing.
    150 
    151  RefPtr<AsyncPanZoomController> apzc =
    152      mApz->GetTargetAPZC(aLayersId, aScrollId, aProofOfMapLock);
    153  if (!apzc) {
    154    return Nothing();
    155  }
    156 
    157  return Some(ScrollOffsetAndRange{
    158      // FIXME: Use the one-frame delayed offset now. This doesn't take
    159      // scroll-linked effets into accounts, so we have to fix this in the
    160      // future.
    161      apzc->GetCurrentAsyncVisualViewport(
    162              AsyncTransformConsumer::eForCompositing)
    163          .TopLeft(),
    164      apzc->GetCurrentScrollRangeInCssPixels()});
    165 }
    166 
    167 void APZSampler::AssertOnSamplerThread() const {
    168  if (APZThreadUtils::GetThreadAssertionsEnabled()) {
    169    MOZ_ASSERT(IsSamplerThread());
    170  }
    171 }
    172 
    173 bool APZSampler::IsSamplerThread() const {
    174  if (mIsUsingWebRender) {
    175    // If the sampler thread id isn't set yet then we cannot be running on the
    176    // sampler thread (because we will have the thread id before we run any
    177    // other C++ code on it, and this function is only ever invoked from C++
    178    // code), so return false in that scenario.
    179    MutexAutoLock lock(mThreadIdLock);
    180    return mSamplerThreadId && PlatformThread::CurrentId() == *mSamplerThreadId;
    181  }
    182  return CompositorThreadHolder::IsInCompositorThread();
    183 }
    184 
    185 /*static*/
    186 already_AddRefed<APZSampler> APZSampler::GetSampler(
    187    const wr::WrWindowId& aWindowId) {
    188  RefPtr<APZSampler> sampler;
    189  StaticMutexAutoLock lock(sWindowIdLock);
    190  if (sWindowIdMap) {
    191    auto it = sWindowIdMap->find(wr::AsUint64(aWindowId));
    192    if (it != sWindowIdMap->end()) {
    193      sampler = it->second;
    194    }
    195  }
    196  return sampler.forget();
    197 }
    198 
    199 }  // namespace layers
    200 }  // namespace mozilla
    201 
    202 void apz_register_sampler(mozilla::wr::WrWindowId aWindowId) {
    203  mozilla::layers::APZSampler::SetSamplerThread(aWindowId);
    204 }
    205 
    206 void apz_sample_transforms(mozilla::wr::WrWindowId aWindowId,
    207                           const uint64_t* aGeneratedFrameId,
    208                           mozilla::wr::Transaction* aTransaction) {
    209  mozilla::layers::APZSampler::SampleForWebRender(aWindowId, aGeneratedFrameId,
    210                                                  aTransaction);
    211 }
    212 
    213 void apz_deregister_sampler(mozilla::wr::WrWindowId aWindowId) {}