Bug 1492930 - Part 1. Expose composition of shared surfaces cache to allow memory reporting. r=nical

This exposes methods to capture a snapshot of the SharedSurfacesParent
cache for memory reporting purposes. It yields the identifiers, image
properties and references to images mapped in the cache. This will be
used by the compositor process to list everything it has mapped into its
memory space. It will also be used by the content processes / main
process to list images that specific process had mapped into the
compositor process. This will allow us to easily identify what images
remain in the compositor process, but are missing from the surface
cache.
This commit is contained in:
Andrew Osmond 2018-09-25 09:13:51 -04:00
Родитель e65c479846
Коммит 3aedcdc649
10 изменённых файлов: 220 добавлений и 8 удалений

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

@ -43,6 +43,7 @@ public:
, mConsumers(0)
, mFormat(SurfaceFormat::UNKNOWN)
, mCreatorPid(0)
, mCreatorRef(true)
{ }
bool Init(const IntSize& aSize,
@ -79,12 +80,30 @@ public:
return ++mConsumers == 1;
}
bool RemoveConsumer()
bool RemoveConsumer(bool aForCreator)
{
MOZ_ASSERT(mConsumers > 0);
if (aForCreator) {
if (!mCreatorRef) {
MOZ_ASSERT_UNREACHABLE("Already released creator reference!");
return false;
}
mCreatorRef = false;
}
return --mConsumers == 0;
}
uint32_t GetConsumers() const
{
MOZ_ASSERT(mConsumers > 0);
return mConsumers;
}
bool HasCreatorRef() const
{
return mCreatorRef;
}
private:
size_t GetDataLength() const
{
@ -102,6 +121,7 @@ private:
RefPtr<SharedMemoryBasic> mBuf;
SurfaceFormat mFormat;
base::ProcessId mCreatorPid;
bool mCreatorRef;
};
/**

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

@ -289,6 +289,15 @@ CompositorManagerParent::RecvRemoveSharedSurface(const wr::ExternalImageId& aId)
return IPC_OK();
}
mozilla::ipc::IPCResult
CompositorManagerParent::RecvReportSharedSurfacesMemory(ReportSharedSurfacesMemoryResolver&& aResolver)
{
SharedSurfacesMemoryReport report;
SharedSurfacesParent::AccumulateMemoryReport(OtherPid(), report);
aResolver(std::move(report));
return IPC_OK();
}
mozilla::ipc::IPCResult
CompositorManagerParent::RecvNotifyMemoryPressure()
{

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

@ -43,6 +43,7 @@ public:
mozilla::ipc::IPCResult RecvAddSharedSurface(const wr::ExternalImageId& aId,
const SurfaceDescriptorShared& aDesc) override;
mozilla::ipc::IPCResult RecvRemoveSharedSurface(const wr::ExternalImageId& aId) override;
mozilla::ipc::IPCResult RecvReportSharedSurfacesMemory(ReportSharedSurfacesMemoryResolver&&) override;
virtual mozilla::ipc::IPCResult RecvNotifyMemoryPressure() override;

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

@ -18,6 +18,7 @@ using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasi
using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h";
using mozilla::wr::ExternalImageId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::MemoryReport from "mozilla/webrender/WebRenderTypes.h";
using mozilla::layers::SharedSurfacesMemoryReport from "mozilla/layers/SharedSurfacesMemoryReport.h";
namespace mozilla {
namespace layers {
@ -76,6 +77,7 @@ parent:
async AddSharedSurface(ExternalImageId aId, SurfaceDescriptorShared aDesc);
async RemoveSharedSurface(ExternalImageId aId);
async ReportSharedSurfacesMemory() returns (SharedSurfacesMemoryReport aReport);
async NotifyMemoryPressure();

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

@ -19,6 +19,8 @@ namespace layers {
using namespace mozilla::gfx;
/* static */ UserDataKey SharedSurfacesChild::sSharedKey;
class SharedSurfacesChild::ImageKeyData final
{
public:
@ -224,7 +226,6 @@ SharedSurfacesChild::ShareInternal(SourceSurfaceSharedData* aSurface,
return NS_ERROR_NOT_INITIALIZED;
}
static UserDataKey sSharedKey;
SharedUserData* data =
static_cast<SharedUserData*>(aSurface->GetUserData(&sSharedKey));
if (!data) {
@ -455,5 +456,20 @@ SharedSurfacesChild::Unshare(const wr::ExternalImageId& aId,
}
}
/* static */ Maybe<wr::ExternalImageId>
SharedSurfacesChild::GetExternalId(const SourceSurfaceSharedData* aSurface)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aSurface);
SharedUserData* data =
static_cast<SharedUserData*>(aSurface->GetUserData(&sSharedKey));
if (!data || !data->IsShared()) {
return Nothing();
}
return Some(data->Id());
}
} // namespace layers
} // namespace mozilla

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

