Bug 1377571 - Add fallback path for layers-free. r=jrmuizel
MozReview-Commit-ID: KOM7JXYljX2
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -8,16 +8,17 @@
#include "gfxPrefs.h"
#include "GeckoProfiler.h"
#include "LayersLogging.h"
#include "mozilla/gfx/DrawEventRecorder.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#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"
#include "WebRenderImageLayer.h"
#include "WebRenderPaintedLayer.h"
#include "WebRenderPaintedLayerBlob.h"
#include "WebRenderTextLayer.h"
#include "WebRenderDisplayItemLayer.h"
@@ -218,17 +219,17 @@ WebRenderLayerManager::CreateWebRenderCo
item->~nsDisplayItem();
continue;
}
savedItems.AppendToTop(item);
if (!item->CreateWebRenderCommands(aBuilder, aSc, mParentCommands, this,
aDisplayListBuilder)) {
- // TODO: fallback
+ PushItemAsImage(item, aBuilder, aSc, aDisplayListBuilder);
}
}
aDisplayList->AppendToTop(&savedItems);
}
void
WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
nsDisplayListBuilder* aDisplayListBuilder)
@@ -299,59 +300,142 @@ WebRenderLayerManager::PushImage(nsDispl
wr::ImageRendering filter = wr::ImageRendering::Auto;
auto r = aSc.ToRelativeWrRect(aRect);
aBuilder.PushImage(r, r, filter, key.value());
return true;
}
+static void
+PaintItemByDrawTarget(nsDisplayItem* aItem,
+ DrawTarget* aDT,
+ const LayerRect& aImageRect,
+ const LayerPoint& aOffset,
+ nsDisplayListBuilder* aDisplayListBuilder)
+{
+ aDT->ClearRect(aImageRect.ToUnknownRect());
+ RefPtr<gfxContext> 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::PushItemAsBlobImage(nsDisplayItem* aItem,
- wr::DisplayListBuilder& aBuilder,
- const StackingContextHelper& aSc,
- nsDisplayListBuilder* aDisplayListBuilder)
+WebRenderLayerManager::PushItemAsImage(nsDisplayItem* aItem,
+ wr::DisplayListBuilder& aBuilder,
+ const StackingContextHelper& aSc,
+ nsDisplayListBuilder* aDisplayListBuilder)
{
- const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
+ RefPtr<WebRenderFallbackData> fallbackData = CreateOrRecycleWebRenderUserData<WebRenderFallbackData>(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<LayerPixel>(
- LayoutDeviceRect::FromAppUnits(aItem->GetBounds(aDisplayListBuilder, &snap), appUnitsPerDevPixel),
+ LayoutDeviceRect::FromAppUnits(clippedBounds, appUnitsPerDevPixel),
PixelCastJustification::WebRenderHasUnitResolution);
+
LayerIntSize imageSize = RoundedToInt(bounds.Size());
LayerRect imageRect;
imageRect.SizeTo(LayerSize(imageSize));
+ if (imageSize.width == 0 || imageSize.height == 0) {
+ return true;
+ }
- RefPtr<gfx::DrawEventRecorderMemory> recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>();
- RefPtr<gfx::DrawTarget> dummyDt =
- gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8X8);
- RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize.ToUnknownSize());
+ nsPoint shift = clippedBounds.TopLeft() - itemBounds.TopLeft();
LayerPoint offset = ViewAs<LayerPixel>(
- LayoutDevicePoint::FromAppUnits(aItem->ToReferenceFrame(), appUnitsPerDevPixel),
+ LayoutDevicePoint::FromAppUnits(aItem->ToReferenceFrame() + shift, appUnitsPerDevPixel),
PixelCastJustification::WebRenderHasUnitResolution);
- {
- dt->ClearRect(imageRect.ToUnknownRect());
- RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt, offset.ToUnknownPoint());
- MOZ_ASSERT(context);
+ nsRegion invalidRegion;
+ nsAutoPtr<nsDisplayItemGeometry> geometry = fallbackData->GetGeometry();
- aItem->Paint(aDisplayListBuilder, context);
+ 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);
+ }
}
- wr::ByteBuffer bytes(recorder->mOutputStream.mLength, (uint8_t*)recorder->mOutputStream.mData);
+ if (!geometry || !invalidRegion.IsEmpty()) {
+ if (gfxPrefs::WebRenderBlobImages()) {
+ RefPtr<gfx::DrawEventRecorderMemory> recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>();
+ RefPtr<gfx::DrawTarget> dummyDt =
+ gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8X8);
+ RefPtr<gfx::DrawTarget> 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> imageClient = fallbackData->GetImageClient();
+ RefPtr<ImageContainer> imageContainer = LayerManager::CreateImageContainer();
+
+ {
+ UpdateImageHelper helper(imageContainer, imageClient, imageSize.ToUnknownSize());
+ {
+ RefPtr<gfx::DrawTarget> 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;
}
void
WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags)
{
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -59,20 +59,20 @@ public:
mozilla::wr::DisplayListBuilder& aBuilder,
const StackingContextHelper& aSc,
gfx::IntSize& aSize);
bool PushImage(nsDisplayItem* aItem,
ImageContainer* aContainer,
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,
wr::DisplayListBuilder& aBuilder);
void EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
nsDisplayListBuilder* aDisplayListBuilder);
bool IsLayersFreeTransaction() { return mEndTransactionWithoutLayers; }
virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -1,14 +1,15 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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 "WebRenderUserData.h"
+#include "nsDisplayListInvalidation.h"
namespace mozilla {
namespace layers {
WebRenderBridgeChild*
WebRenderUserData::WrBridge() const
{
return mWRManager->WrBridge();
@@ -30,17 +31,17 @@ WebRenderImageData::~WebRenderImageData(
}
if (mPipelineId) {
WrBridge()->RemovePipelineIdForAsyncCompositable(mPipelineId.ref());
}
}
Maybe<wr::ImageKey>
-WebRenderImageData::UpdateImageKey(ImageContainer* aContainer)
+WebRenderImageData::UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate)
{
CreateImageClientIfNeeded();
CreateExternalImageIfNeeded();
if (!mImageClient || !mExternalImageId) {
return Nothing();
}
@@ -56,32 +57,39 @@ WebRenderImageData::UpdateImageKey(Image
if (mKey) {
mWRManager->AddImageKeyForDiscard(mKey.value());
mKey = Nothing();
}
return Nothing();
}
// Reuse old key if generation is not updated.
- if (oldCounter == imageClient->GetLastUpdateGenerationCounter() && mKey) {
+ if (!aForceUpdate && oldCounter == imageClient->GetLastUpdateGenerationCounter() && mKey) {
return mKey;
}
// Delete old key, we are generating a new key.
if (mKey) {
mWRManager->AddImageKeyForDiscard(mKey.value());
}
WrImageKey key = WrBridge()->GetNextImageKey();
mWRManager->WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId.value(), key));
mKey = Some(key);
return mKey;
}
+already_AddRefed<ImageClient>
+WebRenderImageData::GetImageClient()
+{
+ RefPtr<ImageClient> imageClient = mImageClient;
+ return imageClient.forget();
+}
+
void
WebRenderImageData::CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
ImageContainer* aContainer,
const StackingContextHelper& aSc,
const LayerRect& aBounds,
const LayerRect& aSCBounds,
const Matrix4x4& aSCTransform,
const MaybeIntSize& aScaleToSize,
@@ -135,10 +143,31 @@ WebRenderImageData::CreateImageClientIfN
void
WebRenderImageData::CreateExternalImageIfNeeded()
{
if (!mExternalImageId) {
mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mImageClient));
}
}
+WebRenderFallbackData::~WebRenderFallbackData()
+{
+}
+
+WebRenderFallbackData::WebRenderFallbackData(WebRenderLayerManager* aWRManager)
+ : WebRenderImageData(aWRManager)
+{
+}
+
+nsAutoPtr<nsDisplayItemGeometry>
+WebRenderFallbackData::GetGeometry()
+{
+ return mGeometry;
+}
+
+void
+WebRenderFallbackData::SetGeometry(nsAutoPtr<nsDisplayItemGeometry> aGeometry)
+{
+ mGeometry = aGeometry;
+}
+
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -4,16 +4,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFX_WEBRENDERUSERDATA_H
#define GFX_WEBRENDERUSERDATA_H
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/webrender/WebRenderAPI.h"
+class nsDisplayItemGeometry;
+
namespace mozilla {
namespace layers {
class ImageClient;
class ImageContainer;
class WebRenderBridgeChild;
class WebRenderImageData;
class WebRenderLayerManager;
@@ -25,16 +27,17 @@ public:
explicit WebRenderUserData(WebRenderLayerManager* aWRManager)
: mWRManager(aWRManager)
{ }
virtual WebRenderImageData* AsImageData() { return nullptr; }
enum class UserDataType {
eImage,
+ eFallback,
};
virtual UserDataType GetType() = 0;
protected:
virtual ~WebRenderUserData() {}
WebRenderBridgeChild* WrBridge() const;
@@ -46,36 +49,58 @@ class WebRenderImageData : public WebRen
{
public:
explicit WebRenderImageData(WebRenderLayerManager* aWRManager);
virtual ~WebRenderImageData();
virtual WebRenderImageData* AsImageData() override { return this; }
virtual UserDataType GetType() override { return UserDataType::eImage; }
static UserDataType Type() { return UserDataType::eImage; }
+ Maybe<wr::ImageKey> GetKey() { return mKey; }
+ void SetKey(const wr::ImageKey& aKey) { mKey = Some(aKey); }
+ already_AddRefed<ImageClient> GetImageClient();
- Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer);
+ Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate = false);
void CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
ImageContainer* aContainer,
const StackingContextHelper& aSc,
const LayerRect& aBounds,
const LayerRect& aSCBounds,
const gfx::Matrix4x4& aSCTransform,
const gfx::MaybeIntSize& aScaleToSize,
const WrImageRendering& aFilter,
const WrMixBlendMode& aMixBlendMode);
+ void CreateImageClientIfNeeded();
+
protected:
- void CreateImageClientIfNeeded();
void CreateExternalImageIfNeeded();
wr::MaybeExternalImageId mExternalImageId;
Maybe<wr::ImageKey> mKey;
RefPtr<ImageClient> mImageClient;
Maybe<wr::PipelineId> mPipelineId;
RefPtr<ImageContainer> 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<nsDisplayItemGeometry> GetGeometry();
+ void SetGeometry(nsAutoPtr<nsDisplayItemGeometry> aGeometry);
+ nsRect GetBounds() { return mBounds; }
+ void SetBounds(const nsRect& aRect) { mBounds = aRect; }
+
+protected:
+ nsAutoPtr<nsDisplayItemGeometry> mGeometry;
+ nsRect mBounds;
+};
+
} // namespace layers
} // namespace mozilla
#endif /* GFX_WEBRENDERUSERDATA_H */
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -485,17 +485,17 @@ BulletRenderer::CreateWebRenderCommandsF
wr::DisplayListBuilder& aBuilder,
const layers::StackingContextHelper& aSc,
nsTArray<layers::WebRenderParentCommand>& aParentCommands,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder)
{
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.");
}
}
void
BulletRenderer::CreateWebRenderCommandsForText(nsDisplayItem* aItem,
wr::DisplayListBuilder& aBuilder,
const layers::StackingContextHelper& aSc,