summaryrefslogtreecommitdiffstats
path: root/gfx/layers/wr/OMTASampler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/wr/OMTASampler.cpp')
-rw-r--r--gfx/layers/wr/OMTASampler.cpp248
1 files changed, 248 insertions, 0 deletions
diff --git a/gfx/layers/wr/OMTASampler.cpp b/gfx/layers/wr/OMTASampler.cpp
new file mode 100644
index 0000000000..c9616e87e1
--- /dev/null
+++ b/gfx/layers/wr/OMTASampler.cpp
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/layers/OMTASampler.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/layers/CompositorAnimationStorage.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/OMTAController.h"
+#include "mozilla/layers/SynchronousTask.h"
+#include "mozilla/layers/WebRenderBridgeParent.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+
+namespace mozilla {
+namespace layers {
+
+StaticMutex OMTASampler::sWindowIdLock;
+StaticAutoPtr<std::unordered_map<uint64_t, RefPtr<OMTASampler>>>
+ OMTASampler::sWindowIdMap;
+
+OMTASampler::OMTASampler(const RefPtr<CompositorAnimationStorage>& aAnimStorage,
+ LayersId aRootLayersId)
+ : mAnimStorage(aAnimStorage),
+ mStorageLock("OMTASampler::mStorageLock"),
+ mThreadIdLock("OMTASampler::mThreadIdLock"),
+ mSampleTimeLock("OMTASampler::mSampleTimeLock"),
+ mIsInTestMode(false) {
+ mController = new OMTAController(aRootLayersId);
+}
+
+void OMTASampler::Destroy() {
+ StaticMutexAutoLock lock(sWindowIdLock);
+ if (mWindowId) {
+ MOZ_ASSERT(sWindowIdMap);
+ sWindowIdMap->erase(wr::AsUint64(*mWindowId));
+ }
+}
+
+void OMTASampler::SetWebRenderWindowId(const wr::WrWindowId& aWindowId) {
+ StaticMutexAutoLock lock(sWindowIdLock);
+ MOZ_ASSERT(!mWindowId);
+ mWindowId = Some(aWindowId);
+ if (!sWindowIdMap) {
+ sWindowIdMap = new std::unordered_map<uint64_t, RefPtr<OMTASampler>>();
+ NS_DispatchToMainThread(
+ NS_NewRunnableFunction("OMTASampler::ClearOnShutdown",
+ [] { ClearOnShutdown(&sWindowIdMap); }));
+ }
+ (*sWindowIdMap)[wr::AsUint64(aWindowId)] = this;
+}
+
+/*static*/
+void OMTASampler::SetSamplerThread(const wr::WrWindowId& aWindowId) {
+ if (RefPtr<OMTASampler> sampler = GetSampler(aWindowId)) {
+ MutexAutoLock lock(sampler->mThreadIdLock);
+ sampler->mSamplerThreadId = Some(PlatformThread::CurrentId());
+ }
+}
+
+/*static*/
+void OMTASampler::Sample(const wr::WrWindowId& aWindowId,
+ wr::Transaction* aTransaction) {
+ if (RefPtr<OMTASampler> sampler = GetSampler(aWindowId)) {
+ wr::TransactionWrapper txn(aTransaction);
+ sampler->Sample(txn);
+ }
+}
+
+void OMTASampler::SetSampleTime(const TimeStamp& aSampleTime) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+
+ const bool hasAnimations = HasAnimations();
+
+ MutexAutoLock lock(mSampleTimeLock);
+
+ // Reset the previous time stamp if we don't already have any running
+ // animations to avoid using the time which is far behind for newly
+ // started animations.
+ mPreviousSampleTime = hasAnimations ? std::move(mSampleTime) : TimeStamp();
+ mSampleTime = aSampleTime;
+}
+
+void OMTASampler::ResetPreviousSampleTime() {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MutexAutoLock lock(mSampleTimeLock);
+
+ mPreviousSampleTime = TimeStamp();
+}
+
+void OMTASampler::Sample(wr::TransactionWrapper& aTxn) {
+ MOZ_ASSERT(IsSamplerThread());
+
+ // If we are in test mode, don't sample with the current time stamp, it will
+ // skew cached animation values.
+ if (mIsInTestMode) {
+ return;
+ }
+
+ TimeStamp sampleTime;
+ TimeStamp previousSampleTime;
+ { // scope lock
+ MutexAutoLock lock(mSampleTimeLock);
+
+ // If mSampleTime is null we're in a startup phase where the
+ // WebRenderBridgeParent hasn't yet provided us with a sample time.
+ // If we're that early there probably aren't any OMTA animations happening
+ // anyway, so using Timestamp::Now() should be fine.
+ sampleTime = mSampleTime.IsNull() ? TimeStamp::Now() : mSampleTime;
+ previousSampleTime = mPreviousSampleTime;
+ }
+
+ WrAnimations animations = SampleAnimations(previousSampleTime, sampleTime);
+
+ aTxn.AppendDynamicProperties(animations.mOpacityArrays,
+ animations.mTransformArrays,
+ animations.mColorArrays);
+}
+
+WrAnimations OMTASampler::SampleAnimations(const TimeStamp& aPreviousSampleTime,
+ const TimeStamp& aSampleTime) {
+ MOZ_ASSERT(IsSamplerThread());
+
+ MutexAutoLock lock(mStorageLock);
+
+ mAnimStorage->SampleAnimations(mController, aPreviousSampleTime, aSampleTime);
+
+ return mAnimStorage->CollectWebRenderAnimations();
+}
+
+OMTAValue OMTASampler::GetOMTAValue(const uint64_t& aId) const {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MutexAutoLock lock(mStorageLock);
+
+ return mAnimStorage->GetOMTAValue(aId);
+}
+
+void OMTASampler::SampleForTesting(const Maybe<TimeStamp>& aTestingSampleTime) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+
+ TimeStamp sampleTime;
+ TimeStamp previousSampleTime;
+ { // scope lock
+ MutexAutoLock timeLock(mSampleTimeLock);
+ if (aTestingSampleTime) {
+ // If we are on testing refresh mode, use the testing time stamp for both
+ // of the previous sample time and the current sample time since unlike
+ // normal refresh mode, the testing mode animations on the compositor are
+ // synchronously composed, so we don't need to worry about the time gap
+ // between the main thread and compositor thread.
+ sampleTime = *aTestingSampleTime;
+ previousSampleTime = *aTestingSampleTime;
+ } else {
+ sampleTime = mSampleTime;
+ previousSampleTime = mPreviousSampleTime;
+ }
+ }
+
+ MutexAutoLock storageLock(mStorageLock);
+ mAnimStorage->SampleAnimations(mController, previousSampleTime, sampleTime);
+}
+
+void OMTASampler::SetAnimations(
+ uint64_t aId, const LayersId& aLayersId,
+ const nsTArray<layers::Animation>& aAnimations) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MutexAutoLock lock(mStorageLock);
+
+ mAnimStorage->SetAnimations(aId, aLayersId, aAnimations);
+}
+
+bool OMTASampler::HasAnimations() const {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MutexAutoLock lock(mStorageLock);
+
+ return mAnimStorage->HasAnimations();
+}
+
+void OMTASampler::ClearActiveAnimations(
+ std::unordered_map<uint64_t, wr::WrEpoch>& aActiveAnimations) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MutexAutoLock lock(mStorageLock);
+ for (const auto& id : aActiveAnimations) {
+ mAnimStorage->ClearById(id.first);
+ }
+}
+
+void OMTASampler::RemoveEpochDataPriorTo(
+ std::queue<CompositorAnimationIdsForEpoch>& aCompositorAnimationsToDelete,
+ std::unordered_map<uint64_t, wr::WrEpoch>& aActiveAnimations,
+ const wr::WrEpoch& aRenderedEpoch) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MutexAutoLock lock(mStorageLock);
+
+ while (!aCompositorAnimationsToDelete.empty()) {
+ if (aRenderedEpoch < aCompositorAnimationsToDelete.front().mEpoch) {
+ break;
+ }
+ for (uint64_t id : aCompositorAnimationsToDelete.front().mIds) {
+ const auto activeAnim = aActiveAnimations.find(id);
+ if (activeAnim == aActiveAnimations.end()) {
+ NS_ERROR("Tried to delete invalid animation");
+ continue;
+ }
+ // Check if animation delete request is still valid.
+ if (activeAnim->second <= aCompositorAnimationsToDelete.front().mEpoch) {
+ mAnimStorage->ClearById(id);
+ aActiveAnimations.erase(activeAnim);
+ }
+ }
+ aCompositorAnimationsToDelete.pop();
+ }
+}
+
+bool OMTASampler::IsSamplerThread() const {
+ MutexAutoLock lock(mThreadIdLock);
+ return mSamplerThreadId && PlatformThread::CurrentId() == *mSamplerThreadId;
+}
+
+/*static*/
+already_AddRefed<OMTASampler> OMTASampler::GetSampler(
+ const wr::WrWindowId& aWindowId) {
+ RefPtr<OMTASampler> sampler;
+ StaticMutexAutoLock lock(sWindowIdLock);
+ if (sWindowIdMap) {
+ auto it = sWindowIdMap->find(wr::AsUint64(aWindowId));
+ if (it != sWindowIdMap->end()) {
+ sampler = it->second;
+ }
+ }
+ return sampler.forget();
+}
+
+} // namespace layers
+} // namespace mozilla
+
+void omta_register_sampler(mozilla::wr::WrWindowId aWindowId) {
+ mozilla::layers::OMTASampler::SetSamplerThread(aWindowId);
+}
+
+void omta_sample(mozilla::wr::WrWindowId aWindowId,
+ mozilla::wr::Transaction* aTransaction) {
+ mozilla::layers::OMTASampler::Sample(aWindowId, aTransaction);
+}
+
+void omta_deregister_sampler(mozilla::wr::WrWindowId aWindowId) {}