tor-browser

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

OMTASampler.cpp (8525B)


      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/OMTASampler.h"
      8 
      9 #include "mozilla/ClearOnShutdown.h"
     10 #include "mozilla/layers/CompositorAnimationStorage.h"
     11 #include "mozilla/layers/CompositorThread.h"
     12 #include "mozilla/layers/OMTAController.h"
     13 #include "mozilla/layers/SynchronousTask.h"
     14 #include "mozilla/layers/WebRenderBridgeParent.h"
     15 #include "mozilla/webrender/WebRenderAPI.h"
     16 
     17 namespace mozilla {
     18 namespace layers {
     19 
     20 StaticMutex OMTASampler::sWindowIdLock;
     21 StaticAutoPtr<std::unordered_map<uint64_t, RefPtr<OMTASampler>>>
     22    OMTASampler::sWindowIdMap;
     23 
     24 OMTASampler::OMTASampler(const RefPtr<CompositorAnimationStorage>& aAnimStorage,
     25                         LayersId aRootLayersId)
     26    : mAnimStorage(aAnimStorage),
     27      mStorageLock("OMTASampler::mStorageLock"),
     28      mThreadIdLock("OMTASampler::mThreadIdLock"),
     29      mSampleTimeLock("OMTASampler::mSampleTimeLock"),
     30      mIsInTestMode(false) {
     31  mController = new OMTAController(aRootLayersId);
     32 }
     33 
     34 void OMTASampler::Destroy() {
     35  StaticMutexAutoLock lock(sWindowIdLock);
     36  if (mWindowId) {
     37    MOZ_ASSERT(sWindowIdMap);
     38    sWindowIdMap->erase(wr::AsUint64(*mWindowId));
     39  }
     40 }
     41 
     42 void OMTASampler::SetWebRenderWindowId(const wr::WrWindowId& aWindowId) {
     43  StaticMutexAutoLock lock(sWindowIdLock);
     44  MOZ_ASSERT(!mWindowId);
     45  mWindowId = Some(aWindowId);
     46  if (!sWindowIdMap) {
     47    sWindowIdMap = new std::unordered_map<uint64_t, RefPtr<OMTASampler>>();
     48    NS_DispatchToMainThread(
     49        NS_NewRunnableFunction("OMTASampler::ClearOnShutdown",
     50                               [] { ClearOnShutdown(&sWindowIdMap); }));
     51  }
     52  (*sWindowIdMap)[wr::AsUint64(aWindowId)] = this;
     53 }
     54 
     55 /*static*/
     56 void OMTASampler::SetSamplerThread(const wr::WrWindowId& aWindowId) {
     57  if (RefPtr<OMTASampler> sampler = GetSampler(aWindowId)) {
     58    MutexAutoLock lock(sampler->mThreadIdLock);
     59    sampler->mSamplerThreadId = Some(PlatformThread::CurrentId());
     60  }
     61 }
     62 
     63 /*static*/
     64 void OMTASampler::Sample(const wr::WrWindowId& aWindowId,
     65                         wr::Transaction* aTransaction) {
     66  if (RefPtr<OMTASampler> sampler = GetSampler(aWindowId)) {
     67    wr::TransactionWrapper txn(aTransaction);
     68    sampler->Sample(txn);
     69  }
     70 }
     71 
     72 void OMTASampler::SetSampleTime(const TimeStamp& aSampleTime) {
     73  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
     74 
     75  const bool hasAnimations = HasAnimations();
     76 
     77  MutexAutoLock lock(mSampleTimeLock);
     78 
     79  // Reset the previous time stamp if we don't already have any running
     80  // animations to avoid using the time which is far behind for newly
     81  // started animations.
     82  mPreviousSampleTime = hasAnimations ? std::move(mSampleTime) : TimeStamp();
     83  mSampleTime = aSampleTime;
     84 }
     85 
     86 void OMTASampler::ResetPreviousSampleTime() {
     87  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
     88  MutexAutoLock lock(mSampleTimeLock);
     89 
     90  mPreviousSampleTime = TimeStamp();
     91 }
     92 
     93 void OMTASampler::Sample(wr::TransactionWrapper& aTxn) {
     94  MOZ_ASSERT(IsSamplerThread());
     95 
     96  // If we are in test mode, don't sample with the current time stamp, it will
     97  // skew cached animation values.
     98  if (mIsInTestMode) {
     99    return;
    100  }
    101 
    102  TimeStamp sampleTime;
    103  TimeStamp previousSampleTime;
    104  {  // scope lock
    105    MutexAutoLock lock(mSampleTimeLock);
    106 
    107    // If mSampleTime is null we're in a startup phase where the
    108    // WebRenderBridgeParent hasn't yet provided us with a sample time.
    109    // If we're that early there probably aren't any OMTA animations happening
    110    // anyway, so using Timestamp::Now() should be fine.
    111    sampleTime = mSampleTime.IsNull() ? TimeStamp::Now() : mSampleTime;
    112    previousSampleTime = mPreviousSampleTime;
    113  }
    114 
    115  WrAnimations animations = SampleAnimations(previousSampleTime, sampleTime);
    116 
    117  aTxn.AppendDynamicProperties(animations.mOpacityArrays,
    118                               animations.mTransformArrays,
    119                               animations.mColorArrays);
    120 }
    121 
    122 WrAnimations OMTASampler::SampleAnimations(const TimeStamp& aPreviousSampleTime,
    123                                           const TimeStamp& aSampleTime) {
    124  MOZ_ASSERT(IsSamplerThread());
    125 
    126  MutexAutoLock lock(mStorageLock);
    127 
    128  mAnimStorage->SampleAnimations(mController, aPreviousSampleTime, aSampleTime);
    129 
    130  return mAnimStorage->CollectWebRenderAnimations();
    131 }
    132 
    133 OMTAValue OMTASampler::GetOMTAValue(const uint64_t& aId) const {
    134  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    135  MutexAutoLock lock(mStorageLock);
    136 
    137  return mAnimStorage->GetOMTAValue(aId);
    138 }
    139 
    140 void OMTASampler::SampleForTesting(const Maybe<TimeStamp>& aTestingSampleTime) {
    141  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    142 
    143  TimeStamp sampleTime;
    144  TimeStamp previousSampleTime;
    145  {  // scope lock
    146    MutexAutoLock timeLock(mSampleTimeLock);
    147    if (aTestingSampleTime) {
    148      // If we are on testing refresh mode, use the testing time stamp for both
    149      // of the previous sample time and the current sample time since unlike
    150      // normal refresh mode, the testing mode animations on the compositor are
    151      // synchronously composed, so we don't need to worry about the time gap
    152      // between the main thread and compositor thread.
    153      sampleTime = *aTestingSampleTime;
    154      previousSampleTime = *aTestingSampleTime;
    155    } else {
    156      sampleTime = mSampleTime;
    157      previousSampleTime = mPreviousSampleTime;
    158    }
    159  }
    160 
    161  MutexAutoLock storageLock(mStorageLock);
    162  mAnimStorage->SampleAnimations(mController, previousSampleTime, sampleTime);
    163 }
    164 
    165 void OMTASampler::SetAnimations(
    166    uint64_t aId, const LayersId& aLayersId,
    167    const nsTArray<layers::Animation>& aAnimations) {
    168  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    169  MutexAutoLock lock(mStorageLock);
    170  MutexAutoLock timeLock(mSampleTimeLock);
    171  mAnimStorage->SetAnimations(aId, aLayersId, aAnimations, mPreviousSampleTime);
    172 }
    173 
    174 bool OMTASampler::HasAnimations() const {
    175  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    176  MutexAutoLock lock(mStorageLock);
    177 
    178  return mAnimStorage->HasAnimations();
    179 }
    180 
    181 void OMTASampler::ClearActiveAnimations(
    182    std::unordered_map<uint64_t, wr::WrEpoch>& aActiveAnimations) {
    183  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    184  MutexAutoLock lock(mStorageLock);
    185  for (const auto& id : aActiveAnimations) {
    186    mAnimStorage->ClearById(id.first);
    187  }
    188 }
    189 
    190 void OMTASampler::RemoveEpochDataPriorTo(
    191    std::queue<CompositorAnimationIdsForEpoch>& aCompositorAnimationsToDelete,
    192    std::unordered_map<uint64_t, wr::WrEpoch>& aActiveAnimations,
    193    const wr::WrEpoch& aRenderedEpoch) {
    194  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    195  MutexAutoLock lock(mStorageLock);
    196 
    197  while (!aCompositorAnimationsToDelete.empty()) {
    198    if (aRenderedEpoch < aCompositorAnimationsToDelete.front().mEpoch) {
    199      break;
    200    }
    201    for (uint64_t id : aCompositorAnimationsToDelete.front().mIds) {
    202      const auto activeAnim = aActiveAnimations.find(id);
    203      if (activeAnim == aActiveAnimations.end()) {
    204        NS_ERROR("Tried to delete invalid animation");
    205        continue;
    206      }
    207      // Check if animation delete request is still valid.
    208      if (activeAnim->second <= aCompositorAnimationsToDelete.front().mEpoch) {
    209        mAnimStorage->ClearById(id);
    210        aActiveAnimations.erase(activeAnim);
    211      }
    212    }
    213    aCompositorAnimationsToDelete.pop();
    214  }
    215 }
    216 
    217 bool OMTASampler::IsSamplerThread() const {
    218  MutexAutoLock lock(mThreadIdLock);
    219  return mSamplerThreadId && PlatformThread::CurrentId() == *mSamplerThreadId;
    220 }
    221 
    222 /*static*/
    223 already_AddRefed<OMTASampler> OMTASampler::GetSampler(
    224    const wr::WrWindowId& aWindowId) {
    225  RefPtr<OMTASampler> sampler;
    226  StaticMutexAutoLock lock(sWindowIdLock);
    227  if (sWindowIdMap) {
    228    auto it = sWindowIdMap->find(wr::AsUint64(aWindowId));
    229    if (it != sWindowIdMap->end()) {
    230      sampler = it->second;
    231    }
    232  }
    233  return sampler.forget();
    234 }
    235 
    236 }  // namespace layers
    237 }  // namespace mozilla
    238 
    239 void omta_register_sampler(mozilla::wr::WrWindowId aWindowId) {
    240  mozilla::layers::OMTASampler::SetSamplerThread(aWindowId);
    241 }
    242 
    243 void omta_sample(mozilla::wr::WrWindowId aWindowId,
    244                 mozilla::wr::Transaction* aTransaction) {
    245  mozilla::layers::OMTASampler::Sample(aWindowId, aTransaction);
    246 }
    247 
    248 void omta_deregister_sampler(mozilla::wr::WrWindowId aWindowId) {}