@ -10,8 +10,10 @@
#include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t, uint64_t
#include "mozilla/Attributes.h" // for override
#include "mozilla/Maybe.h" // for Maybe
#include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/StaticPtr.h" // for StaticRefPtr
#include "mozilla/gfx/UserData.h" // for UserDataKey
#include "mozilla/webrender/WebRenderTypes.h" // for wr::ImageKey
namespace mozilla {
@ -71,6 +73,13 @@ public:
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey);
/**
* Get the external ID, if any, bound to the shared surface. Used for memory
* reporting purposes.
*/
static Maybe<wr::ExternalImageId>
GetExternalId(const gfx::SourceSurfaceSharedData* aSurface);
private:
SharedSurfacesChild() = delete;
~SharedSurfacesChild() = delete;
@ -83,6 +92,8 @@ private:
static void Unshare(const wr::ExternalImageId& aId, nsTArray<ImageKeyData>& aKeys);
static void DestroySharedUserData(void* aClosure);
static gfx::UserDataKey sSharedKey;
};
} // namespace layers

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

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 MOZILLA_GFX_SHAREDSURFACESMEMORYREPORT_H
#define MOZILLA_GFX_SHAREDSURFACESMEMORYREPORT_H
#include <cstdint> // for uint32_t
#include <unordered_map>
#include "ipc/IPCMessageUtils.h"
#include "mozilla/gfx/Point.h" // for IntSize
namespace mozilla {
namespace layers {
class SharedSurfacesMemoryReport final
{
public:
class SurfaceEntry final {
public:
base::ProcessId mCreatorPid;
gfx::IntSize mSize;
int32_t mStride;
uint32_t mConsumers;
bool mCreatorRef;
};
std::unordered_map<uint64_t, SurfaceEntry> mSurfaces;
};
} // namespace layers
} // namespace mozilla
namespace IPC {
template<>
struct ParamTraits<mozilla::layers::SharedSurfacesMemoryReport>
{
typedef mozilla::layers::SharedSurfacesMemoryReport paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(aMsg, aParam.mSurfaces);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, &aResult->mSurfaces);
}
};
template<>
struct ParamTraits<mozilla::layers::SharedSurfacesMemoryReport::SurfaceEntry>
: public PlainOldDataSerializer<mozilla::layers::SharedSurfacesMemoryReport::SurfaceEntry>
{
};
template<class KeyType, class DataType>
struct ParamTraits<std::unordered_map<KeyType, DataType>>
{
typedef std::unordered_map<KeyType, DataType> paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(aMsg, aParam.size());
for (auto i = aParam.begin(); i != aParam.end(); ++i) {
WriteParam(aMsg, i->first);
WriteParam(aMsg, i->second);
}
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
size_t count;
if (!ReadParam(aMsg, aIter, &count)) {
return false;
}
for (; count > 0; --count) {
KeyType k;
DataType v;
if (!ReadParam(aMsg, aIter, &k) ||
!ReadParam(aMsg, aIter, &v)) {
return false;
}
aResult->insert(std::make_pair(std::move(k), std::move(v)));
}
return true;
}
};
} // namespace IPC
#endif

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

