Bug 1428558 - Part 2. Improve plumbing to sending resource updates to WebRender. r=nical

Animated images will require scheduling a composite of the frame in
addition to updating the ImageKey/external image ID bindings. It would
be good if this could be done as part of the same IPDL message.
Additionally a page may have many animated images that we update the
frame for at the same time, so these updates should be batched together.
In the event that we needed to regenerate the display list, or produce
an empty transaction, ideally we would just throw these resource updates
in with the rest of the changes. This patch allows us to do all of that
without unnecessarily burdening the caller with tracking extra state.

Differential Revision: https://phabricator.services.mozilla.com/D7499
This commit is contained in:
Andrew Osmond 2018-10-11 10:41:46 -04:00
Родитель 83a52f66de
Коммит 74a32dcaab
9 изменённых файлов: 174 добавлений и 26 удалений

Просмотреть файл

@ -50,9 +50,10 @@ parent:
IdNamespace aIdNamespace, bool containsSVGGroup, TimeStamp refreshStartTime, TimeStamp txnStartTime, TimeStamp fwdTime);
async EmptyTransaction(FocusTarget focusTarget, ScrollUpdatesMap scrollUpdates, uint32_t aPaintSequenceNumber,
WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, TransactionId transactionId,
OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems,
IdNamespace aIdNamespace, TimeStamp refreshStartTime, TimeStamp txnStartTime, TimeStamp fwdTime);
async SetFocusTarget(FocusTarget focusTarget);
async UpdateResources(OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems);
async UpdateResources(OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems, bool scheduleComposite);
async ParentCommands(WebRenderParentCommand[] commands);
sync GetSnapshot(PTexture texture);
async SetLayersObserverEpoch(LayersObserverEpoch childEpoch);

Просмотреть файл

