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

--HG--
extra : rebase_source : 636653f78d1d6c310726a1a2c944141dc691decc
This commit is contained in:
Morris Tseng 2017-06-28 15:03:27 -07:00
parent a43aba7200
commit 77424afaa9
6 changed files with 332 additions and 2 deletions

View File

@ -238,6 +238,7 @@ EXPORTS.mozilla.layers += [
'wr/WebRenderScrollData.h',
'wr/WebRenderScrollDataWrapper.h',
'wr/WebRenderTextureHost.h',
'wr/WebRenderUserData.h',
]
if CONFIG['MOZ_X11']:
@ -467,6 +468,7 @@ UNIFIED_SOURCES += [
'wr/WebRenderPaintedLayerBlob.cpp',
'wr/WebRenderScrollData.cpp',
'wr/WebRenderTextLayer.cpp',
'wr/WebRenderUserData.cpp',
# XXX here are some unified build error.
#'wr/WebRenderTextureHost.cpp'
]

View File

@ -20,7 +20,6 @@
#include "WebRenderPaintedLayerBlob.h"
#include "WebRenderTextLayer.h"
#include "WebRenderDisplayItemLayer.h"
#include "nsDisplayList.h"
namespace mozilla {
@ -244,6 +243,66 @@ WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* 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,

View File

@ -12,11 +12,12 @@
#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 {
@ -52,6 +53,16 @@ public:
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,
@ -152,6 +163,34 @@ public:
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

View File

@ -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

View File

@ -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 */

View File

@ -32,6 +32,7 @@
#include "nsDirection.h"
#include "nsFrameList.h"
#include "nsFrameState.h"
#include "mozilla/layers/WebRenderUserData.h"
#include "mozilla/ReflowOutput.h"
#include "nsITheme.h"
#include "nsLayoutUtils.h"
@ -1131,6 +1132,9 @@ public:
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. */ \
@ -1228,6 +1232,7 @@ public:
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
{