Bug 1405824 - Recycle a Shmem for IpcResourceUpdateQueue to avoid allocation overhead. r=jrmuizel

This commit is contained in:
Nicolas Silva 2018-01-12 15:11:32 +01:00
Родитель 36aaaf44e8
Коммит a98ed42cd6
6 изменённых файлов: 99 добавлений и 47 удалений

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

@ -92,11 +92,12 @@ bool
ShmSegmentsWriter::AllocChunk()
{
RefCountedShmem shm;
if (!RefCountedShm::Alloc(mShmAllocator, mChunkSize, shm)) {
if (!mShmAllocator->AllocResourceShmem(mChunkSize, shm)) {
gfxCriticalNote << "ShmSegmentsWriter failed to allocate chunk #" << mSmallAllocs.Length();
MOZ_ASSERT(false, "ShmSegmentsWriter fails to allocate chunk");
return false;
}
RefCountedShm::AddRef(shm);
mSmallAllocs.AppendElement(shm);
return true;
}
@ -119,8 +120,8 @@ ShmSegmentsWriter::AllocLargeChunk(size_t aSize)
void
ShmSegmentsWriter::Flush(nsTArray<RefCountedShmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs)
{
aSmallAllocs.Clear();
aLargeAllocs.Clear();
MOZ_ASSERT(aSmallAllocs.IsEmpty());
MOZ_ASSERT(aLargeAllocs.IsEmpty());
mSmallAllocs.SwapElements(aSmallAllocs);
mLargeAllocs.SwapElements(aLargeAllocs);
}
@ -129,15 +130,9 @@ void
ShmSegmentsWriter::Clear()
{
if (mShmAllocator) {
for (auto& shm : mSmallAllocs) {
RefCountedShm::Dealloc(mShmAllocator, shm);
}
for (auto& shm : mLargeAllocs) {
mShmAllocator->DeallocShmem(shm);
}
IpcResourceUpdateQueue::ReleaseShmems(mShmAllocator, mSmallAllocs);
IpcResourceUpdateQueue::ReleaseShmems(mShmAllocator, mLargeAllocs);
}
mSmallAllocs.Clear();
mLargeAllocs.Clear();
mCursor = 0;
}
@ -354,7 +349,7 @@ IpcResourceUpdateQueue::DeleteFontInstance(wr::FontInstanceKey aKey)
void
IpcResourceUpdateQueue::Flush(nsTArray<layers::OpUpdateResource>& aUpdates,
nsTArray<RefCountedShmem>& aSmallAllocs,
nsTArray<layers::RefCountedShmem>& aSmallAllocs,
nsTArray<ipc::Shmem>& aLargeAllocs)
{
aUpdates.Clear();
@ -369,5 +364,27 @@ IpcResourceUpdateQueue::Clear()
mUpdates.Clear();
}
//static
void
IpcResourceUpdateQueue::ReleaseShmems(ipc::IProtocol* aShmAllocator, nsTArray<layers::RefCountedShmem>& aShms)
{
for (auto& shm : aShms) {
if (RefCountedShm::IsValid(shm) && RefCountedShm::Release(shm) == 0) {
RefCountedShm::Dealloc(aShmAllocator, shm);
}
}
aShms.Clear();
}
//static
void
IpcResourceUpdateQueue::ReleaseShmems(ipc::IProtocol* aShmAllocator, nsTArray<ipc::Shmem>& aShms)
{
for (auto& shm : aShms) {
aShmAllocator->DeallocShmem(shm);
}
aShms.Clear();
}
} // namespace
} // namespace

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

@ -118,6 +118,8 @@ public:
nsTArray<layers::RefCountedShmem>& aSmallAllocs,
nsTArray<ipc::Shmem>& aLargeAllocs);
static void ReleaseShmems(ipc::IProtocol*, nsTArray<layers::RefCountedShmem>& aShmems);
static void ReleaseShmems(ipc::IProtocol*, nsTArray<ipc::Shmem>& aShmems);
protected:
ShmSegmentsWriter mWriter;
nsTArray<layers::OpUpdateResource> mUpdates;

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