@ -30,6 +30,30 @@ ShmSegmentsWriter::~ShmSegmentsWriter()
Clear();
}
ShmSegmentsWriter::ShmSegmentsWriter(ShmSegmentsWriter&& aOther) noexcept
: mSmallAllocs(std::move(aOther.mSmallAllocs))
, mLargeAllocs(std::move(aOther.mLargeAllocs))
, mShmAllocator(aOther.mShmAllocator)
, mCursor(aOther.mCursor)
, mChunkSize(aOther.mChunkSize)
{
aOther.mCursor = 0;
}
ShmSegmentsWriter&
ShmSegmentsWriter::operator=(ShmSegmentsWriter&& aOther) noexcept
{
MOZ_ASSERT(IsEmpty(), "Will forget existing updates!");
Clear();
mSmallAllocs = std::move(aOther.mSmallAllocs);
mLargeAllocs = std::move(aOther.mLargeAllocs);
mShmAllocator = aOther.mShmAllocator;
mCursor = aOther.mCursor;
mChunkSize = aOther.mChunkSize;
aOther.mCursor = 0;
return *this;
}
layers::OffsetRange
ShmSegmentsWriter::Write(Range<uint8_t> aBytes)
{
@ -246,9 +270,23 @@ ShmSegmentsReader::Read(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& aIn
IpcResourceUpdateQueue::IpcResourceUpdateQueue(layers::WebRenderBridgeChild* aAllocator,
size_t aChunkSize)
: mWriter(std::move(aAllocator), aChunkSize)
: mWriter(aAllocator, aChunkSize)
{}
IpcResourceUpdateQueue::IpcResourceUpdateQueue(IpcResourceUpdateQueue&& aOther) noexcept
: mWriter(std::move(aOther.mWriter))
, mUpdates(std::move(aOther.mUpdates))
{ }
IpcResourceUpdateQueue&
IpcResourceUpdateQueue::operator=(IpcResourceUpdateQueue&& aOther) noexcept
{
MOZ_ASSERT(IsEmpty(), "Will forget existing updates!");
mWriter = std::move(aOther.mWriter);
mUpdates = std::move(aOther.mUpdates);
return *this;
}
bool
IpcResourceUpdateQueue::AddImage(ImageKey key, const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes)

Просмотреть файл

@ -24,6 +24,12 @@ public:
ShmSegmentsWriter(layers::WebRenderBridgeChild* aAllocator, size_t aChunkSize);
~ShmSegmentsWriter();
ShmSegmentsWriter(ShmSegmentsWriter&& aOther) noexcept;
ShmSegmentsWriter& operator=(ShmSegmentsWriter&& aOther) noexcept;
ShmSegmentsWriter(const ShmSegmentsWriter& aOther) = delete;
ShmSegmentsWriter& operator=(const ShmSegmentsWriter& aOther) = delete;
layers::OffsetRange Write(Range<uint8_t> aBytes);
template<typename T>
@ -32,7 +38,7 @@ public:
return Write(Range<uint8_t>((uint8_t*)aValues.begin().get(), aValues.length() * sizeof(T)));
}
void Flush(nsTArray<layers::RefCountedShmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs);
void Flush(nsTArray<layers::RefCountedShmem>& aSmallAllocs, nsTArray<mozilla::ipc::Shmem>& aLargeAllocs);
void Clear();
bool IsEmpty() const;
@ -44,7 +50,7 @@ protected:
layers::OffsetRange AllocLargeChunk(size_t aSize);
nsTArray<layers::RefCountedShmem> mSmallAllocs;
nsTArray<ipc::Shmem> mLargeAllocs;
nsTArray<mozilla::ipc::Shmem> mLargeAllocs;
layers::WebRenderBridgeChild* mShmAllocator;
size_t mCursor;
size_t mChunkSize;
@ -53,7 +59,7 @@ protected:
class ShmSegmentsReader {
public:
ShmSegmentsReader(const nsTArray<layers::RefCountedShmem>& aSmallShmems,
const nsTArray<ipc::Shmem>& aLargeShmems);
const nsTArray<mozilla::ipc::Shmem>& aLargeShmems);
bool Read(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& aInto);
@ -61,7 +67,7 @@ protected:
bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& aInto);
const nsTArray<layers::RefCountedShmem>& mSmallAllocs;
const nsTArray<ipc::Shmem>& mLargeAllocs;
const nsTArray<mozilla::ipc::Shmem>& mLargeAllocs;
size_t mChunkSize;
};
@ -75,6 +81,12 @@ public:
// So we pick 64k - 2 * 4k - 16 = 57328 bytes as the default alloc size.
explicit IpcResourceUpdateQueue(layers::WebRenderBridgeChild* aAllocator, size_t aChunkSize = 57328);
IpcResourceUpdateQueue(IpcResourceUpdateQueue&& aOther) noexcept;
IpcResourceUpdateQueue& operator=(IpcResourceUpdateQueue&& aOther) noexcept;
IpcResourceUpdateQueue(const IpcResourceUpdateQueue& aOther) = delete;
IpcResourceUpdateQueue& operator=(const IpcResourceUpdateQueue& aOther) = delete;
bool AddImage(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes);
@ -126,12 +138,12 @@ public:
void Flush(nsTArray<layers::OpUpdateResource>& aUpdates,
nsTArray<layers::RefCountedShmem>& aSmallAllocs,
nsTArray<ipc::Shmem>& aLargeAllocs);
nsTArray<mozilla::ipc::Shmem>& aLargeAllocs);
bool IsEmpty() const;
static void ReleaseShmems(ipc::IProtocol*, nsTArray<layers::RefCountedShmem>& aShmems);
static void ReleaseShmems(ipc::IProtocol*, nsTArray<ipc::Shmem>& aShmems);
static void ReleaseShmems(mozilla::ipc::IProtocol*, nsTArray<layers::RefCountedShmem>& aShms);
static void ReleaseShmems(mozilla::ipc::IProtocol*, nsTArray<mozilla::ipc::Shmem>& aShms);
protected:
ShmSegmentsWriter mWriter;
nsTArray<layers::OpUpdateResource> mUpdates;

Просмотреть файл

