From a11b08a3ac796fa28257fed68e51ffbe33a4828c Mon Sep 17 00:00:00 2001 From: Ethan Lin Date: Thu, 6 Jul 2017 00:29:41 +0800 Subject: [PATCH] Bug 1377571 - Add fallback path for layers-free. r=jrmuizel MozReview-Commit-ID: KOM7JXYljX2 --HG-- extra : rebase_source : 94a8c314ac311a05256a27bd61648815b0e42734 --- gfx/layers/wr/WebRenderLayerManager.cpp | 142 +++++++++++++++++++----- gfx/layers/wr/WebRenderLayerManager.h | 8 +- gfx/layers/wr/WebRenderUserData.cpp | 33 +++++- gfx/layers/wr/WebRenderUserData.h | 29 ++++- layout/generic/nsBulletFrame.cpp | 2 +- 5 files changed, 176 insertions(+), 38 deletions(-) diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp index dbb69dbd890a..ffd7e2bd9019 100644 --- a/gfx/layers/wr/WebRenderLayerManager.cpp +++ b/gfx/layers/wr/WebRenderLayerManager.cpp @@ -13,6 +13,7 @@ #include "mozilla/layers/StackingContextHelper.h" #include "mozilla/layers/TextureClient.h" #include "mozilla/layers/WebRenderBridgeChild.h" +#include "mozilla/layers/UpdateImageHelper.h" #include "WebRenderCanvasLayer.h" #include "WebRenderColorLayer.h" #include "WebRenderContainerLayer.h" @@ -223,7 +224,7 @@ WebRenderLayerManager::CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDi if (!item->CreateWebRenderCommands(aBuilder, aSc, mParentCommands, this, aDisplayListBuilder)) { - // TODO: fallback + PushItemAsImage(item, aBuilder, aSc, aDisplayListBuilder); } } aDisplayList->AppendToTop(&savedItems); @@ -304,49 +305,132 @@ WebRenderLayerManager::PushImage(nsDisplayItem* aItem, return true; } -bool -WebRenderLayerManager::PushItemAsBlobImage(nsDisplayItem* aItem, - wr::DisplayListBuilder& aBuilder, - const StackingContextHelper& aSc, - nsDisplayListBuilder* aDisplayListBuilder) +static void +PaintItemByDrawTarget(nsDisplayItem* aItem, + DrawTarget* aDT, + const LayerRect& aImageRect, + const LayerPoint& aOffset, + nsDisplayListBuilder* aDisplayListBuilder) { - const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel(); + aDT->ClearRect(aImageRect.ToUnknownRect()); + RefPtr context = gfxContext::CreateOrNull(aDT, aOffset.ToUnknownPoint()); + MOZ_ASSERT(context); + aItem->Paint(aDisplayListBuilder, context); + + if (gfxPrefs::WebRenderHighlightPaintedLayers()) { + aDT->SetTransform(Matrix()); + aDT->FillRect(Rect(0, 0, aImageRect.width, aImageRect.height), ColorPattern(Color(1.0, 0.0, 0.0, 0.5))); + } + if (aItem->Frame()->PresContext()->GetPaintFlashing()) { + aDT->SetTransform(Matrix()); + float r = float(rand()) / RAND_MAX; + float g = float(rand()) / RAND_MAX; + float b = float(rand()) / RAND_MAX; + aDT->FillRect(Rect(0, 0, aImageRect.width, aImageRect.height), ColorPattern(Color(r, g, b, 0.5))); + } +} + +bool +WebRenderLayerManager::PushItemAsImage(nsDisplayItem* aItem, + wr::DisplayListBuilder& aBuilder, + const StackingContextHelper& aSc, + nsDisplayListBuilder* aDisplayListBuilder) +{ + RefPtr fallbackData = CreateOrRecycleWebRenderUserData(aItem); bool snap; + nsRect itemBounds = aItem->GetBounds(aDisplayListBuilder, &snap); + nsRect clippedBounds = itemBounds; + + const DisplayItemClip& clip = aItem->GetClip(); + if (clip.HasClip()) { + clippedBounds = itemBounds.Intersect(clip.GetClipRect()); + } + + const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel(); LayerRect bounds = ViewAs( - LayoutDeviceRect::FromAppUnits(aItem->GetBounds(aDisplayListBuilder, &snap), appUnitsPerDevPixel), + LayoutDeviceRect::FromAppUnits(clippedBounds, appUnitsPerDevPixel), PixelCastJustification::WebRenderHasUnitResolution); + LayerIntSize imageSize = RoundedToInt(bounds.Size()); LayerRect imageRect; imageRect.SizeTo(LayerSize(imageSize)); - - RefPtr recorder = MakeAndAddRef(); - RefPtr dummyDt = - gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8X8); - RefPtr dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize.ToUnknownSize()); - LayerPoint offset = ViewAs( - LayoutDevicePoint::FromAppUnits(aItem->ToReferenceFrame(), appUnitsPerDevPixel), - PixelCastJustification::WebRenderHasUnitResolution); - - { - dt->ClearRect(imageRect.ToUnknownRect()); - RefPtr context = gfxContext::CreateOrNull(dt, offset.ToUnknownPoint()); - MOZ_ASSERT(context); - - aItem->Paint(aDisplayListBuilder, context); + if (imageSize.width == 0 || imageSize.height == 0) { + return true; } - wr::ByteBuffer bytes(recorder->mOutputStream.mLength, (uint8_t*)recorder->mOutputStream.mData); + nsPoint shift = clippedBounds.TopLeft() - itemBounds.TopLeft(); + LayerPoint offset = ViewAs( + LayoutDevicePoint::FromAppUnits(aItem->ToReferenceFrame() + shift, appUnitsPerDevPixel), + PixelCastJustification::WebRenderHasUnitResolution); + + nsRegion invalidRegion; + nsAutoPtr geometry = fallbackData->GetGeometry(); + + if (geometry) { + nsPoint shift = itemBounds.TopLeft() - geometry->mBounds.TopLeft(); + geometry->MoveBy(shift); + aItem->ComputeInvalidationRegion(aDisplayListBuilder, geometry, &invalidRegion); + nsRect lastBounds = fallbackData->GetBounds(); + lastBounds.MoveBy(shift); + + if (!lastBounds.IsEqualInterior(clippedBounds)) { + invalidRegion.OrWith(lastBounds); + invalidRegion.OrWith(clippedBounds); + } + } + + if (!geometry || !invalidRegion.IsEmpty()) { + if (gfxPrefs::WebRenderBlobImages()) { + RefPtr recorder = MakeAndAddRef(); + RefPtr dummyDt = + gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8X8); + RefPtr dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize.ToUnknownSize()); + PaintItemByDrawTarget(aItem, dt, imageRect, offset, aDisplayListBuilder); + recorder->Finish(); + + wr::ByteBuffer bytes(recorder->mOutputStream.mLength, (uint8_t*)recorder->mOutputStream.mData); + wr::ImageKey key = WrBridge()->GetNextImageKey(); + WrBridge()->SendAddBlobImage(key, imageSize.ToUnknownSize(), imageSize.width * 4, dt->GetFormat(), bytes); + fallbackData->SetKey(key); + } else { + fallbackData->CreateImageClientIfNeeded(); + RefPtr imageClient = fallbackData->GetImageClient(); + RefPtr imageContainer = LayerManager::CreateImageContainer(); + + { + UpdateImageHelper helper(imageContainer, imageClient, imageSize.ToUnknownSize()); + { + RefPtr dt = helper.GetDrawTarget(); + PaintItemByDrawTarget(aItem, dt, imageRect, offset, aDisplayListBuilder); + } + if (!helper.UpdateImage()) { + return false; + } + } + + // 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 (!fallbackData->UpdateImageKey(imageContainer, true)) { + return false; + } + } + + geometry = aItem->AllocateGeometry(aDisplayListBuilder); + } + + // Update current bounds to fallback data + fallbackData->SetGeometry(Move(geometry)); + fallbackData->SetBounds(clippedBounds); + + MOZ_ASSERT(fallbackData->GetKey()); WrRect dest = aSc.ToRelativeWrRect(imageRect + offset); - WrImageKey key = WrBridge()->GetNextImageKey(); - WrBridge()->SendAddBlobImage(key, imageSize.ToUnknownSize(), imageSize.width * 4, dt->GetFormat(), bytes); - AddImageKeyForDiscard(key); - aBuilder.PushImage(dest, dest, wr::ImageRendering::Auto, - key); + fallbackData->GetKey().value()); return true; } diff --git a/gfx/layers/wr/WebRenderLayerManager.h b/gfx/layers/wr/WebRenderLayerManager.h index 0fc8b118897a..03ed79e5331f 100644 --- a/gfx/layers/wr/WebRenderLayerManager.h +++ b/gfx/layers/wr/WebRenderLayerManager.h @@ -64,10 +64,10 @@ public: mozilla::wr::DisplayListBuilder& aBuilder, const StackingContextHelper& aSc, const LayerRect& aRect); - bool PushItemAsBlobImage(nsDisplayItem* aItem, - wr::DisplayListBuilder& aBuilder, - const StackingContextHelper& aSc, - nsDisplayListBuilder* aDisplayListBuilder); + bool PushItemAsImage(nsDisplayItem* aItem, + wr::DisplayListBuilder& aBuilder, + const StackingContextHelper& aSc, + nsDisplayListBuilder* aDisplayListBuilder); void CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder, StackingContextHelper& aSc, diff --git a/gfx/layers/wr/WebRenderUserData.cpp b/gfx/layers/wr/WebRenderUserData.cpp index f4dbca228a18..bb5a89c7af36 100644 --- a/gfx/layers/wr/WebRenderUserData.cpp +++ b/gfx/layers/wr/WebRenderUserData.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WebRenderUserData.h" +#include "nsDisplayListInvalidation.h" namespace mozilla { namespace layers { @@ -35,7 +36,7 @@ WebRenderImageData::~WebRenderImageData() } Maybe -WebRenderImageData::UpdateImageKey(ImageContainer* aContainer) +WebRenderImageData::UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate) { CreateImageClientIfNeeded(); CreateExternalImageIfNeeded(); @@ -61,7 +62,7 @@ WebRenderImageData::UpdateImageKey(ImageContainer* aContainer) } // Reuse old key if generation is not updated. - if (oldCounter == imageClient->GetLastUpdateGenerationCounter() && mKey) { + if (!aForceUpdate && oldCounter == imageClient->GetLastUpdateGenerationCounter() && mKey) { return mKey; } @@ -77,6 +78,13 @@ WebRenderImageData::UpdateImageKey(ImageContainer* aContainer) return mKey; } +already_AddRefed +WebRenderImageData::GetImageClient() +{ + RefPtr imageClient = mImageClient; + return imageClient.forget(); +} + void WebRenderImageData::CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder, ImageContainer* aContainer, @@ -140,5 +148,26 @@ WebRenderImageData::CreateExternalImageIfNeeded() } } +WebRenderFallbackData::~WebRenderFallbackData() +{ +} + +WebRenderFallbackData::WebRenderFallbackData(WebRenderLayerManager* aWRManager) + : WebRenderImageData(aWRManager) +{ +} + +nsAutoPtr +WebRenderFallbackData::GetGeometry() +{ + return mGeometry; +} + +void +WebRenderFallbackData::SetGeometry(nsAutoPtr aGeometry) +{ + mGeometry = aGeometry; +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/wr/WebRenderUserData.h b/gfx/layers/wr/WebRenderUserData.h index f783c2107854..d1f11872c2b1 100644 --- a/gfx/layers/wr/WebRenderUserData.h +++ b/gfx/layers/wr/WebRenderUserData.h @@ -9,6 +9,8 @@ #include "mozilla/layers/StackingContextHelper.h" #include "mozilla/webrender/WebRenderAPI.h" +class nsDisplayItemGeometry; + namespace mozilla { namespace layers { class ImageClient; @@ -30,6 +32,7 @@ public: enum class UserDataType { eImage, + eFallback, }; virtual UserDataType GetType() = 0; @@ -51,8 +54,11 @@ public: virtual WebRenderImageData* AsImageData() override { return this; } virtual UserDataType GetType() override { return UserDataType::eImage; } static UserDataType Type() { return UserDataType::eImage; } + Maybe GetKey() { return mKey; } + void SetKey(const wr::ImageKey& aKey) { mKey = Some(aKey); } + already_AddRefed GetImageClient(); - Maybe UpdateImageKey(ImageContainer* aContainer); + Maybe UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate = false); void CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder, ImageContainer* aContainer, @@ -64,8 +70,9 @@ public: const WrImageRendering& aFilter, const WrMixBlendMode& aMixBlendMode); -protected: void CreateImageClientIfNeeded(); + +protected: void CreateExternalImageIfNeeded(); wr::MaybeExternalImageId mExternalImageId; @@ -75,6 +82,24 @@ protected: RefPtr mContainer; }; +class WebRenderFallbackData : public WebRenderImageData +{ +public: + explicit WebRenderFallbackData(WebRenderLayerManager* aWRManager); + virtual ~WebRenderFallbackData(); + + virtual UserDataType GetType() override { return UserDataType::eFallback; } + static UserDataType Type() { return UserDataType::eFallback; } + nsAutoPtr GetGeometry(); + void SetGeometry(nsAutoPtr aGeometry); + nsRect GetBounds() { return mBounds; } + void SetBounds(const nsRect& aRect) { mBounds = aRect; } + +protected: + nsAutoPtr mGeometry; + nsRect mBounds; +}; + } // namespace layers } // namespace mozilla diff --git a/layout/generic/nsBulletFrame.cpp b/layout/generic/nsBulletFrame.cpp index 7501ffd92c2c..2eabf9fd849a 100644 --- a/layout/generic/nsBulletFrame.cpp +++ b/layout/generic/nsBulletFrame.cpp @@ -490,7 +490,7 @@ BulletRenderer::CreateWebRenderCommandsForPath(nsDisplayItem* aItem, { MOZ_ASSERT(IsPathType()); - if (!aManager->PushItemAsBlobImage(aItem, aBuilder, aSc, aDisplayListBuilder)) { + if (!aManager->PushItemAsImage(aItem, aBuilder, aSc, aDisplayListBuilder)) { NS_WARNING("Fail to create WebRender commands for Bullet path."); } }