@ -68,6 +68,11 @@ WebRenderBridgeChild::ActorDestroy(ActorDestroyReason why)
void
WebRenderBridgeChild::DoDestroy()
{
if (RefCountedShm::IsValid(mResourceShm) && RefCountedShm::Release(mResourceShm) == 0) {
RefCountedShm::Dealloc(this, mResourceShm);
mResourceShm = RefCountedShmem();
}
// mDestroyed is used to prevent calling Send__delete__() twice.
// When this function is called from CompositorBridgeChild::Destroy().
// mActiveResourceTracker is not cleared here, since it is
@ -637,5 +642,49 @@ WebRenderBridgeChild::GetForMedia()
return MakeAndAddRef<KnowsCompositorMediaProxy>(GetTextureFactoryIdentifier());
}
bool
WebRenderBridgeChild::AllocResourceShmem(size_t aSize, RefCountedShmem& aShm)
{
// We keep a single shmem around to reuse later if it is reference count has
// dropped back to 1 (the reference held by the WebRenderBridgeChild).
// If the cached shmem exists, has the correct size and isn't held by anything
// other than us, recycle it.
bool alreadyAllocated = RefCountedShm::IsValid(mResourceShm);
if (alreadyAllocated) {
if (RefCountedShm::GetSize(mResourceShm) == aSize
&& RefCountedShm::GetReferenceCount(mResourceShm) <= 1) {
MOZ_ASSERT(RefCountedShm::GetReferenceCount(mResourceShm) == 1);
aShm = mResourceShm;
return true;
}
}
// If there was no cached shmem or we couldn't recycle it, alloc a new one.
if (!RefCountedShm::Alloc(this, aSize, aShm)) {
return false;
}
// Now that we have a valid shmem, put it in the cache if we don't have one
// yet.
if (!alreadyAllocated) {
mResourceShm = aShm;
RefCountedShm::AddRef(aShm);
}
return true;
}
void
WebRenderBridgeChild::DeallocResourceShmem(RefCountedShmem& aShm)
{
if (!RefCountedShm::IsValid(aShm)) {
return;
}
MOZ_ASSERT(RefCountedShm::GetReferenceCount(aShm) == 0);
RefCountedShm::Dealloc(this, aShm);
}
} // namespace layers
} // namespace mozilla

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

@ -154,6 +154,17 @@ public:
virtual RefPtr<KnowsCompositor> GetForMedia() override;
/// Alloc a specific type of shmem that is intended for use in
/// IpcResourceUpdateQueue only, and cache at most one of them,
/// when called multiple times.
///
/// Do not use this for anything else.
bool AllocResourceShmem(size_t aSize, RefCountedShmem& aShm);
/// Dealloc shared memory that was allocated with AllocResourceShmem.
///
/// Do not use this for anything else.
void DeallocResourceShmem(RefCountedShmem& aShm);
private:
friend class CompositorBridgeChild;
@ -224,6 +235,8 @@ private:
nsDataHashtable<ScaledFontHashKey, wr::FontInstanceKey> mFontInstanceKeys;
UniquePtr<ActiveResourceTracker> mActiveResourceTracker;
RefCountedShmem mResourceShm;
};
} // namespace layers

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

@ -266,28 +266,6 @@ WebRenderBridgeParent::Destroy()
ClearResources();
}
void
WebRenderBridgeParent::DeallocShmems(nsTArray<ipc::Shmem>& aShmems)
{
if (IPCOpen()) {
for (auto& shm : aShmems) {
DeallocShmem(shm);
}
}
aShmems.Clear();
}
void
WebRenderBridgeParent::DeallocShmems(nsTArray<RefCountedShmem>& aShmems)
{
if (IPCOpen()) {
for (auto& shm : aShmems) {
RefCountedShm::Dealloc(this, shm);
}
}
aShmems.Clear();
}
bool
WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
const nsTArray<RefCountedShmem>& aSmallShmems,
@ -465,16 +443,14 @@ WebRenderBridgeParent::RecvUpdateResources(nsTArray<OpUpdateResource>&& aResourc
nsTArray<ipc::Shmem>&& aLargeShmems)
{
if (mDestroyed) {
DeallocShmems(aSmallShmems);
DeallocShmems(aLargeShmems);
return IPC_OK();
}
wr::ResourceUpdateQueue updates;
if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, updates)) {
DeallocShmems(aSmallShmems);
DeallocShmems(aLargeShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
}
@ -482,8 +458,8 @@ WebRenderBridgeParent::RecvUpdateResources(nsTArray<OpUpdateResource>&& aResourc
txn.UpdateResources(updates);
mApi->SendTransaction(txn);
DeallocShmems(aSmallShmems);
DeallocShmems(aLargeShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
return IPC_OK();
}
@ -601,8 +577,6 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
for (const auto& op : aToDestroy) {
DestroyActor(op);
}
DeallocShmems(aSmallShmems);
DeallocShmems(aLargeShmems);
return IPC_OK();
}
@ -664,8 +638,8 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
mCompositorBridge->DidComposite(wr::AsUint64(mPipelineId), now, now);
}
DeallocShmems(aSmallShmems);
DeallocShmems(aLargeShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
return IPC_OK();
}

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

@ -192,9 +192,6 @@ public:
CompositorAnimationStorage* aAnimStorage);
private:
void DeallocShmems(nsTArray<ipc::Shmem>& aShmems);
void DeallocShmems(nsTArray<RefCountedShmem>& aShmems);
explicit WebRenderBridgeParent(const wr::PipelineId& aPipelineId);
virtual ~WebRenderBridgeParent();