summaryrefslogtreecommitdiffstats
path: root/gfx/layers/wr/WebRenderLayerManager.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /gfx/layers/wr/WebRenderLayerManager.cpp
parentInitial commit. (diff)
downloadfirefox-e51783d008170d9ab27d25da98ca3a38b0a41b67.tar.xz
firefox-e51783d008170d9ab27d25da98ca3a38b0a41b67.zip
Adding upstream version 124.0.1.upstream/124.0.1
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.cpp803
1 files changed, 803 insertions, 0 deletions
diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp
new file mode 100644
index 0000000000..66b98a7db3
--- /dev/null
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -0,0 +1,803 @@
+/* -*- 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 "GeckoProfiler.h"
+#include "mozilla/StaticPrefs_apz.h"
+#include "mozilla/StaticPrefs_layers.h"
+#include "mozilla/dom/BrowserChild.h"
+#include "mozilla/gfx/DrawEventRecorder.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 "mozilla/PerfStats.h"
+#include "nsDisplayList.h"
+#include "nsLayoutUtils.h"
+#include "WebRenderCanvasRenderer.h"
+#include "LayerUserData.h"
+
+#ifdef XP_WIN
+# include "gfxDWriteFonts.h"
+# include "mozilla/WindowsProcessMitigations.h"
+#endif
+
+namespace mozilla {
+
+using namespace gfx;
+
+namespace layers {
+
+WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
+ : mWidget(aWidget),
+ mLatestTransactionId{0},
+ mNeedsComposite(false),
+ mIsFirstPaint(false),
+ mDestroyed(false),
+ mTarget(nullptr),
+ mPaintSequenceNumber(0),
+ mWebRenderCommandBuilder(this) {
+ 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->GetWindowType() != widget::WindowType::Popup) {
+ windowKind = WindowKind::MAIN;
+ } else {
+ windowKind = WindowKind::SECONDARY;
+ }
+
+ LayoutDeviceIntSize size = mWidget->GetClientSize();
+ // Check widget size
+ if (!wr::WindowSizeSanityCheck(size.width, size.height)) {
+ gfxCriticalNoteOnce << "Widget size is not valid " << size
+ << " isParent: " << XRE_IsParentProcess();
+ }
+
+ 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;
+ }
+
+ mWrChild = static_cast<WebRenderBridgeChild*>(bridge);
+
+ TextureFactoryIdentifier textureFactoryIdentifier;
+ wr::MaybeIdNamespace idNamespace;
+ // Sync ipc
+ if (!WrBridge()->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. isParent="
+ << XRE_IsParentProcess();
+ aError.Append(hasInitialized ? "_POST"_ns : "_FIRST"_ns);
+ return false;
+ }
+
+ WrBridge()->SetWebRenderLayerManager(this);
+ WrBridge()->IdentifyTextureHost(textureFactoryIdentifier);
+ WrBridge()->SetNamespace(idNamespace.ref());
+ *aTextureFactoryIdentifier = textureFactoryIdentifier;
+
+ mDLBuilder = MakeUnique<wr::DisplayListBuilder>(
+ WrBridge()->GetPipeline(), WrBridge()->GetWebRenderBackend());
+
+ hasInitialized = true;
+ return true;
+}
+
+void WebRenderLayerManager::Destroy() { DoDestroy(/* aIsSync */ false); }
+
+void WebRenderLayerManager::DoDestroy(bool aIsSync) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (IsDestroyed()) {
+ return;
+ }
+
+ mDLBuilder = nullptr;
+ mUserData.Destroy();
+ mPartialPrerenderedAnimations.Clear();
+
+ 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->ClearPendingTransactions();
+ allocator->NotifyTransactionCompleted(id);
+ });
+ NS_DispatchToMainThread(task.forget());
+ }
+
+ // Forget the widget pointer in case we outlive our owning widget.
+ mWidget = nullptr;
+ mDestroyed = true;
+}
+
+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()->UsingSoftwareWebRenderOpenGL()) {
+ name.AssignLiteral("WebRender (Software OpenGL)");
+ } 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::TakeCompositionPayloads(
+ nsTArray<CompositionPayload>& aPayloads) {
+ aPayloads.Clear();
+
+ std::swap(mPayload, aPayloads);
+}
+
+bool WebRenderLayerManager::BeginTransactionWithTarget(gfxContext* aTarget,
+ const nsCString& aURL) {
+ mTarget = aTarget;
+ bool retval = BeginTransaction(aURL);
+ if (!retval) {
+ mTarget = nullptr;
+ }
+ return retval;
+}
+
+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) {
+ auto clearTarget = MakeScopeExit([&] { mTarget = nullptr; });
+
+ // 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();
+
+ // Don't block on hidden windows on Linux as it may block all rendering.
+ const bool throttle = mWidget->IsMapped();
+ mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(throttle);
+
+ 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 (const auto& scrollId : transactionData->mScrollUpdates.Keys()) {
+ nsLayoutUtils::NotifyPaintSkipTransaction(/*scroll id=*/scrollId);
+ }
+ }
+
+ 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::EndTransactionWithoutLayer(
+ nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
+ WrFiltersHolder&& aFilters, WebRenderBackgroundData* aBackground,
+ const double aGeckoDLBuildTime) {
+ AUTO_PROFILER_TRACING_MARKER("Paint", "WrDisplayList", GRAPHICS);
+
+ auto clearTarget = MakeScopeExit([&] { mTarget = nullptr; });
+
+ WrBridge()->BeginTransaction();
+
+ LayoutDeviceIntSize size = mWidget->GetClientSize();
+
+ mDLBuilder->Begin(&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_debug_dl_dump_content_serialized()) {
+ mDLBuilder->DumpSerializedDisplayList();
+ }
+
+ if (aDisplayList) {
+ MOZ_ASSERT(aDisplayListBuilder && !aBackground);
+ mDisplayItemCache.SetDisplayList(aDisplayListBuilder, aDisplayList);
+
+ mWebRenderCommandBuilder.BuildWebRenderCommands(
+ *mDLBuilder, 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(*mDLBuilder);
+ if (dumpEnabled) {
+ printf_stderr("(no display list; background only)\n");
+ builderDumpIndex =
+ mDLBuilder->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);
+ }
+
+ // Don't block on hidden windows on Linux as it may block all rendering.
+ const bool throttle = mWidget->IsMapped();
+ mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(throttle);
+
+ // 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;
+ mDLBuilder->End(dlData);
+ resourceUpdates.Flush(dlData.mResourceUpdates, dlData.mSmallShmems,
+ dlData.mLargeShmems);
+ dlData.mRect =
+ LayoutDeviceRect(LayoutDevicePoint(), LayoutDeviceSize(size));
+ dlData.mScrollData.emplace(std::move(mScrollData));
+ dlData.mDLDesc.gecko_display_list_type =
+ aDisplayListBuilder && aDisplayListBuilder->PartialBuildFailed()
+ ? wr::GeckoDisplayListType::Full(aGeckoDLBuildTime)
+ : wr::GeckoDisplayListType::Partial(aGeckoDLBuildTime);
+
+ // convert from nanoseconds to microseconds
+ auto duration = TimeDuration::FromMicroseconds(
+ double(dlData.mDLDesc.builder_finish_time -
+ dlData.mDLDesc.builder_start_time) /
+ 1000.);
+ PerfStats::RecordMeasurement(PerfStats::Metric::WrDisplayListBuilding,
+ duration);
+ 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();
+}
+
+IntRect ToOutsideIntRect(const gfxRect& aRect) {
+ return IntRect::RoundOut(aRect.X(), aRect.Y(), aRect.Width(), aRect.Height());
+}
+
+void WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize) {
+ auto clearTarget = MakeScopeExit([&] { mTarget = nullptr; });
+
+ if (!mTarget || !mTarget->GetDrawTarget() || 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;
+ }
+
+ // The other side knows our ContentParentId and WebRenderBridgeChild will
+ // ignore the one provided here in favour of what WebRenderBridgeParent
+ // already has.
+ texture->InitIPDLActor(WrBridge(), dom::ContentParentId());
+ if (!texture->GetIPDLActor()) {
+ return;
+ }
+
+ IntRect bounds = ToOutsideIntRect(mTarget->GetClipExtents());
+ bool needsYFlip = false;
+ if (!WrBridge()->SendGetSnapshot(WrapNotNull(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::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);
+ }
+ }
+}
+
+void WebRenderLayerManager::ClearCachedResources() {
+ if (!WrBridge()->IPCOpen()) {
+ gfxCriticalNote << "IPC Channel is already torn down unexpectedly\n";
+ return;
+ }
+ WrBridge()->BeginClearCachedResources();
+ // We flush any pending async resource updates before we clear the display
+ // list items because some resources (e.g. images) might be shared between
+ // multiple layer managers, not get freed here, and we want to keep their
+ // states consistent.
+ mStateManager.FlushAsyncResourceUpdates();
+ mWebRenderCommandBuilder.ClearCachedResources();
+ DiscardImages();
+ mStateManager.ClearCachedResources();
+ CompositorBridgeChild* compositorBridge = GetCompositorBridgeChild();
+ if (compositorBridge) {
+ compositorBridge->ClearCachedResources();
+ }
+ WrBridge()->EndClearCachedResources();
+}
+
+void WebRenderLayerManager::ClearAnimationResources() {
+ if (!WrBridge()->IPCOpen()) {
+ gfxCriticalNote << "IPC Channel is already torn down unexpectedly\n";
+ return;
+ }
+ WrBridge()->SendClearAnimationResources();
+}
+
+void WebRenderLayerManager::WrUpdated() {
+ ClearAsyncAnimations();
+ mStateManager.mAsyncResourceUpdates.reset();
+ 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::FlushRendering(wr::RenderReasons aReasons) {
+ 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);
+
+ if (resizing) {
+ aReasons = aReasons | wr::RenderReasons::RESIZE;
+ }
+
+ // Limit async FlushRendering to !resizing and Win DComp.
+ // XXX relax the limitation
+ if (WrBridge()->GetCompositorUseDComp() && !resizing) {
+ cBridge->SendFlushRenderingAsync(aReasons);
+ } else if (mWidget->SynchronouslyRepaintOnResize() ||
+ StaticPrefs::layers_force_synchronous_resize()) {
+ cBridge->SendFlushRendering(aReasons);
+ } else {
+ cBridge->SendFlushRenderingAsync(aReasons);
+ }
+}
+
+void WebRenderLayerManager::WaitOnTransactionProcessed() {
+ CompositorBridgeChild* bridge = GetCompositorBridgeChild();
+ if (bridge) {
+ bridge->SendWaitOnTransactionProcessed();
+ }
+}
+
+void WebRenderLayerManager::SendInvalidRegion(const nsIntRegion& aRegion) {
+ // XXX Webrender does not support invalid region yet.
+
+#ifndef XP_WIN
+ if (WrBridge()) {
+ WrBridge()->SendInvalidateRenderedFrame();
+ }
+#endif
+}
+
+void WebRenderLayerManager::ScheduleComposite(wr::RenderReasons aReasons) {
+ WrBridge()->SendScheduleComposite(aReasons);
+}
+
+already_AddRefed<PersistentBufferProvider>
+WebRenderLayerManager::CreatePersistentBufferProvider(
+ const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
+ bool aWillReadFrequently) {
+ // Only initialize devices if hardware acceleration may possibly be used.
+ // Remoting moves hardware usage out-of-process, while will-read-frequently
+ // avoids hardware acceleration entirely.
+ if (!aWillReadFrequently && !gfxPlatform::UseRemoteCanvas()) {
+#ifdef XP_WIN
+ // Any kind of hardware acceleration is incompatible with Win32k Lockdown
+ // We don't initialize devices here so that PersistentBufferProviderShared
+ // will fall back to using a piece of shared memory as a backing for the
+ // canvas
+ if (!IsWin32kLockedDown()) {
+ gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
+ }
+#else
+ gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
+#endif
+ }
+
+ RefPtr<PersistentBufferProvider> provider =
+ PersistentBufferProviderShared::Create(
+ aSize, aFormat, AsKnowsCompositor(), aWillReadFrequently);
+ if (provider) {
+ return provider.forget();
+ }
+
+ return WindowRenderer::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);
+}
+
+/*static*/
+void WebRenderLayerManager::LayerUserDataDestroy(void* data) {
+ delete static_cast<LayerUserData*>(data);
+}
+
+UniquePtr<LayerUserData> WebRenderLayerManager::RemoveUserData(void* aKey) {
+ UniquePtr<LayerUserData> d(static_cast<LayerUserData*>(
+ mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
+ return d;
+}
+
+std::unordered_set<ScrollableLayerGuid::ViewID>
+WebRenderLayerManager::ClearPendingScrollInfoUpdate() {
+ std::unordered_set<ScrollableLayerGuid::ViewID> scrollIds(
+ mPendingScrollUpdates.Keys().cbegin(),
+ mPendingScrollUpdates.Keys().cend());
+ mPendingScrollUpdates.Clear();
+ return scrollIds;
+}
+
+} // namespace layers
+} // namespace mozilla