commit 8a79d4eeeaee24d3b7f3b637f6b042074250089d
parent 3dc42d023d79d2b8ac2d19b63a7059eca92d23ab
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date: Tue, 30 Dec 2025 13:22:02 +0000
Bug 2007997 - Remove non-blob fallback code-path. r=gfx-reviewers,aosmond
When this was introduced, we used to draw a lot more native widgets.
Nowadays:
* Outlines never hit this (we use webrender to paint them).
* The widgets that hit the fallback codepath are rather small
(checkboxes / radios / macOS buttons and dropdowns).
So let's simplify the code a bit. I wrote this to see if it helped with
bug 2007110 but I still think it's worth landing.
Differential Revision: https://phabricator.services.mozilla.com/D277637
Diffstat:
5 files changed, 71 insertions(+), 229 deletions(-)
diff --git a/gfx/layers/UpdateImageHelper.h b/gfx/layers/UpdateImageHelper.h
@@ -1,82 +0,0 @@
-/* -*- 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/. */
-
-#ifndef GFX_UPDATEIMAGEHELPER_H
-#define GFX_UPDATEIMAGEHELPER_H
-
-#include "mozilla/layers/CompositorTypes.h"
-#include "mozilla/layers/ImageClient.h"
-#include "mozilla/layers/TextureClient.h"
-#include "mozilla/layers/TextureClientRecycleAllocator.h"
-#include "mozilla/layers/TextureWrapperImage.h"
-#include "mozilla/gfx/Types.h"
-
-namespace mozilla {
-namespace layers {
-
-class UpdateImageHelper {
- public:
- UpdateImageHelper(ImageContainer* aImageContainer, ImageClient* aImageClient,
- gfx::IntSize aImageSize, gfx::SurfaceFormat aFormat)
- : mImageContainer(aImageContainer),
- mImageClient(aImageClient),
- mImageSize(aImageSize),
- mIsLocked(false) {
- mTexture = mImageClient->GetTextureClientRecycler()->CreateOrRecycle(
- aFormat, mImageSize, BackendSelector::Content, TextureFlags::DEFAULT);
- if (!mTexture) {
- return;
- }
-
- mIsLocked = mTexture->Lock(OpenMode::OPEN_WRITE_ONLY);
- if (!mIsLocked) {
- return;
- }
- }
-
- ~UpdateImageHelper() {
- if (mIsLocked) {
- mTexture->Unlock();
- mIsLocked = false;
- }
- }
-
- already_AddRefed<gfx::DrawTarget> GetDrawTarget() {
- RefPtr<gfx::DrawTarget> target;
- if (mTexture) {
- target = mTexture->BorrowDrawTarget();
- }
- return target.forget();
- }
-
- bool UpdateImage() {
- if (!mTexture) {
- return false;
- }
-
- if (mIsLocked) {
- mTexture->Unlock();
- mIsLocked = false;
- }
-
- RefPtr<TextureWrapperImage> image = new TextureWrapperImage(
- mTexture, gfx::IntRect(gfx::IntPoint(0, 0), mImageSize));
- mImageContainer->SetCurrentImageInTransaction(image);
- return mImageClient->UpdateImage(mImageContainer);
- }
-
- private:
- RefPtr<ImageContainer> mImageContainer;
- RefPtr<ImageClient> mImageClient;
- gfx::IntSize mImageSize;
- RefPtr<TextureClient> mTexture;
- bool mIsLocked;
-};
-
-} // namespace layers
-} // namespace mozilla
-
-#endif // GFX_UPDATEIMAGEHELPER_H
diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build
@@ -219,7 +219,6 @@ EXPORTS.mozilla.layers += [
"TextureWrapperImage.h",
"TransactionIdAllocator.h",
"TreeTraversal.h",
- "UpdateImageHelper.h",
"wr/AsyncImagePipelineManager.h",
"wr/AsyncImagePipelineOp.h",
"wr/ClipManager.h",
diff --git a/gfx/layers/wr/WebRenderCommandBuilder.cpp b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -28,7 +28,6 @@
#include "mozilla/layers/SharedSurfacesChild.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/layers/StackingContextHelper.h"
-#include "mozilla/layers/UpdateImageHelper.h"
#include "mozilla/layers/WebRenderDrawEventRecorder.h"
#include "UnitTransforms.h"
#include "gfxEnv.h"
@@ -361,7 +360,7 @@ struct DIGroup {
mFonts.clear();
}
- static LayerIntRect ToDeviceSpace(nsRect aBounds, Matrix& aMatrix,
+ static LayerIntRect ToDeviceSpace(const nsRect& aBounds, Matrix& aMatrix,
int32_t aAppUnitsPerDevPixel) {
// RoundedOut can convert empty rectangles to non-empty ones
// so special case them here
@@ -2496,11 +2495,9 @@ WebRenderCommandBuilder::GenerateFallbackData(
nsDisplayItem* aItem, wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources, const StackingContextHelper& aSc,
nsDisplayListBuilder* aDisplayListBuilder, LayoutDeviceRect& aImageRect) {
- bool useBlobImage = aItem->ShouldUseBlobRenderingForFallback();
- Maybe<gfx::DeviceColor> highlight = Nothing();
+ Maybe<gfx::DeviceColor> highlight;
if (StaticPrefs::gfx_webrender_debug_highlight_painted_layers()) {
- highlight = Some(useBlobImage ? gfx::DeviceColor(1.0, 0.0, 0.0, 0.5)
- : gfx::DeviceColor(1.0, 1.0, 0.0, 0.5));
+ highlight.emplace(gfx::DeviceColor(1.0, 0.0, 0.0, 0.5));
}
RefPtr<WebRenderFallbackData> fallbackData =
@@ -2585,13 +2582,8 @@ WebRenderCommandBuilder::GenerateFallbackData(
return nullptr;
}
- if (useBlobImage) {
- // Display item bounds should be unscaled
- aImageRect = visibleRect / layerScale;
- } else {
- // Display item bounds should be unscaled
- aImageRect = dtRect / layerScale;
- }
+ // Display item bounds should be unscaled
+ aImageRect = visibleRect / layerScale;
// We always paint items at 0,0 so the visibleRect that we use inside the blob
// is needs to be adjusted by the display item bounds top left.
@@ -2640,129 +2632,83 @@ WebRenderCommandBuilder::GenerateFallbackData(
: (opacity == wr::OpacityType::Opaque
? gfx::SurfaceFormat::B8G8R8X8
: gfx::SurfaceFormat::B8G8R8A8);
- if (useBlobImage) {
- MOZ_ASSERT(!opaqueRegion.IsComplex());
-
- std::vector<RefPtr<ScaledFont>> fonts;
- bool validFonts = true;
- RefPtr<WebRenderDrawEventRecorder> recorder =
- MakeAndAddRef<WebRenderDrawEventRecorder>(
- [&](MemStream& aStream,
- std::vector<RefPtr<ScaledFont>>& aScaledFonts) {
- size_t count = aScaledFonts.size();
- aStream.write((const char*)&count, sizeof(count));
- for (auto& scaled : aScaledFonts) {
- Maybe<wr::FontInstanceKey> key =
- mManager->WrBridge()->GetFontKeyForScaledFont(scaled,
- aResources);
- if (key.isNothing()) {
- validFonts = false;
- break;
- }
- BlobFont font = {key.value(), scaled};
- aStream.write((const char*)&font, sizeof(font));
- }
- fonts = std::move(aScaledFonts);
- });
- RefPtr<gfx::DrawTarget> dummyDt = gfx::Factory::CreateDrawTarget(
- gfx::BackendType::SKIA, gfx::IntSize(1, 1), format);
- RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(
- recorder, dummyDt, (dtRect - dtRect.TopLeft()).ToUnknownRect());
- if (aBuilder.GetInheritedOpacity() != 1.0f) {
- dt->PushLayer(false, aBuilder.GetInheritedOpacity(), nullptr,
- gfx::Matrix());
- }
- PaintItemByDrawTarget(aItem, dt, (dtRect / layerScale).TopLeft(),
- /*aVisibleRect: */ dt->GetRect(),
- aDisplayListBuilder, scale, highlight);
- if (aBuilder.GetInheritedOpacity() != 1.0f) {
- dt->PopLayer();
- }
-
- // the item bounds are relative to the blob origin which is
- // dtRect.TopLeft()
- recorder->FlushItem((dtRect - dtRect.TopLeft()).ToUnknownRect());
- recorder->Finish();
-
- if (!validFonts) {
- gfxCriticalNote << "Failed serializing fonts for blob image";
- return nullptr;
- }
-
- Range<uint8_t> bytes((uint8_t*)recorder->mOutputStream.mData,
- recorder->mOutputStream.mLength);
- wr::BlobImageKey key =
- wr::BlobImageKey{mManager->WrBridge()->GetNextImageKey()};
- wr::ImageDescriptor descriptor(visibleSize.ToUnknownSize(), 0,
- dt->GetFormat(), opacity);
- if (!aResources.AddBlobImage(
- key, descriptor, bytes,
- ViewAs<ImagePixel>(visibleRect,
- PixelCastJustification::LayerIsImage))) {
- return nullptr;
- }
- TakeExternalSurfaces(recorder, fallbackData->mExternalSurfaces,
- mManager->GetRenderRootStateManager(), aResources);
- fallbackData->SetBlobImageKey(key);
- fallbackData->SetFonts(fonts);
- } else {
- WebRenderImageData* imageData = fallbackData->PaintIntoImage();
+ MOZ_ASSERT(!opaqueRegion.IsComplex());
- imageData->CreateImageClientIfNeeded();
- RefPtr<ImageClient> imageClient = imageData->GetImageClient();
- RefPtr<ImageContainer> imageContainer = MakeAndAddRef<ImageContainer>(
- ImageUsageType::WebRenderFallbackData, ImageContainer::SYNCHRONOUS);
-
- {
- UpdateImageHelper helper(imageContainer, imageClient,
- dtRect.Size().ToUnknownSize(), format);
- {
- RefPtr<gfx::DrawTarget> dt = helper.GetDrawTarget();
- if (!dt) {
- return nullptr;
- }
- if (aBuilder.GetInheritedOpacity() != 1.0f) {
- dt->PushLayer(false, aBuilder.GetInheritedOpacity(), nullptr,
- gfx::Matrix());
- }
- PaintItemByDrawTarget(aItem, dt,
- /*aOffset: */ aImageRect.TopLeft(),
- /*aVisibleRect: */ dt->GetRect(),
- aDisplayListBuilder, scale, highlight);
- if (aBuilder.GetInheritedOpacity() != 1.0f) {
- dt->PopLayer();
- }
- }
+ std::vector<RefPtr<ScaledFont>> fonts;
+ bool validFonts = true;
+ RefPtr<WebRenderDrawEventRecorder> recorder =
+ MakeAndAddRef<WebRenderDrawEventRecorder>(
+ [&](MemStream& aStream,
+ std::vector<RefPtr<ScaledFont>>& aScaledFonts) {
+ size_t count = aScaledFonts.size();
+ aStream.write((const char*)&count, sizeof(count));
+ for (auto& scaled : aScaledFonts) {
+ Maybe<wr::FontInstanceKey> key =
+ mManager->WrBridge()->GetFontKeyForScaledFont(scaled,
+ aResources);
+ if (key.isNothing()) {
+ validFonts = false;
+ break;
+ }
+ BlobFont font = {key.value(), scaled};
+ aStream.write((const char*)&font, sizeof(font));
+ }
+ fonts = std::move(aScaledFonts);
+ });
+ RefPtr<gfx::DrawTarget> dummyDt = gfx::Factory::CreateDrawTarget(
+ gfx::BackendType::SKIA, gfx::IntSize(1, 1), format);
+ RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(
+ recorder, dummyDt, (dtRect - dtRect.TopLeft()).ToUnknownRect());
+ if (aBuilder.GetInheritedOpacity() != 1.0f) {
+ dt->PushLayer(false, aBuilder.GetInheritedOpacity(), nullptr,
+ gfx::Matrix());
+ }
+ PaintItemByDrawTarget(aItem, dt, (dtRect / layerScale).TopLeft(),
+ /*aVisibleRect: */ dt->GetRect(), aDisplayListBuilder,
+ scale, highlight);
+ if (aBuilder.GetInheritedOpacity() != 1.0f) {
+ dt->PopLayer();
+ }
- // Update image if there it's invalidated.
- if (!helper.UpdateImage()) {
- return nullptr;
- }
- }
+ // the item bounds are relative to the blob origin which is
+ // dtRect.TopLeft()
+ recorder->FlushItem((dtRect - dtRect.TopLeft()).ToUnknownRect());
+ recorder->Finish();
- // Force update the key in fallback data since we repaint the image in
- // this path. If not force update, fallbackData may reuse the original key
- // because it doesn't know UpdateImageHelper already updated the image
- // container.
- if (!imageData->UpdateImageKey(imageContainer, aResources, true)) {
- return nullptr;
- }
+ if (!validFonts) {
+ gfxCriticalNote << "Failed serializing fonts for blob image";
+ return nullptr;
}
+ Range<uint8_t> bytes((uint8_t*)recorder->mOutputStream.mData,
+ recorder->mOutputStream.mLength);
+ wr::BlobImageKey key =
+ wr::BlobImageKey{mManager->WrBridge()->GetNextImageKey()};
+ wr::ImageDescriptor descriptor(visibleSize.ToUnknownSize(), 0,
+ dt->GetFormat(), opacity);
+ if (!aResources.AddBlobImage(
+ key, descriptor, bytes,
+ ViewAs<ImagePixel>(visibleRect,
+ PixelCastJustification::LayerIsImage))) {
+ return nullptr;
+ }
+ TakeExternalSurfaces(recorder, fallbackData->mExternalSurfaces,
+ mManager->GetRenderRootStateManager(), aResources);
+ fallbackData->SetBlobImageKey(key);
+ fallbackData->SetFonts(fonts);
+
fallbackData->mScale = scale;
fallbackData->mOpacity = aBuilder.GetInheritedOpacity();
fallbackData->SetInvalid(false);
}
- if (useBlobImage) {
- MOZ_DIAGNOSTIC_ASSERT(mManager->WrBridge()->MatchesNamespace(
- fallbackData->GetBlobImageKey().ref()),
- "Stale blob key for fallback!");
+ MOZ_DIAGNOSTIC_ASSERT(mManager->WrBridge()->MatchesNamespace(
+ fallbackData->GetBlobImageKey().ref()),
+ "Stale blob key for fallback!");
- aResources.SetBlobImageVisibleArea(
- fallbackData->GetBlobImageKey().value(),
- ViewAs<ImagePixel>(visibleRect, PixelCastJustification::LayerIsImage));
- }
+ aResources.SetBlobImageVisibleArea(
+ fallbackData->GetBlobImageKey().value(),
+ ViewAs<ImagePixel>(visibleRect, PixelCastJustification::LayerIsImage));
// Update current bounds to fallback data
fallbackData->mBounds = paintBounds;
diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -18,7 +18,6 @@
#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"
diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h
@@ -2787,16 +2787,6 @@ class nsDisplayItem {
virtual bool NeedsGeometryUpdates() const { return false; }
/**
- * When this item is rendered using fallback rendering, whether it should use
- * blob rendering (i.e. a recording DrawTarget), as opposed to a pixel-backed
- * DrawTarget.
- * Some items, such as those calling into the native themed widget machinery,
- * are more efficiently painted without blob recording. Those should return
- * false here.
- */
- virtual bool ShouldUseBlobRenderingForFallback() const { return true; }
-
- /**
* If this has a child list where the children are in the same coordinate
* system as this item (i.e., they have the same reference frame),
* return the list.
@@ -4515,10 +4505,6 @@ class nsDisplayThemedBackground : public nsPaintedDisplayItem {
layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) override;
- bool ShouldUseBlobRenderingForFallback() const override {
- return !XRE_IsParentProcess();
- }
-
/**
* GetBounds() returns the background painting area.
*/
@@ -4845,12 +4831,6 @@ class nsDisplayOutline final : public nsPaintedDisplayItem {
NS_DISPLAY_DECL_NAME("Outline", TYPE_OUTLINE)
- bool ShouldUseBlobRenderingForFallback() const override {
- MOZ_ASSERT(IsThemedOutline(),
- "The only fallback path we have is for themed outlines");
- return !XRE_IsParentProcess();
- }
-
bool CreateWebRenderCommands(
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,