@ -96,7 +96,8 @@ WebRenderBridgeChild::BeginTransaction()
}
void
WebRenderBridgeChild::UpdateResources(wr::IpcResourceUpdateQueue& aResources)
WebRenderBridgeChild::UpdateResources(wr::IpcResourceUpdateQueue& aResources,
bool aScheduleComposite /* = false */)
{
if (!IPCOpen()) {
aResources.Clear();
@ -112,7 +113,8 @@ WebRenderBridgeChild::UpdateResources(wr::IpcResourceUpdateQueue& aResources)
nsTArray<ipc::Shmem> largeShmems;
aResources.Flush(resourceUpdates, smallShmems, largeShmems);
this->SendUpdateResources(resourceUpdates, std::move(smallShmems), largeShmems);
this->SendUpdateResources(resourceUpdates, smallShmems,
largeShmems, aScheduleComposite);
}
void
@ -146,7 +148,7 @@ WebRenderBridgeChild::EndTransaction(const wr::LayoutSize& aContentSize,
this->SendSetDisplayList(aSize, mParentCommands, mDestroyedActors,
GetFwdTransactionId(), aTransactionId,
aContentSize, dlData, aDL.dl_desc, aScrollData,
std::move(resourceUpdates), std::move(smallShmems), largeShmems,
resourceUpdates, smallShmems, largeShmems,
mIdNamespace, aContainsSVGGroup, aRefreshStartTime, aTxnStartTime, fwdTime);
mParentCommands.Clear();
@ -157,6 +159,7 @@ WebRenderBridgeChild::EndTransaction(const wr::LayoutSize& aContentSize,
void
WebRenderBridgeChild::EndEmptyTransaction(const FocusTarget& aFocusTarget,
const ScrollUpdatesMap& aUpdates,
Maybe<wr::IpcResourceUpdateQueue>& aResources,
uint32_t aPaintSequenceNumber,
TransactionId aTransactionId,
const mozilla::TimeStamp& aRefreshStartTime,
@ -170,9 +173,18 @@ WebRenderBridgeChild::EndEmptyTransaction(const FocusTarget& aFocusTarget,
fwdTime = TimeStamp::Now();
#endif
nsTArray<OpUpdateResource> resourceUpdates;
nsTArray<RefCountedShmem> smallShmems;
nsTArray<ipc::Shmem> largeShmems;
if (aResources) {
aResources->Flush(resourceUpdates, smallShmems, largeShmems);
aResources.reset();
}
this->SendEmptyTransaction(aFocusTarget, aUpdates, aPaintSequenceNumber,
mParentCommands, mDestroyedActors,
GetFwdTransactionId(), aTransactionId,
resourceUpdates, smallShmems, largeShmems,
mIdNamespace, aRefreshStartTime, aTxnStartTime, fwdTime);
mParentCommands.Clear();
mDestroyedActors.Clear();

Просмотреть файл

@ -66,7 +66,8 @@ public:
void AddWebRenderParentCommand(const WebRenderParentCommand& aCmd);
void UpdateResources(wr::IpcResourceUpdateQueue& aResources);
void UpdateResources(wr::IpcResourceUpdateQueue& aResources,
bool aScheduleComposite = false);
void BeginTransaction();
void EndTransaction(const wr::LayoutSize& aContentSize,
wr::BuiltDisplayList& dl,
@ -79,6 +80,7 @@ public:
const mozilla::TimeStamp& aTxnStartTime);
void EndEmptyTransaction(const FocusTarget& aFocusTarget,
const ScrollUpdatesMap& aUpdates,
Maybe<wr::IpcResourceUpdateQueue>& aResources,
uint32_t aPaintSequenceNumber,
TransactionId aTransactionId,
const mozilla::TimeStamp& aRefreshStartTime,

Просмотреть файл

@ -624,25 +624,34 @@ WebRenderBridgeParent::UpdateExternalImage(wr::ExternalImageId aExtId,
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvUpdateResources(nsTArray<OpUpdateResource>&& aResourceUpdates,
nsTArray<RefCountedShmem>&& aSmallShmems,
nsTArray<ipc::Shmem>&& aLargeShmems)
nsTArray<ipc::Shmem>&& aLargeShmems,
const bool& aScheduleComposite)
{
if (mDestroyed) {
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
return IPC_OK();
}
wr::TransactionBuilder txn;
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn)) {
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
bool success =
UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
if (!success) {
return IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
}
if (aScheduleComposite) {
txn.InvalidateRenderedFrame();
ScheduleGenerateFrame();
}
mApi->SendTransaction(txn);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
return IPC_OK();
}
@ -910,6 +919,9 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget,
InfallibleTArray<OpDestroy>&& aToDestroy,
const uint64_t& aFwdTransactionId,
const TransactionId& aTransactionId,
nsTArray<OpUpdateResource>&& aResourceUpdates,
nsTArray<RefCountedShmem>&& aSmallShmems,
nsTArray<ipc::Shmem>&& aLargeShmems,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aRefreshStartTime,
const TimeStamp& aTxnStartTime,
@ -941,10 +953,18 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget,
scheduleComposite = true;
}
wr::TransactionBuilder txn;
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
if (!aResourceUpdates.IsEmpty()) {
scheduleComposite = true;
}
if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn)) {
return IPC_FAIL(this, "Failed to deserialize resource updates");
}
if (!aCommands.IsEmpty()) {
mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
wr::TransactionBuilder txn;
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
wr::Epoch wrEpoch = GetNextWrEpoch();
txn.UpdateEpoch(mPipelineId, wrEpoch);
if (!ProcessWebRenderParentCommands(aCommands, txn)) {
@ -962,10 +982,13 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget,
);
}
mApi->SendTransaction(txn);
scheduleComposite = true;
}
if (!txn.IsEmpty()) {
mApi->SendTransaction(txn);
}
bool sendDidComposite = true;
if (scheduleComposite || !mPendingTransactionIds.empty()) {
// If we are going to kick off a new composite as a result of this
@ -1001,6 +1024,8 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget,
}
}
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
return IPC_OK();
}

Просмотреть файл

