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 "mozilla/StaticPrefs_image.h"
11 #include "nsIMemoryReporter.h"
12 #include "nsISupportsImpl.h"
17 ImageMemoryReporter::WebRenderReporter
* ImageMemoryReporter::sWrReporter
;
19 class ImageMemoryReporter::WebRenderReporter final
: public nsIMemoryReporter
{
23 WebRenderReporter() {}
25 NS_IMETHOD
CollectReports(nsIHandleReportCallback
* aHandleReport
,
26 nsISupports
* aData
, bool aAnonymize
) override
{
27 layers::SharedSurfacesMemoryReport report
;
28 layers::SharedSurfacesParent::AccumulateMemoryReport(report
);
29 ReportSharedSurfaces(aHandleReport
, aData
, /* aIsForCompositor */ true,
35 virtual ~WebRenderReporter() {}
38 NS_IMPL_ISUPPORTS(ImageMemoryReporter::WebRenderReporter
, nsIMemoryReporter
)
41 void ImageMemoryReporter::InitForWebRender() {
42 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess());
44 sWrReporter
= new WebRenderReporter();
45 RegisterStrongMemoryReporter(sWrReporter
);
50 void ImageMemoryReporter::ShutdownForWebRender() {
51 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess());
53 UnregisterStrongMemoryReporter(sWrReporter
);
54 sWrReporter
= nullptr;
59 void ImageMemoryReporter::ReportSharedSurfaces(
60 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
61 const layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
62 ReportSharedSurfaces(aHandleReport
, aData
,
63 /* aIsForCompositor */ false, aSharedSurfaces
);
67 void ImageMemoryReporter::ReportSharedSurfaces(
68 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
69 bool aIsForCompositor
,
70 const layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
71 MOZ_ASSERT_IF(aIsForCompositor
, XRE_IsParentProcess() || XRE_IsGPUProcess());
72 MOZ_ASSERT_IF(!aIsForCompositor
,
73 XRE_IsParentProcess() || XRE_IsContentProcess());
75 for (auto i
= aSharedSurfaces
.mSurfaces
.begin();
76 i
!= aSharedSurfaces
.mSurfaces
.end(); ++i
) {
77 ReportSharedSurface(aHandleReport
, aData
, aIsForCompositor
, i
->first
,
83 void ImageMemoryReporter::ReportSharedSurface(
84 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
85 bool aIsForCompositor
, uint64_t aExternalId
,
86 const layers::SharedSurfacesMemoryReport::SurfaceEntry
& aEntry
) {
88 if (aIsForCompositor
) {
89 path
.AppendLiteral("gfx/webrender/images/mapped_from_owner/");
91 path
.AppendLiteral("gfx/webrender/images/owner_cache_missing/");
94 if (aIsForCompositor
) {
95 path
.AppendLiteral("pid=");
96 path
.AppendInt(uint32_t(aEntry
.mCreatorPid
));
97 path
.AppendLiteral("/");
100 if (StaticPrefs::image_mem_debug_reporting()) {
101 path
.AppendInt(aExternalId
, 16);
102 path
.AppendLiteral("/");
105 path
.AppendLiteral("image(");
106 path
.AppendInt(aEntry
.mSize
.width
);
107 path
.AppendLiteral("x");
108 path
.AppendInt(aEntry
.mSize
.height
);
109 path
.AppendLiteral(", compositor_ref:");
110 path
.AppendInt(aEntry
.mConsumers
);
111 path
.AppendLiteral(", creator_ref:");
112 path
.AppendInt(aEntry
.mCreatorRef
);
113 path
.AppendLiteral(")/decoded-nonheap");
115 size_t surfaceSize
= mozilla::ipc::SharedMemory::PageAlignedSize(
116 aEntry
.mSize
.height
* aEntry
.mStride
);
118 // If this memory has already been reported elsewhere (e.g. as part of our
119 // explicit section in the surface cache), we don't want report it again as
120 // KIND_NONHEAP and have it counted again.
121 bool sameProcess
= aEntry
.mCreatorPid
== base::GetCurrentProcId();
122 int32_t kind
= aIsForCompositor
&& !sameProcess
123 ? nsIMemoryReporter::KIND_NONHEAP
124 : nsIMemoryReporter::KIND_OTHER
;
126 NS_NAMED_LITERAL_CSTRING(desc
, "Decoded image data stored in shared memory.");
127 aHandleReport
->Callback(EmptyCString(), path
, kind
,
128 nsIMemoryReporter::UNITS_BYTES
, surfaceSize
, desc
,
133 void ImageMemoryReporter::AppendSharedSurfacePrefix(
134 nsACString
& aPathPrefix
, const SurfaceMemoryCounter
& aCounter
,
135 layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
136 uint64_t extId
= aCounter
.Values().ExternalId();
138 auto gpuEntry
= aSharedSurfaces
.mSurfaces
.find(extId
);
140 if (StaticPrefs::image_mem_debug_reporting()) {
141 aPathPrefix
.AppendLiteral(", external_id:");
142 aPathPrefix
.AppendInt(extId
, 16);
143 if (gpuEntry
!= aSharedSurfaces
.mSurfaces
.end()) {
144 aPathPrefix
.AppendLiteral(", compositor_ref:");
145 aPathPrefix
.AppendInt(gpuEntry
->second
.mConsumers
);
147 aPathPrefix
.AppendLiteral(", compositor_ref:missing");
151 if (gpuEntry
!= aSharedSurfaces
.mSurfaces
.end()) {
152 MOZ_ASSERT(gpuEntry
->second
.mCreatorRef
);
153 aSharedSurfaces
.mSurfaces
.erase(gpuEntry
);
159 void ImageMemoryReporter::TrimSharedSurfaces(
160 const ImageMemoryCounter
& aCounter
,
161 layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
162 if (aSharedSurfaces
.mSurfaces
.empty()) {
166 for (const SurfaceMemoryCounter
& counter
: aCounter
.Surfaces()) {
167 uint64_t extId
= counter
.Values().ExternalId();
169 auto gpuEntry
= aSharedSurfaces
.mSurfaces
.find(extId
);
170 if (gpuEntry
!= aSharedSurfaces
.mSurfaces
.end()) {
171 MOZ_ASSERT(gpuEntry
->second
.mCreatorRef
);
172 aSharedSurfaces
.mSurfaces
.erase(gpuEntry
);
179 } // namespace mozilla