@ -6,6 +6,8 @@
#include "SharedSurfacesParent.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/layers/SharedSurfacesMemoryReport.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/webrender/RenderSharedSurfaceTextureHost.h"
@ -85,7 +87,7 @@ SharedSurfacesParent::Acquire(const wr::ExternalImageId& aId)
}
/* static */ bool
SharedSurfacesParent::Release(const wr::ExternalImageId& aId)
SharedSurfacesParent::Release(const wr::ExternalImageId& aId, bool aForCreator)
{
StaticMutexAutoLock lock(sMutex);
if (!sInstance) {
@ -99,7 +101,7 @@ SharedSurfacesParent::Release(const wr::ExternalImageId& aId)
return false;
}
if (surface->RemoveConsumer()) {
if (surface->RemoveConsumer(aForCreator)) {
wr::RenderThread::Get()->UnregisterExternalImage(id);
sInstance->mSurfaces.Remove(id);
}
@ -143,7 +145,7 @@ SharedSurfacesParent::RemoveSameProcess(const wr::ExternalImageId& aId)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
Release(aId);
Release(aId, /* aForCreator */ true);
}
/* static */ void
@ -158,7 +160,9 @@ SharedSurfacesParent::DestroyProcess(base::ProcessId aPid)
// lot of surfaces still bound that require unmapping.
for (auto i = sInstance->mSurfaces.Iter(); !i.Done(); i.Next()) {
SourceSurfaceSharedDataWrapper* surface = i.Data();
if (surface->GetCreatorPid() == aPid && surface->RemoveConsumer()) {
if (surface->GetCreatorPid() == aPid &&
surface->HasCreatorRef() &&
surface->RemoveConsumer(/* aForCreator */ true)) {
wr::RenderThread::Get()->UnregisterExternalImage(i.Key());
i.Remove();
}
@ -200,9 +204,57 @@ SharedSurfacesParent::Add(const wr::ExternalImageId& aId,
/* static */ void
SharedSurfacesParent::Remove(const wr::ExternalImageId& aId)
{
DebugOnly<bool> rv = Release(aId);
DebugOnly<bool> rv = Release(aId, /* aForCreator */ true);
MOZ_ASSERT(rv);
}
/* static */ void
SharedSurfacesParent::AccumulateMemoryReport(base::ProcessId aPid,
SharedSurfacesMemoryReport& aReport)
{
StaticMutexAutoLock lock(sMutex);
if (!sInstance) {
return;
}
for (auto i = sInstance->mSurfaces.ConstIter(); !i.Done(); i.Next()) {
SourceSurfaceSharedDataWrapper* surface = i.Data();
if (surface->GetCreatorPid() == aPid) {
aReport.mSurfaces.insert(std::make_pair(i.Key(),
SharedSurfacesMemoryReport::SurfaceEntry {
aPid, surface->GetSize(), surface->Stride(),
surface->GetConsumers(), surface->HasCreatorRef() }));
}
}
}
/* static */ bool
SharedSurfacesParent::AccumulateMemoryReport(SharedSurfacesMemoryReport& aReport)
{
if (XRE_IsParentProcess()) {
GPUProcessManager* gpm = GPUProcessManager::Get();
if (!gpm || gpm->GPUProcessPid() != -1) {
return false;
}
} else if (!XRE_IsGPUProcess()) {
return false;
}
StaticMutexAutoLock lock(sMutex);
if (!sInstance) {
return true;
}
for (auto i = sInstance->mSurfaces.ConstIter(); !i.Done(); i.Next()) {
SourceSurfaceSharedDataWrapper* surface = i.Data();
aReport.mSurfaces.insert(std::make_pair(i.Key(),
SharedSurfacesMemoryReport::SurfaceEntry {
surface->GetCreatorPid(), surface->GetSize(), surface->Stride(),
surface->GetConsumers(), surface->HasCreatorRef() }));
}
return true;
}
} // namespace layers
} // namespace mozilla

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

@ -29,6 +29,7 @@ class SourceSurfaceSharedDataWrapper;
namespace layers {
class SharedSurfacesChild;
class SharedSurfacesMemoryReport;
class SharedSurfacesParent final
{
@ -44,7 +45,8 @@ public:
static already_AddRefed<gfx::DataSourceSurface>
Acquire(const wr::ExternalImageId& aId);
static bool Release(const wr::ExternalImageId& aId);
static bool Release(const wr::ExternalImageId& aId,
bool aForCreator = false);
static void Add(const wr::ExternalImageId& aId,
const SurfaceDescriptorShared& aDesc,
@ -54,6 +56,11 @@ public:
static void DestroyProcess(base::ProcessId aPid);
static void AccumulateMemoryReport(base::ProcessId aPid,
SharedSurfacesMemoryReport& aReport);
static bool AccumulateMemoryReport(SharedSurfacesMemoryReport& aReport);
~SharedSurfacesParent();
private:

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

@ -196,6 +196,7 @@ EXPORTS.mozilla.layers += [
'ipc/SharedPlanarYCbCrImage.h',
'ipc/SharedRGBImage.h',
'ipc/SharedSurfacesChild.h',
'ipc/SharedSurfacesMemoryReport.h',
'ipc/SharedSurfacesParent.h',
'ipc/SynchronousTask.h',
'ipc/TextureForwarder.h',