Bug 1376855 - Introduce WebRenderUserData and WebRenderImageData. r=kats
Layers are retained between transaction and we store some data in the layers.
Thus, if we no longer use layers, we need find another storage to place
those data. I use frame's property to retain WebRenderUserData between
transaction.
MozReview-Commit-ID: Ku5VGBXa3w6
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -233,16 +233,17 @@ EXPORTS.mozilla.layers += [
'wr/WebRenderImageHost.h',
'wr/WebRenderLayer.h',
'wr/WebRenderLayerManager.h',
'wr/WebRenderLayersLogging.h',
'wr/WebRenderMessageUtils.h',
'wr/WebRenderScrollData.h',
'wr/WebRenderScrollDataWrapper.h',
'wr/WebRenderTextureHost.h',
+ 'wr/WebRenderUserData.h',
]
if CONFIG['MOZ_X11']:
EXPORTS.mozilla.layers += [
'basic/TextureClientX11.h',
'basic/X11TextureSourceBasic.h',
'composite/X11TextureHost.h',
'ipc/ShadowLayerUtilsX11.h',
@@ -462,16 +463,17 @@ UNIFIED_SOURCES += [
'wr/WebRenderImageLayer.cpp',
'wr/WebRenderLayer.cpp',
'wr/WebRenderLayerManager.cpp',
'wr/WebRenderLayersLogging.cpp',
'wr/WebRenderPaintedLayer.cpp',
'wr/WebRenderPaintedLayerBlob.cpp',
'wr/WebRenderScrollData.cpp',
'wr/WebRenderTextLayer.cpp',
+ 'wr/WebRenderUserData.cpp',
# XXX here are some unified build error.
#'wr/WebRenderTextureHost.cpp'
]
SOURCES += [
'basic/BasicImageLayer.cpp',
'ImageContainer.cpp',
'Layers.cpp',
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -15,17 +15,16 @@
#include "WebRenderCanvasLayer.h"
#include "WebRenderColorLayer.h"
#include "WebRenderContainerLayer.h"
#include "WebRenderImageLayer.h"
#include "WebRenderPaintedLayer.h"
#include "WebRenderPaintedLayerBlob.h"
#include "WebRenderTextLayer.h"
#include "WebRenderDisplayItemLayer.h"
-#include "nsDisplayList.h"
namespace mozilla {
using namespace gfx;
namespace layers {
WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
@@ -239,16 +238,76 @@ WebRenderLayerManager::EndTransactionWit
WrBridge()->RemoveExpiredFontKeys();
EndTransactionInternal(nullptr,
nullptr,
EndTransactionFlags::END_DEFAULT,
aDisplayList,
aDisplayListBuilder);
}
+Maybe<wr::ImageKey>
+WebRenderLayerManager::CreateImageKey(nsDisplayItem* aItem,
+ ImageContainer* aContainer,
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ const StackingContextHelper& aSc,
+ gfx::IntSize& aSize)
+{
+ RefPtr<WebRenderImageData> imageData = CreateOrRecycleWebRenderUserData<WebRenderImageData>(aItem);
+ MOZ_ASSERT(imageData);
+
+ if (aContainer->IsAsync()) {
+ bool snap;
+ nsRect bounds = aItem->GetBounds(nullptr, &snap);
+ int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
+ LayerRect rect = ViewAs<LayerPixel>(
+ LayoutDeviceRect::FromAppUnits(bounds, appUnitsPerDevPixel),
+ PixelCastJustification::WebRenderHasUnitResolution);
+ LayerRect scBounds(0, 0, rect.width, rect.height);
+ imageData->CreateAsyncImageWebRenderCommands(aBuilder,
+ aContainer,
+ aSc,
+ rect,
+ scBounds,
+ gfx::Matrix4x4(),
+ Nothing(),
+ wr::ImageRendering::Auto,
+ wr::MixBlendMode::Normal);
+ return Nothing();
+ }
+
+ AutoLockImage autoLock(aContainer);
+ if (!autoLock.HasImage()) {
+ return Nothing();
+ }
+ mozilla::layers::Image* image = autoLock.GetImage();
+ aSize = image->GetSize();
+
+ return imageData->UpdateImageKey(aContainer);
+}
+
+bool
+WebRenderLayerManager::PushImage(nsDisplayItem* aItem,
+ ImageContainer* aContainer,
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ const StackingContextHelper& aSc,
+ const LayerRect& aRect)
+{
+ gfx::IntSize size;
+ Maybe<wr::ImageKey> key = CreateImageKey(aItem, aContainer, aBuilder, aSc, size);
+ if (!key) {
+ return false;
+ }
+
+ wr::ImageRendering filter = wr::ImageRendering::Auto;
+ auto r = aSc.ToRelativeWrRect(aRect);
+ aBuilder.PushImage(r, r, filter, key.value());
+
+ return true;
+}
+
void
WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags)
{
mEndTransactionWithoutLayers = false;
DiscardImages();
WrBridge()->RemoveExpiredFontKeys();
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -7,21 +7,22 @@
#define GFX_WEBRENDERLAYERMANAGER_H
#include "Layers.h"
#include "mozilla/MozPromise.h"
#include "mozilla/layers/APZTestData.h"
#include "mozilla/layers/FocusTarget.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/layers/TransactionIdAllocator.h"
+#include "mozilla/layers/WebRenderUserData.h"
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/webrender/WebRenderTypes.h"
+#include "nsDisplayList.h"
class nsIWidget;
-class nsDisplayList;
namespace mozilla {
namespace layers {
class CompositorBridgeChild;
class KnowsCompositor;
class PCompositorBridgeChild;
class WebRenderBridgeChild;
@@ -47,16 +48,26 @@ public:
WebRenderLayerManager* AsWebRenderLayerManager() override { return this; }
virtual CompositorBridgeChild* GetCompositorBridgeChild() override;
virtual int32_t GetMaxTextureSize() const override;
virtual bool BeginTransactionWithTarget(gfxContext* aTarget) override;
virtual bool BeginTransaction() override;
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override;
+ Maybe<wr::ImageKey> CreateImageKey(nsDisplayItem* aItem,
+ ImageContainer* aContainer,
+ 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);
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,
@@ -147,16 +158,44 @@ public:
const std::string& aKey,
const std::string& aValue) {
mApzTestData.LogTestDataForPaint(mPaintSequenceNumber, aScrollId, aKey, aValue);
}
// See equivalent function in ClientLayerManager
const APZTestData& GetAPZTestData() const
{ return mApzTestData; }
+ // Those are data that we kept between transactions. We used to cache some
+ // data in the layer. But in layers free mode, we don't have layer which
+ // means we need some other place to cached the data between transaction.
+ // We store the data in frame's property.
+ template<class T> already_AddRefed<T>
+ CreateOrRecycleWebRenderUserData(nsDisplayItem* aItem)
+ {
+ MOZ_ASSERT(aItem);
+ nsIFrame* frame = aItem->Frame();
+
+ if (!frame->HasProperty(nsIFrame::WebRenderUserDataProperty())) {
+ frame->AddProperty(nsIFrame::WebRenderUserDataProperty(),
+ new nsIFrame::WebRenderUserDataTable());
+ }
+
+ nsIFrame::WebRenderUserDataTable* userDataTable =
+ frame->GetProperty(nsIFrame::WebRenderUserDataProperty());
+ RefPtr<WebRenderUserData>& data = userDataTable->GetOrInsert(aItem->GetPerFrameKey());
+ if (!data || (data->GetType() != T::Type())) {
+ data = new T(this);
+ }
+
+ MOZ_ASSERT(data);
+ MOZ_ASSERT(data->GetType() == T::Type());
+ RefPtr<T> res = static_cast<T*>(data.get());
+ return res.forget();
+ }
+
private:
/**
* Take a snapshot of the parent context, and copy
* it into mTarget.
*/
void MakeSnapshotIfRequired(LayoutDeviceIntSize aSize);
void ClearLayer(Layer* aLayer);
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -0,0 +1,144 @@
+/* -*- 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"
+
+namespace mozilla {
+namespace layers {
+
+WebRenderBridgeChild*
+WebRenderUserData::WrBridge() const
+{
+ return mWRManager->WrBridge();
+}
+
+WebRenderImageData::WebRenderImageData(WebRenderLayerManager* aWRManager)
+ : WebRenderUserData(aWRManager)
+{
+}
+
+WebRenderImageData::~WebRenderImageData()
+{
+ if (mKey) {
+ mWRManager->AddImageKeyForDiscard(mKey.value());
+ }
+
+ if (mExternalImageId) {
+ WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
+ }
+
+ if (mPipelineId) {
+ WrBridge()->RemovePipelineIdForAsyncCompositable(mPipelineId.ref());
+ }
+}
+
+Maybe<wr::ImageKey>
+WebRenderImageData::UpdateImageKey(ImageContainer* aContainer)
+{
+ CreateImageClientIfNeeded();
+ CreateExternalImageIfNeeded();
+
+ if (!mImageClient || !mExternalImageId) {
+ return Nothing();
+ }
+
+ MOZ_ASSERT(mImageClient->AsImageClientSingle());
+ MOZ_ASSERT(aContainer);
+
+ ImageClientSingle* imageClient = mImageClient->AsImageClientSingle();
+ uint32_t oldCounter = imageClient->GetLastUpdateGenerationCounter();
+
+ bool ret = imageClient->UpdateImage(aContainer, /* unused */0);
+ if (!ret || imageClient->IsEmpty()) {
+ // Delete old key
+ if (mKey) {
+ mWRManager->AddImageKeyForDiscard(mKey.value());
+ mKey = Nothing();
+ }
+ return Nothing();
+ }
+
+ // Reuse old key if generation is not updated.
+ if (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;
+}
+
+void
+WebRenderImageData::CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+ ImageContainer* aContainer,
+ const StackingContextHelper& aSc,
+ const LayerRect& aBounds,
+ const LayerRect& aSCBounds,
+ const Matrix4x4& aSCTransform,
+ const MaybeIntSize& aScaleToSize,
+ const WrImageRendering& aFilter,
+ const WrMixBlendMode& aMixBlendMode)
+{
+ MOZ_ASSERT(aContainer->IsAsync());
+ if (!mPipelineId) {
+ // Alloc async image pipeline id.
+ mPipelineId = Some(WrBridge()->GetCompositorBridgeChild()->GetNextPipelineId());
+ WrBridge()->AddPipelineIdForAsyncCompositable(mPipelineId.ref(),
+ aContainer->GetAsyncContainerHandle());
+ }
+ MOZ_ASSERT(!mImageClient);
+ MOZ_ASSERT(!mExternalImageId);
+
+ // Push IFrame for async image pipeline.
+ //
+ // We don't push a stacking context for this async image pipeline here.
+ // Instead, we do it inside the iframe that hosts the image. As a result,
+ // a bunch of the calculations normally done as part of that stacking
+ // context need to be done manually and pushed over to the parent side,
+ // where it will be done when we build the display list for the iframe.
+ // That happens in WebRenderCompositableHolder.
+ WrRect r = aSc.ToRelativeWrRect(aBounds);
+ aBuilder.PushIFrame(r, r, mPipelineId.ref());
+
+ WrBridge()->AddWebRenderParentCommand(OpUpdateAsyncImagePipeline(mPipelineId.value(),
+ aSCBounds,
+ aSCTransform,
+ aScaleToSize,
+ aFilter,
+ aMixBlendMode));
+}
+
+void
+WebRenderImageData::CreateImageClientIfNeeded()
+{
+ if (!mImageClient) {
+ mImageClient = ImageClient::CreateImageClient(CompositableType::IMAGE,
+ WrBridge(),
+ TextureFlags::DEFAULT);
+ if (!mImageClient) {
+ return;
+ }
+
+ mImageClient->Connect();
+ }
+}
+
+void
+WebRenderImageData::CreateExternalImageIfNeeded()
+{
+ if (!mExternalImageId) {
+ mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mImageClient));
+ }
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -0,0 +1,81 @@
+/* -*- 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/. */
+
+#ifndef GFX_WEBRENDERUSERDATA_H
+#define GFX_WEBRENDERUSERDATA_H
+
+#include "mozilla/layers/StackingContextHelper.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+
+namespace mozilla {
+namespace layers {
+class ImageClient;
+class ImageContainer;
+class WebRenderBridgeChild;
+class WebRenderImageData;
+class WebRenderLayerManager;
+
+class WebRenderUserData
+{
+public:
+ NS_INLINE_DECL_REFCOUNTING(WebRenderUserData)
+
+ explicit WebRenderUserData(WebRenderLayerManager* aWRManager)
+ : mWRManager(aWRManager)
+ { }
+
+ virtual WebRenderImageData* AsImageData() { return nullptr; }
+
+ enum class UserDataType {
+ eImage,
+ };
+
+ virtual UserDataType GetType() = 0;
+
+protected:
+ virtual ~WebRenderUserData() {}
+
+ WebRenderBridgeChild* WrBridge() const;
+
+ WebRenderLayerManager* mWRManager;
+};
+
+class WebRenderImageData : public WebRenderUserData
+{
+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> UpdateImageKey(ImageContainer* aContainer);
+
+ 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);
+
+protected:
+ void CreateImageClientIfNeeded();
+ void CreateExternalImageIfNeeded();
+
+ wr::MaybeExternalImageId mExternalImageId;
+ Maybe<wr::ImageKey> mKey;
+ RefPtr<ImageClient> mImageClient;
+ Maybe<wr::PipelineId> mPipelineId;
+ RefPtr<ImageContainer> mContainer;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* GFX_WEBRENDERUSERDATA_H */
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -27,16 +27,17 @@
#include "FrameProperties.h"
#include "mozilla/layout/FrameChildList.h"
#include "mozilla/Maybe.h"
#include "mozilla/SmallPointerArray.h"
#include "mozilla/WritingModes.h"
#include "nsDirection.h"
#include "nsFrameList.h"
#include "nsFrameState.h"
+#include "mozilla/layers/WebRenderUserData.h"
#include "mozilla/ReflowOutput.h"
#include "nsITheme.h"
#include "nsLayoutUtils.h"
#include "nsQueryFrame.h"
#include "nsStringGlue.h"
#include "nsStyleContext.h"
#include "nsStyleStruct.h"
#include "Visibility.h"
@@ -1126,16 +1127,19 @@ public:
virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
{ return aChild->GetPosition(); }
nsPoint GetPositionIgnoringScrolling();
typedef AutoTArray<nsIContent*, 2> ContentArray;
static void DestroyContentArray(ContentArray* aArray);
+ typedef mozilla::layers::WebRenderUserData WebRenderUserData;
+ typedef nsRefPtrHashtable<nsUint32HashKey, WebRenderUserData> WebRenderUserDataTable;
+
#define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, dtor) \
static const mozilla::FramePropertyDescriptor<type>* prop() { \
/* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
static const auto descriptor = \
mozilla::FramePropertyDescriptor<type>::NewWithDestructor<dtor>(); \
return &descriptor; \
}
@@ -1223,16 +1227,17 @@ public:
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BBaselinePadProperty, nscoord)
NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(GenConProperty, ContentArray,
DestroyContentArray)
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty, mozilla::FrameBidiData)
NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(PlaceholderFrameProperty, nsPlaceholderFrame)
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(WebRenderUserDataProperty, WebRenderUserDataTable)
mozilla::FrameBidiData GetBidiData() const
{
bool exists;
mozilla::FrameBidiData bidiData = GetProperty(BidiDataProperty(), &exists);
if (!exists) {
bidiData.precedingControl = mozilla::kBidiLevelNone;
}