1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ImageMemoryReporter.h"
9 #include "mozilla/layers/SharedSurfacesParent.h"
10 #include "nsIMemoryReporter.h"
11 #include "nsISupportsImpl.h"
16 ImageMemoryReporter::WebRenderReporter
* ImageMemoryReporter::sWrReporter
;
18 class ImageMemoryReporter::WebRenderReporter final
: public nsIMemoryReporter
{
22 WebRenderReporter() {}
24 NS_IMETHOD
CollectReports(nsIHandleReportCallback
* aHandleReport
,
25 nsISupports
* aData
, bool aAnonymize
) override
{
26 layers::SharedSurfacesMemoryReport report
;
27 layers::SharedSurfacesParent::AccumulateMemoryReport(report
);
28 ReportSharedSurfaces(aHandleReport
, aData
, /* aIsForCompositor */ true,
34 virtual ~WebRenderReporter() {}
37 NS_IMPL_ISUPPORTS(ImageMemoryReporter::WebRenderReporter
, nsIMemoryReporter
)
40 void ImageMemoryReporter::InitForWebRender() {
41 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess());
43 sWrReporter
= new WebRenderReporter();
44 RegisterStrongMemoryReporter(sWrReporter
);
49 void ImageMemoryReporter::ShutdownForWebRender() {
50 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess());
52 UnregisterStrongMemoryReporter(sWrReporter
);
53 sWrReporter
= nullptr;
58 void ImageMemoryReporter::ReportSharedSurfaces(
59 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
60 const layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
61 ReportSharedSurfaces(aHandleReport
, aData
,
62 /* aIsForCompositor */ false, aSharedSurfaces
);
66 void ImageMemoryReporter::ReportSharedSurfaces(
67 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
68 bool aIsForCompositor
,
69 const layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
70 MOZ_ASSERT_IF(aIsForCompositor
, XRE_IsParentProcess() || XRE_IsGPUProcess());
71 MOZ_ASSERT_IF(!aIsForCompositor
,
72 XRE_IsParentProcess() || XRE_IsContentProcess());
74 for (auto i
= aSharedSurfaces
.mSurfaces
.begin();
75 i
!= aSharedSurfaces
.mSurfaces
.end(); ++i
) {
76 ReportSharedSurface(aHandleReport
, aData
, aIsForCompositor
, i
->first
,
82 void ImageMemoryReporter::ReportSharedSurface(
83 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
84 bool aIsForCompositor
, uint64_t aExternalId
,
85 const layers::SharedSurfacesMemoryReport::SurfaceEntry
& aEntry
) {
87 if (aIsForCompositor
) {
88 path
.AppendLiteral("gfx/webrender/images/mapped_from_owner/");
90 path
.AppendLiteral("gfx/webrender/images/owner_cache_missing/");
93 if (aIsForCompositor
) {
94 path
.AppendLiteral("pid=");
95 path
.AppendInt(uint32_t(aEntry
.mCreatorPid
));
96 path
.AppendLiteral("/");
99 if (gfxPrefs::ImageMemDebugReporting()) {
100 path
.AppendInt(aExternalId
, 16);
101 path
.AppendLiteral("/");
104 path
.AppendLiteral("image(");
105 path
.AppendInt(aEntry
.mSize
.width
);
106 path
.AppendLiteral("x");
107 path
.AppendInt(aEntry
.mSize
.height
);
108 path
.AppendLiteral(", compositor_ref:");
109 path
.AppendInt(aEntry
.mConsumers
);
110 path
.AppendLiteral(", creator_ref:");
111 path
.AppendInt(aEntry
.mCreatorRef
);
112 path
.AppendLiteral(")/decoded-nonheap");
114 size_t surfaceSize
= mozilla::ipc::SharedMemory::PageAlignedSize(
115 aEntry
.mSize
.height
* aEntry
.mStride
);
117 // If this memory has already been reported elsewhere (e.g. as part of our
118 // explicit section in the surface cache), we don't want report it again as
119 // KIND_NONHEAP and have it counted again.
120 bool sameProcess
= aEntry
.mCreatorPid
== base::GetCurrentProcId();
121 int32_t kind
= aIsForCompositor
&& !sameProcess
122 ? nsIMemoryReporter::KIND_NONHEAP
123 : nsIMemoryReporter::KIND_OTHER
;
125 NS_NAMED_LITERAL_CSTRING(desc
, "Decoded image data stored in shared memory.");
126 aHandleReport
->Callback(EmptyCString(), path
, kind
,
127 nsIMemoryReporter::UNITS_BYTES
, surfaceSize
, desc
,
132 void ImageMemoryReporter::AppendSharedSurfacePrefix(
133 nsACString
& aPathPrefix
, const SurfaceMemoryCounter
& aCounter
,
134 layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
135 uint64_t extId
= aCounter
.Values().ExternalId();
137 auto gpuEntry
= aSharedSurfaces
.mSurfaces
.find(extId
);
139 if (gfxPrefs::ImageMemDebugReporting()) {
140 aPathPrefix
.AppendLiteral(", external_id:");
141 aPathPrefix
.AppendInt(extId
, 16);
142 if (gpuEntry
!= aSharedSurfaces
.mSurfaces
.end()) {
143 aPathPrefix
.AppendLiteral(", compositor_ref:");
144 aPathPrefix
.AppendInt(gpuEntry
->second
.mConsumers
);
146 aPathPrefix
.AppendLiteral(", compositor_ref:missing");
150 if (gpuEntry
!= aSharedSurfaces
.mSurfaces
.end()) {
151 MOZ_ASSERT(gpuEntry
->second
.mCreatorRef
);
152 aSharedSurfaces
.mSurfaces
.erase(gpuEntry
);
158 void ImageMemoryReporter::TrimSharedSurfaces(
159 const ImageMemoryCounter
& aCounter
,
160 layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
161 if (aSharedSurfaces
.mSurfaces
.empty()) {
165 for (const SurfaceMemoryCounter
& counter
: aCounter
.Surfaces()) {
166 uint64_t extId
= counter
.Values().ExternalId();
168 auto gpuEntry
= aSharedSurfaces
.mSurfaces
.find(extId
);
169 if (gpuEntry
!= aSharedSurfaces
.mSurfaces
.end()) {
170 MOZ_ASSERT(gpuEntry
->second
.mCreatorRef
);
171 aSharedSurfaces
.mSurfaces
.erase(gpuEntry
);
178 } // namespace mozilla