@ -78,7 +78,8 @@ public:
mozilla::ipc::IPCResult RecvDeleteCompositorAnimations(InfallibleTArray<uint64_t>&& aIds) override;
mozilla::ipc::IPCResult RecvUpdateResources(nsTArray<OpUpdateResource>&& aUpdates,
nsTArray<RefCountedShmem>&& aSmallShmems,
nsTArray<ipc::Shmem>&& aLargeShmems) override;
nsTArray<ipc::Shmem>&& aLargeShmems,
const bool& aScheduleComposite) override;
mozilla::ipc::IPCResult RecvSetDisplayList(const gfx::IntSize& aSize,
InfallibleTArray<WebRenderParentCommand>&& aCommands,
InfallibleTArray<OpDestroy>&& aToDestroy,
@ -103,6 +104,9 @@ public:
InfallibleTArray<OpDestroy>&& aToDestroy,
const uint64_t& aFwdTransactionId,
const TransactionId& aTransactionId,
nsTArray<OpUpdateResource>&& aResourceUpdates,
nsTArray<RefCountedShmem>&& aSmallShmems,
nsTArray<ipc::Shmem>&& aLargeShmems,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aRefreshStartTime,
const TimeStamp& aTxnStartTime,

Просмотреть файл

@ -14,7 +14,6 @@
#include "mozilla/dom/TabGroup.h"
#include "mozilla/gfx/DrawEventRecorder.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/IpcResourceUpdateQueue.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
@ -248,7 +247,8 @@ WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
}
WrBridge()->EndEmptyTransaction(mFocusTarget, mPendingScrollUpdates,
mPaintSequenceNumber, mLatestTransactionId, refreshStart, mTransactionStart);
mAsyncResourceUpdates, mPaintSequenceNumber, mLatestTransactionId,
refreshStart, mTransactionStart);
ClearPendingScrollInfoUpdate();
mTransactionStart = TimeStamp();
@ -343,6 +343,19 @@ WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true);
TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
if (mAsyncResourceUpdates) {
if (resourceUpdates.IsEmpty()) {
resourceUpdates = std::move(mAsyncResourceUpdates.ref());
} else {
// If we can't just swap the queue, we need to take the slow path and
// send the update as a separate message. We don't need to schedule a
// composite however because that will happen with EndTransaction.
WrBridge()->UpdateResources(mAsyncResourceUpdates.ref(),
/* aScheduleComposite */ false);
}
mAsyncResourceUpdates.reset();
}
for (const auto& key : mImageKeysToDelete) {
resourceUpdates.DeleteImage(key);
}
@ -706,5 +719,39 @@ WebRenderLayerManager::CreatePersistentBufferProvider(const gfx::IntSize& aSize,
return LayerManager::CreatePersistentBufferProvider(aSize, aFormat);
}
wr::IpcResourceUpdateQueue&
WebRenderLayerManager::AsyncResourceUpdates()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mAsyncResourceUpdates) {
mAsyncResourceUpdates.emplace(WrBridge());
RefPtr<Runnable> task = NewRunnableMethod(
"WebRenderLayerManager::FlushAsyncResourceUpdates",
this, &WebRenderLayerManager::FlushAsyncResourceUpdates);
NS_DispatchToMainThread(task.forget());
}
return mAsyncResourceUpdates.ref();
}
void
WebRenderLayerManager::FlushAsyncResourceUpdates()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mAsyncResourceUpdates) {
return;
}
if (!IsDestroyed() && WrBridge()) {
WrBridge()->UpdateResources(mAsyncResourceUpdates.ref(),
/* aScheduleComposite */ true);
}
mAsyncResourceUpdates.reset();
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -12,9 +12,11 @@
#include "gfxPrefs.h"
#include "Layers.h"
#include "mozilla/Maybe.h"
#include "mozilla/MozPromise.h"
#include "mozilla/layers/APZTestData.h"
#include "mozilla/layers/FocusTarget.h"
#include "mozilla/layers/IpcResourceUpdateQueue.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/layers/TransactionIdAllocator.h"
#include "mozilla/layers/WebRenderCommandBuilder.h"
@ -133,6 +135,9 @@ public:
void DiscardImages();
void DiscardLocalImages();
wr::IpcResourceUpdateQueue& AsyncResourceUpdates();
void FlushAsyncResourceUpdates();
// Methods to manage the compositor animation ids. Active animations are still
// going, and when they end we discard them and remove them from the active
// list.
@ -219,6 +224,8 @@ private:
WebRenderCommandBuilder mWebRenderCommandBuilder;
size_t mLastDisplayListSize;
Maybe<wr::IpcResourceUpdateQueue> mAsyncResourceUpdates;
};
} // namespace layers