summaryrefslogtreecommitdiffstats
path: root/gfx/layers/wr/WebRenderLayerManager.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/layers/wr/WebRenderLayerManager.cpp
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/layers/wr/WebRenderLayerManager.cpp')
-rw-r--r--gfx/layers/wr/WebRenderLayerManager.cpp772
1 files changed, 772 insertions, 0 deletions
diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp
new file mode 100644
index 0000000000..b0011e24de
--- /dev/null
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -0,0 +1,772 @@
+/* -*- 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 "WebRenderLayerManager.h"
+
+#include "BasicLayers.h"
+#include "Layers.h"
+
+#include "GeckoProfiler.h"
+#include "mozilla/StaticPrefs_apz.h"
+#include "mozilla/StaticPrefs_layers.h"
+#include "mozilla/dom/BrowserChild.h"
+#include "mozilla/gfx/DrawEventRecorder.h"
+#include "mozilla/gfx/gfxVars.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
+#include "mozilla/layers/StackingContextHelper.h"
+#include "mozilla/layers/TextureClient.h"
+#include "mozilla/layers/TransactionIdAllocator.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/layers/UpdateImageHelper.h"
+#include "nsDisplayList.h"
+#include "nsLayoutUtils.h"
+#include "WebRenderCanvasRenderer.h"
+
+#ifdef XP_WIN
+# include "gfxDWriteFonts.h"
+#endif
+
+namespace mozilla {
+
+using namespace gfx;
+
+namespace layers {
+
+WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
+ : mWidget(aWidget),
+ mLatestTransactionId{0},
+ mNeedsComposite(false),
+ mIsFirstPaint(false),
+ mTarget(nullptr),
+ mPaintSequenceNumber(0),
+ mWebRenderCommandBuilder(this),
+ mLastDisplayListSize(0) {
+ MOZ_COUNT_CTOR(WebRenderLayerManager);
+ mStateManager.mLayerManager = this;
+
+ if (XRE_IsContentProcess() &&
+ StaticPrefs::gfx_webrender_enable_item_cache_AtStartup()) {
+ static const size_t kInitialCacheSize = 1024;
+ static const size_t kMaximumCacheSize = 10240;
+
+ mDisplayItemCache.SetCapacity(kInitialCacheSize, kMaximumCacheSize);
+ }
+}
+
+KnowsCompositor* WebRenderLayerManager::AsKnowsCompositor() { return mWrChild; }
+
+bool WebRenderLayerManager::Initialize(
+ PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId,
+ TextureFactoryIdentifier* aTextureFactoryIdentifier, nsCString& aError) {
+ MOZ_ASSERT(mWrChild == nullptr);
+ MOZ_ASSERT(aTextureFactoryIdentifier);
+
+ // When we fail to initialize WebRender, it is useful to know if it has ever
+ // succeeded, or if this is the first attempt.
+ static bool hasInitialized = false;
+
+ WindowKind windowKind;
+ if (mWidget->WindowType() != eWindowType_popup) {
+ windowKind = WindowKind::MAIN;
+ } else {
+ windowKind = WindowKind::SECONDARY;
+ }
+
+ LayoutDeviceIntSize size = mWidget->GetClientSize();
+ PWebRenderBridgeChild* bridge =
+ aCBChild->SendPWebRenderBridgeConstructor(aLayersId, size, windowKind);
+ if (!bridge) {
+ // This should only fail if we attempt to access a layer we don't have
+ // permission for, or more likely, the GPU process crashed again during
+ // reinitialization. We can expect to be notified again to reinitialize
+ // (which may or may not be using WebRender).
+ gfxCriticalNote << "Failed to create WebRenderBridgeChild.";
+ aError.Assign(hasInitialized
+ ? "FEATURE_FAILURE_WEBRENDER_INITIALIZE_IPDL_POST"_ns
+ : "FEATURE_FAILURE_WEBRENDER_INITIALIZE_IPDL_FIRST"_ns);
+ return false;
+ }
+
+ TextureFactoryIdentifier textureFactoryIdentifier;
+ wr::MaybeIdNamespace idNamespace;
+ // Sync ipc
+ if (!bridge->SendEnsureConnected(&textureFactoryIdentifier, &idNamespace,
+ &aError)) {
+ gfxCriticalNote << "Failed as lost WebRenderBridgeChild.";
+ aError.Assign(hasInitialized
+ ? "FEATURE_FAILURE_WEBRENDER_INITIALIZE_SYNC_POST"_ns
+ : "FEATURE_FAILURE_WEBRENDER_INITIALIZE_SYNC_FIRST"_ns);
+ return false;
+ }
+
+ if (textureFactoryIdentifier.mParentBackend == LayersBackend::LAYERS_NONE ||
+ idNamespace.isNothing()) {
+ gfxCriticalNote << "Failed to connect WebRenderBridgeChild.";
+ aError.Append(hasInitialized ? "_POST"_ns : "_FIRST"_ns);
+ return false;
+ }
+
+ mWrChild = static_cast<WebRenderBridgeChild*>(bridge);
+ WrBridge()->SetWebRenderLayerManager(this);
+ WrBridge()->IdentifyTextureHost(textureFactoryIdentifier);
+ WrBridge()->SetNamespace(idNamespace.ref());
+ *aTextureFactoryIdentifier = textureFactoryIdentifier;
+ hasInitialized = true;
+ return true;
+}
+
+void WebRenderLayerManager::Destroy() { DoDestroy(/* aIsSync */ false); }
+
+void WebRenderLayerManager::DoDestroy(bool aIsSync) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (IsDestroyed()) {
+ return;
+ }
+
+ LayerManager::Destroy();
+
+ mStateManager.Destroy();
+
+ if (WrBridge()) {
+ WrBridge()->Destroy(aIsSync);
+ }
+
+ mWebRenderCommandBuilder.Destroy();
+
+ if (mTransactionIdAllocator) {
+ // Make sure to notify the refresh driver just in case it's waiting on a
+ // pending transaction. Do this at the top of the event loop so we don't
+ // cause a paint to occur during compositor shutdown.
+ RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
+ TransactionId id = mLatestTransactionId;
+
+ RefPtr<Runnable> task = NS_NewRunnableFunction(
+ "TransactionIdAllocator::NotifyTransactionCompleted",
+ [allocator, id]() -> void {
+ allocator->NotifyTransactionCompleted(id);
+ });
+ NS_DispatchToMainThread(task.forget());
+ }
+
+ // Forget the widget pointer in case we outlive our owning widget.
+ mWidget = nullptr;
+}
+
+WebRenderLayerManager::~WebRenderLayerManager() {
+ Destroy();
+ MOZ_COUNT_DTOR(WebRenderLayerManager);
+}
+
+CompositorBridgeChild* WebRenderLayerManager::GetCompositorBridgeChild() {
+ return WrBridge()->GetCompositorBridgeChild();
+}
+
+void WebRenderLayerManager::GetBackendName(nsAString& name) {
+ if (WrBridge()->UsingSoftwareWebRenderD3D11()) {
+ name.AssignLiteral("WebRender (Software D3D11)");
+ } else if (WrBridge()->UsingSoftwareWebRender()) {
+ name.AssignLiteral("WebRender (Software)");
+ } else {
+ name.AssignLiteral("WebRender");
+ }
+}
+
+uint32_t WebRenderLayerManager::StartFrameTimeRecording(int32_t aBufferSize) {
+ CompositorBridgeChild* renderer = GetCompositorBridgeChild();
+ if (renderer) {
+ uint32_t startIndex;
+ renderer->SendStartFrameTimeRecording(aBufferSize, &startIndex);
+ return startIndex;
+ }
+ return -1;
+}
+
+void WebRenderLayerManager::StopFrameTimeRecording(
+ uint32_t aStartIndex, nsTArray<float>& aFrameIntervals) {
+ CompositorBridgeChild* renderer = GetCompositorBridgeChild();
+ if (renderer) {
+ renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
+ }
+}
+
+void WebRenderLayerManager::PayloadPresented(const TimeStamp& aTimeStamp) {
+ MOZ_CRASH("WebRenderLayerManager::PayloadPresented should not be called");
+}
+
+void WebRenderLayerManager::TakeCompositionPayloads(
+ nsTArray<CompositionPayload>& aPayloads) {
+ aPayloads.Clear();
+
+ std::swap(mPayload, aPayloads);
+}
+
+bool WebRenderLayerManager::BeginTransactionWithTarget(gfxContext* aTarget,
+ const nsCString& aURL) {
+ mTarget = aTarget;
+ return BeginTransaction(aURL);
+}
+
+bool WebRenderLayerManager::BeginTransaction(const nsCString& aURL) {
+ if (!WrBridge()->IPCOpen()) {
+ gfxCriticalNote << "IPC Channel is already torn down unexpectedly\n";
+ return false;
+ }
+
+ mTransactionStart = TimeStamp::Now();
+ mURL = aURL;
+
+ // Increment the paint sequence number even if test logging isn't
+ // enabled in this process; it may be enabled in the parent process,
+ // and the parent process expects unique sequence numbers.
+ ++mPaintSequenceNumber;
+ if (StaticPrefs::apz_test_logging_enabled()) {
+ mApzTestData.StartNewPaint(mPaintSequenceNumber);
+ }
+ return true;
+}
+
+bool WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) {
+ // If we haven't sent a display list (since creation or since the last time we
+ // sent ClearDisplayList to the parent) then we can't do an empty transaction
+ // because the parent doesn't have a display list for us and we need to send a
+ // display list first.
+ if (!WrBridge()->GetSentDisplayList()) {
+ return false;
+ }
+
+ mDisplayItemCache.SkipWaitingForPartialDisplayList();
+
+ // Since we don't do repeat transactions right now, just set the time
+ mAnimationReadyTime = TimeStamp::Now();
+
+ mLatestTransactionId =
+ mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true);
+
+ if (aFlags & EndTransactionFlags::END_NO_COMPOSITE &&
+ !mWebRenderCommandBuilder.NeedsEmptyTransaction()) {
+ if (mPendingScrollUpdates.IsEmpty()) {
+ MOZ_ASSERT(!mTarget);
+ WrBridge()->SendSetFocusTarget(mFocusTarget);
+ // Revoke TransactionId to trigger next paint.
+ mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
+ mLatestTransactionId = mLatestTransactionId.Prev();
+ return true;
+ }
+ }
+
+ LayoutDeviceIntSize size = mWidget->GetClientSize();
+ WrBridge()->BeginTransaction();
+
+ mWebRenderCommandBuilder.EmptyTransaction();
+
+ // Get the time of when the refresh driver start its tick (if available),
+ // otherwise use the time of when LayerManager::BeginTransaction was called.
+ TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
+ if (!refreshStart) {
+ refreshStart = mTransactionStart;
+ }
+
+ // Skip the synchronization for buffer since we also skip the painting during
+ // device-reset status.
+ if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+ if (WrBridge()->GetSyncObject() &&
+ WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
+ WrBridge()->GetSyncObject()->Synchronize();
+ }
+ }
+
+ GetCompositorBridgeChild()->EndCanvasTransaction();
+
+ Maybe<TransactionData> transactionData;
+ if (mStateManager.mAsyncResourceUpdates || !mPendingScrollUpdates.IsEmpty() ||
+ WrBridge()->HasWebRenderParentCommands()) {
+ transactionData.emplace();
+ transactionData->mIdNamespace = WrBridge()->GetNamespace();
+ transactionData->mPaintSequenceNumber = mPaintSequenceNumber;
+ if (mStateManager.mAsyncResourceUpdates) {
+ mStateManager.mAsyncResourceUpdates->Flush(
+ transactionData->mResourceUpdates, transactionData->mSmallShmems,
+ transactionData->mLargeShmems);
+ }
+ transactionData->mScrollUpdates = std::move(mPendingScrollUpdates);
+ for (auto it = transactionData->mScrollUpdates.Iter(); !it.Done();
+ it.Next()) {
+ nsLayoutUtils::NotifyPaintSkipTransaction(/*scroll id=*/it.Key());
+ }
+ }
+
+ Maybe<wr::IpcResourceUpdateQueue> nothing;
+ WrBridge()->EndEmptyTransaction(mFocusTarget, std::move(transactionData),
+ mLatestTransactionId,
+ mTransactionIdAllocator->GetVsyncId(),
+ mTransactionIdAllocator->GetVsyncStart(),
+ refreshStart, mTransactionStart, mURL);
+ mTransactionStart = TimeStamp();
+
+ MakeSnapshotIfRequired(size);
+ return true;
+}
+
+void WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
+ void* aCallbackData,
+ EndTransactionFlags aFlags) {
+ // This should never get called, all callers should use
+ // EndTransactionWithoutLayer instead.
+ MOZ_ASSERT(false);
+}
+
+void WebRenderLayerManager::EndTransactionWithoutLayer(
+ nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
+ WrFiltersHolder&& aFilters, WebRenderBackgroundData* aBackground) {
+ AUTO_PROFILER_TRACING_MARKER("Paint", "RenderLayers", GRAPHICS);
+
+ // Since we don't do repeat transactions right now, just set the time
+ mAnimationReadyTime = TimeStamp::Now();
+
+ WrBridge()->BeginTransaction();
+
+ LayoutDeviceIntSize size = mWidget->GetClientSize();
+
+ // While the first display list after tab-switch can be large, the
+ // following ones are always smaller thanks to interning (rarely above 0.3MB).
+ // So don't let the spike of the first allocation make us allocate a large
+ // contiguous buffer (with some likelihood of OOM, see bug 1531819).
+ static const size_t kMaxPrealloc = 300000;
+ size_t preallocate =
+ mLastDisplayListSize < kMaxPrealloc ? mLastDisplayListSize : kMaxPrealloc;
+
+ wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), preallocate,
+ &mDisplayItemCache);
+
+ wr::IpcResourceUpdateQueue resourceUpdates(WrBridge());
+ wr::usize builderDumpIndex = 0;
+ bool containsSVGGroup = false;
+ bool dumpEnabled =
+ mWebRenderCommandBuilder.ShouldDumpDisplayList(aDisplayListBuilder);
+ Maybe<AutoDisplayItemCacheSuppressor> cacheSuppressor;
+ if (dumpEnabled) {
+ cacheSuppressor.emplace(&mDisplayItemCache);
+ printf_stderr("-- WebRender display list build --\n");
+ }
+
+ if (XRE_IsContentProcess() &&
+ StaticPrefs::gfx_webrender_dl_dump_content_serialized()) {
+ builder.DumpSerializedDisplayList();
+ }
+
+ if (aDisplayList) {
+ MOZ_ASSERT(aDisplayListBuilder && !aBackground);
+ // Record the time spent "layerizing". WR doesn't actually layerize but
+ // generating the WR display list is the closest equivalent
+ PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
+
+ mDisplayItemCache.SetDisplayList(aDisplayListBuilder, aDisplayList);
+
+ mWebRenderCommandBuilder.BuildWebRenderCommands(
+ builder, resourceUpdates, aDisplayList, aDisplayListBuilder,
+ mScrollData, std::move(aFilters));
+
+ aDisplayListBuilder->NotifyAndClearScrollFrames();
+
+ builderDumpIndex = mWebRenderCommandBuilder.GetBuilderDumpIndex();
+ containsSVGGroup = mWebRenderCommandBuilder.GetContainsSVGGroup();
+ } else {
+ // ViewToPaint does not have frame yet, then render only background clolor.
+ MOZ_ASSERT(!aDisplayListBuilder && aBackground);
+ aBackground->AddWebRenderCommands(builder);
+ if (dumpEnabled) {
+ printf_stderr("(no display list; background only)\n");
+ builderDumpIndex =
+ builder.Dump(/*indent*/ 1, Some(builderDumpIndex), Nothing());
+ }
+ }
+
+ mWidget->AddWindowOverlayWebRenderCommands(WrBridge(), builder,
+ resourceUpdates);
+ if (dumpEnabled) {
+ printf_stderr("(window overlay)\n");
+ Unused << builder.Dump(/*indent*/ 1, Some(builderDumpIndex), Nothing());
+ }
+
+ if (AsyncPanZoomEnabled()) {
+ if (mIsFirstPaint) {
+ mScrollData.SetIsFirstPaint();
+ mIsFirstPaint = false;
+ }
+ mScrollData.SetPaintSequenceNumber(mPaintSequenceNumber);
+ if (dumpEnabled) {
+ std::stringstream str;
+ str << mScrollData;
+ print_stderr(str);
+ }
+ }
+
+ // Since we're sending a full mScrollData that will include the new scroll
+ // offsets, and we can throw away the pending scroll updates we had kept for
+ // an empty transaction.
+ auto scrollIdsUpdated = ClearPendingScrollInfoUpdate();
+ for (ScrollableLayerGuid::ViewID update : scrollIdsUpdated) {
+ nsLayoutUtils::NotifyPaintSkipTransaction(update);
+ }
+
+ mLatestTransactionId =
+ mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true);
+
+ // Get the time of when the refresh driver start its tick (if available),
+ // otherwise use the time of when LayerManager::BeginTransaction was called.
+ TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
+ if (!refreshStart) {
+ refreshStart = mTransactionStart;
+ }
+
+ if (mStateManager.mAsyncResourceUpdates) {
+ if (resourceUpdates.IsEmpty()) {
+ resourceUpdates.ReplaceResources(
+ std::move(mStateManager.mAsyncResourceUpdates.ref()));
+ } else {
+ WrBridge()->UpdateResources(mStateManager.mAsyncResourceUpdates.ref());
+ }
+ mStateManager.mAsyncResourceUpdates.reset();
+ }
+ mStateManager.DiscardImagesInTransaction(resourceUpdates);
+
+ WrBridge()->RemoveExpiredFontKeys(resourceUpdates);
+
+ // Skip the synchronization for buffer since we also skip the painting during
+ // device-reset status.
+ if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+ if (WrBridge()->GetSyncObject() &&
+ WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
+ WrBridge()->GetSyncObject()->Synchronize();
+ }
+ }
+
+ GetCompositorBridgeChild()->EndCanvasTransaction();
+
+ {
+ AUTO_PROFILER_TRACING_MARKER("Paint", "ForwardDPTransaction", GRAPHICS);
+ DisplayListData dlData;
+ builder.Finalize(dlData);
+ mLastDisplayListSize = dlData.mDL->mCapacity;
+ resourceUpdates.Flush(dlData.mResourceUpdates, dlData.mSmallShmems,
+ dlData.mLargeShmems);
+ dlData.mRect =
+ LayoutDeviceRect(LayoutDevicePoint(), LayoutDeviceSize(size));
+ dlData.mScrollData.emplace(std::move(mScrollData));
+
+ bool ret = WrBridge()->EndTransaction(
+ std::move(dlData), mLatestTransactionId, containsSVGGroup,
+ mTransactionIdAllocator->GetVsyncId(),
+ mTransactionIdAllocator->GetVsyncStart(), refreshStart,
+ mTransactionStart, mURL);
+ if (!ret) {
+ // Failed to send display list, reset display item cache state.
+ mDisplayItemCache.Clear();
+ }
+
+ WrBridge()->SendSetFocusTarget(mFocusTarget);
+ mFocusTarget = FocusTarget();
+ }
+
+ // Discard animations after calling WrBridge()->EndTransaction().
+ // It updates mWrEpoch in WebRenderBridgeParent. The updated mWrEpoch is
+ // necessary for deleting animations at the correct time.
+ mStateManager.DiscardCompositorAnimations();
+
+ mTransactionStart = TimeStamp();
+
+ MakeSnapshotIfRequired(size);
+ mNeedsComposite = false;
+}
+
+void WebRenderLayerManager::SetFocusTarget(const FocusTarget& aFocusTarget) {
+ mFocusTarget = aFocusTarget;
+}
+
+bool WebRenderLayerManager::AsyncPanZoomEnabled() const {
+ return mWidget->AsyncPanZoomEnabled();
+}
+
+void WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize) {
+ if (!mTarget || aSize.IsEmpty()) {
+ return;
+ }
+
+ // XXX Add other TextureData supports.
+ // Only BufferTexture is supported now.
+
+ // TODO: fixup for proper surface format.
+ // The GLES spec only guarantees that RGBA can be used with glReadPixels,
+ // so on Android we use RGBA.
+ SurfaceFormat format =
+#ifdef MOZ_WIDGET_ANDROID
+ SurfaceFormat::R8G8B8A8;
+#else
+ SurfaceFormat::B8G8R8A8;
+#endif
+ RefPtr<TextureClient> texture = TextureClient::CreateForRawBufferAccess(
+ WrBridge(), format, aSize.ToUnknownSize(), BackendType::SKIA,
+ TextureFlags::SNAPSHOT);
+ if (!texture) {
+ return;
+ }
+
+ texture->InitIPDLActor(WrBridge());
+ if (!texture->GetIPDLActor()) {
+ return;
+ }
+
+ IntRect bounds = ToOutsideIntRect(mTarget->GetClipExtents());
+ bool needsYFlip = false;
+ if (!WrBridge()->SendGetSnapshot(texture->GetIPDLActor(), &needsYFlip)) {
+ return;
+ }
+
+ TextureClientAutoLock autoLock(texture, OpenMode::OPEN_READ_ONLY);
+ if (!autoLock.Succeeded()) {
+ return;
+ }
+ RefPtr<DrawTarget> drawTarget = texture->BorrowDrawTarget();
+ if (!drawTarget || !drawTarget->IsValid()) {
+ return;
+ }
+ RefPtr<SourceSurface> snapshot = drawTarget->Snapshot();
+ /*
+ static int count = 0;
+ char filename[100];
+ snprintf(filename, 100, "output%d.png", count++);
+ printf_stderr("Writing to :%s\n", filename);
+ gfxUtils::WriteAsPNG(snapshot, filename);
+ */
+
+ Rect dst(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height());
+ Rect src(0, 0, bounds.Width(), bounds.Height());
+
+ Matrix m;
+ if (needsYFlip) {
+ m = Matrix::Scaling(1.0, -1.0).PostTranslate(0.0, aSize.height);
+ }
+ SurfacePattern pattern(snapshot, ExtendMode::CLAMP, m);
+ DrawTarget* dt = mTarget->GetDrawTarget();
+ MOZ_RELEASE_ASSERT(dt);
+ dt->FillRect(dst, pattern);
+
+ mTarget = nullptr;
+}
+
+void WebRenderLayerManager::DiscardImages() {
+ wr::IpcResourceUpdateQueue resources(WrBridge());
+ mStateManager.DiscardImagesInTransaction(resources);
+ WrBridge()->UpdateResources(resources);
+}
+
+void WebRenderLayerManager::DiscardLocalImages() {
+ mStateManager.DiscardLocalImages();
+}
+
+void WebRenderLayerManager::SetLayersObserverEpoch(LayersObserverEpoch aEpoch) {
+ if (WrBridge()->IPCOpen()) {
+ WrBridge()->SendSetLayersObserverEpoch(aEpoch);
+ }
+}
+
+void WebRenderLayerManager::DidComposite(
+ TransactionId aTransactionId, const mozilla::TimeStamp& aCompositeStart,
+ const mozilla::TimeStamp& aCompositeEnd) {
+ if (IsDestroyed()) {
+ return;
+ }
+
+ MOZ_ASSERT(mWidget);
+
+ // Notifying the observers may tick the refresh driver which can cause
+ // a lot of different things to happen that may affect the lifetime of
+ // this layer manager. So let's make sure this object stays alive until
+ // the end of the method invocation.
+ RefPtr<WebRenderLayerManager> selfRef = this;
+
+ // |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
+ // layers transaction.
+ if (aTransactionId.IsValid()) {
+ nsIWidgetListener* listener = mWidget->GetWidgetListener();
+ if (listener) {
+ listener->DidCompositeWindow(aTransactionId, aCompositeStart,
+ aCompositeEnd);
+ }
+ listener = mWidget->GetAttachedWidgetListener();
+ if (listener) {
+ listener->DidCompositeWindow(aTransactionId, aCompositeStart,
+ aCompositeEnd);
+ }
+ if (mTransactionIdAllocator) {
+ mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
+ }
+ }
+
+ // These observers fire whether or not we were in a transaction.
+ for (size_t i = 0; i < mDidCompositeObservers.Length(); i++) {
+ mDidCompositeObservers[i]->DidComposite();
+ }
+}
+
+void WebRenderLayerManager::ClearCachedResources(Layer* aSubtree) {
+ if (!WrBridge()->IPCOpen()) {
+ gfxCriticalNote << "IPC Channel is already torn down unexpectedly\n";
+ return;
+ }
+ WrBridge()->BeginClearCachedResources();
+ mWebRenderCommandBuilder.ClearCachedResources();
+ DiscardImages();
+ mStateManager.ClearCachedResources();
+ WrBridge()->EndClearCachedResources();
+}
+
+void WebRenderLayerManager::WrUpdated() {
+ ClearAsyncAnimations();
+ mWebRenderCommandBuilder.ClearCachedResources();
+ DiscardLocalImages();
+ mDisplayItemCache.Clear();
+
+ if (mWidget) {
+ if (dom::BrowserChild* browserChild = mWidget->GetOwningBrowserChild()) {
+ browserChild->SchedulePaint();
+ }
+ }
+}
+
+void WebRenderLayerManager::UpdateTextureFactoryIdentifier(
+ const TextureFactoryIdentifier& aNewIdentifier) {
+ WrBridge()->IdentifyTextureHost(aNewIdentifier);
+}
+
+TextureFactoryIdentifier WebRenderLayerManager::GetTextureFactoryIdentifier() {
+ return WrBridge()->GetTextureFactoryIdentifier();
+}
+
+void WebRenderLayerManager::SetTransactionIdAllocator(
+ TransactionIdAllocator* aAllocator) {
+ // When changing the refresh driver, the previous refresh driver may never
+ // receive updates of pending transactions it's waiting for. So clear the
+ // waiting state before assigning another refresh driver.
+ if (mTransactionIdAllocator && (aAllocator != mTransactionIdAllocator)) {
+ mTransactionIdAllocator->ClearPendingTransactions();
+
+ // We should also reset the transaction id of the new allocator to previous
+ // allocator's last transaction id, so that completed transactions for
+ // previous allocator will be ignored and won't confuse the new allocator.
+ if (aAllocator) {
+ aAllocator->ResetInitialTransactionId(
+ mTransactionIdAllocator->LastTransactionId());
+ }
+ }
+
+ mTransactionIdAllocator = aAllocator;
+}
+
+TransactionId WebRenderLayerManager::GetLastTransactionId() {
+ return mLatestTransactionId;
+}
+
+void WebRenderLayerManager::AddDidCompositeObserver(
+ DidCompositeObserver* aObserver) {
+ if (!mDidCompositeObservers.Contains(aObserver)) {
+ mDidCompositeObservers.AppendElement(aObserver);
+ }
+}
+
+void WebRenderLayerManager::RemoveDidCompositeObserver(
+ DidCompositeObserver* aObserver) {
+ mDidCompositeObservers.RemoveElement(aObserver);
+}
+
+void WebRenderLayerManager::FlushRendering() {
+ CompositorBridgeChild* cBridge = GetCompositorBridgeChild();
+ if (!cBridge) {
+ return;
+ }
+ MOZ_ASSERT(mWidget);
+
+ // If value of IsResizingNativeWidget() is nothing, we assume that resizing
+ // might happen.
+ bool resizing = mWidget && mWidget->IsResizingNativeWidget().valueOr(true);
+
+ // Limit async FlushRendering to !resizing and Win DComp.
+ // XXX relax the limitation
+ if (WrBridge()->GetCompositorUseDComp() && !resizing) {
+ cBridge->SendFlushRenderingAsync();
+ } else if (mWidget->SynchronouslyRepaintOnResize() ||
+ StaticPrefs::layers_force_synchronous_resize()) {
+ cBridge->SendFlushRendering();
+ } else {
+ cBridge->SendFlushRenderingAsync();
+ }
+}
+
+void WebRenderLayerManager::WaitOnTransactionProcessed() {
+ CompositorBridgeChild* bridge = GetCompositorBridgeChild();
+ if (bridge) {
+ bridge->SendWaitOnTransactionProcessed();
+ }
+}
+
+void WebRenderLayerManager::SendInvalidRegion(const nsIntRegion& aRegion) {
+ // XXX Webrender does not support invalid region yet.
+
+#ifdef XP_WIN
+ // When DWM is disabled, each window does not have own back buffer. They would
+ // paint directly to a buffer that was to be displayed by the video card.
+ // WM_PAINT via SendInvalidRegion() requests necessary re-paint.
+ const bool needsInvalidate = !gfx::gfxVars::DwmCompositionEnabled();
+#else
+ const bool needsInvalidate = true;
+#endif
+ if (needsInvalidate && WrBridge()) {
+ WrBridge()->SendInvalidateRenderedFrame();
+ }
+}
+
+void WebRenderLayerManager::ScheduleComposite() {
+ WrBridge()->SendScheduleComposite();
+}
+
+void WebRenderLayerManager::SetRoot(Layer* aLayer) {
+ // This should never get called
+ MOZ_ASSERT(false);
+}
+
+already_AddRefed<PersistentBufferProvider>
+WebRenderLayerManager::CreatePersistentBufferProvider(
+ const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat) {
+ // Ensure devices initialization for canvas 2d. The devices are lazily
+ // initialized with WebRender to reduce memory usage.
+ gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
+
+ RefPtr<PersistentBufferProvider> provider =
+ PersistentBufferProviderShared::Create(aSize, aFormat,
+ AsKnowsCompositor());
+ if (provider) {
+ return provider.forget();
+ }
+
+ return LayerManager::CreatePersistentBufferProvider(aSize, aFormat);
+}
+
+void WebRenderLayerManager::ClearAsyncAnimations() {
+ mStateManager.ClearAsyncAnimations();
+}
+
+void WebRenderLayerManager::WrReleasedImages(
+ const nsTArray<wr::ExternalImageKeyPair>& aPairs) {
+ mStateManager.WrReleasedImages(aPairs);
+}
+
+void WebRenderLayerManager::GetFrameUniformity(FrameUniformityData* aOutData) {
+ WrBridge()->SendGetFrameUniformity(aOutData);
+}
+
+} // namespace layers
+} // namespace mozilla