/* -*- 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(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 allocator = mTransactionIdAllocator; TransactionId id = mLatestTransactionId; RefPtr 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& 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& 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; 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 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 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 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 = texture->BorrowDrawTarget(); if (!drawTarget || !drawTarget->IsValid()) { return; } RefPtr 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 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 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 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& aPairs) { mStateManager.WrReleasedImages(aPairs); } void WebRenderLayerManager::GetFrameUniformity(FrameUniformityData* aOutData) { WrBridge()->SendGetFrameUniformity(aOutData); } } // namespace layers } // namespace mozilla