forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			185 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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/. */
 | |
| 
 | |
| #include "ImageMemoryReporter.h"
 | |
| #include "Image.h"
 | |
| #include "base/process_util.h"
 | |
| #include "mozilla/layers/SharedSurfacesParent.h"
 | |
| #include "mozilla/StaticPrefs_image.h"
 | |
| #include "nsIMemoryReporter.h"
 | |
| #include "nsISupportsImpl.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace image {
 | |
| 
 | |
| ImageMemoryReporter::WebRenderReporter* ImageMemoryReporter::sWrReporter;
 | |
| 
 | |
| class ImageMemoryReporter::WebRenderReporter final : public nsIMemoryReporter {
 | |
|  public:
 | |
|   NS_DECL_ISUPPORTS
 | |
| 
 | |
|   WebRenderReporter() {}
 | |
| 
 | |
|   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
 | |
|                             nsISupports* aData, bool aAnonymize) override {
 | |
|     layers::SharedSurfacesMemoryReport report;
 | |
|     layers::SharedSurfacesParent::AccumulateMemoryReport(report);
 | |
|     ReportSharedSurfaces(aHandleReport, aData, /* aIsForCompositor */ true,
 | |
|                          report);
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   virtual ~WebRenderReporter() {}
 | |
| };
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(ImageMemoryReporter::WebRenderReporter, nsIMemoryReporter)
 | |
| 
 | |
| /* static */
 | |
| void ImageMemoryReporter::InitForWebRender() {
 | |
|   MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess());
 | |
|   if (!sWrReporter) {
 | |
|     sWrReporter = new WebRenderReporter();
 | |
|     RegisterStrongMemoryReporter(sWrReporter);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void ImageMemoryReporter::ShutdownForWebRender() {
 | |
|   MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess());
 | |
|   if (sWrReporter) {
 | |
|     UnregisterStrongMemoryReporter(sWrReporter);
 | |
|     sWrReporter = nullptr;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void ImageMemoryReporter::ReportSharedSurfaces(
 | |
|     nsIHandleReportCallback* aHandleReport, nsISupports* aData,
 | |
|     const layers::SharedSurfacesMemoryReport& aSharedSurfaces) {
 | |
|   ReportSharedSurfaces(aHandleReport, aData,
 | |
|                        /* aIsForCompositor */ false, aSharedSurfaces);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void ImageMemoryReporter::ReportSharedSurfaces(
 | |
|     nsIHandleReportCallback* aHandleReport, nsISupports* aData,
 | |
|     bool aIsForCompositor,
 | |
|     const layers::SharedSurfacesMemoryReport& aSharedSurfaces) {
 | |
|   MOZ_ASSERT_IF(aIsForCompositor, XRE_IsParentProcess() || XRE_IsGPUProcess());
 | |
|   MOZ_ASSERT_IF(!aIsForCompositor,
 | |
|                 XRE_IsParentProcess() || XRE_IsContentProcess());
 | |
| 
 | |
|   for (auto i = aSharedSurfaces.mSurfaces.begin();
 | |
|        i != aSharedSurfaces.mSurfaces.end(); ++i) {
 | |
|     ReportSharedSurface(aHandleReport, aData, aIsForCompositor, i->first,
 | |
|                         i->second);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void ImageMemoryReporter::ReportSharedSurface(
 | |
|     nsIHandleReportCallback* aHandleReport, nsISupports* aData,
 | |
|     bool aIsForCompositor, uint64_t aExternalId,
 | |
|     const layers::SharedSurfacesMemoryReport::SurfaceEntry& aEntry) {
 | |
|   nsAutoCString path;
 | |
|   if (aIsForCompositor) {
 | |
|     path.AppendLiteral("gfx/webrender/images/mapped_from_owner/");
 | |
|   } else {
 | |
|     path.AppendLiteral("gfx/webrender/images/owner_cache_missing/");
 | |
|   }
 | |
| 
 | |
|   if (aIsForCompositor) {
 | |
|     path.AppendLiteral("pid=");
 | |
|     path.AppendInt(uint32_t(aEntry.mCreatorPid));
 | |
|     path.AppendLiteral("/");
 | |
|   }
 | |
| 
 | |
|   if (StaticPrefs::image_mem_debug_reporting()) {
 | |
|     path.AppendInt(aExternalId, 16);
 | |
|     path.AppendLiteral("/");
 | |
|   }
 | |
| 
 | |
|   path.AppendLiteral("image(");
 | |
|   path.AppendInt(aEntry.mSize.width);
 | |
|   path.AppendLiteral("x");
 | |
|   path.AppendInt(aEntry.mSize.height);
 | |
|   path.AppendLiteral(", compositor_ref:");
 | |
|   path.AppendInt(aEntry.mConsumers);
 | |
|   path.AppendLiteral(", creator_ref:");
 | |
|   path.AppendInt(aEntry.mCreatorRef);
 | |
|   path.AppendLiteral(")/decoded-");
 | |
| 
 | |
|   size_t surfaceSize = mozilla::ipc::SharedMemory::PageAlignedSize(
 | |
|       aEntry.mSize.height * aEntry.mStride);
 | |
| 
 | |
|   // If this memory has already been reported elsewhere (e.g. as part of our
 | |
|   // explicit section in the surface cache), we don't want report it again as
 | |
|   // KIND_NONHEAP and have it counted again. The paths must be different if the
 | |
|   // kinds are different to avoid problems when diffing memory reports.
 | |
|   bool sameProcess = aEntry.mCreatorPid == base::GetCurrentProcId();
 | |
|   int32_t kind;
 | |
|   if (aIsForCompositor && !sameProcess) {
 | |
|     path.AppendLiteral("nonheap");
 | |
|     kind = nsIMemoryReporter::KIND_NONHEAP;
 | |
|   } else {
 | |
|     path.AppendLiteral("other");
 | |
|     kind = nsIMemoryReporter::KIND_OTHER;
 | |
|   }
 | |
| 
 | |
|   constexpr auto desc = "Decoded image data stored in shared memory."_ns;
 | |
|   aHandleReport->Callback(""_ns, path, kind, nsIMemoryReporter::UNITS_BYTES,
 | |
|                           surfaceSize, desc, aData);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void ImageMemoryReporter::AppendSharedSurfacePrefix(
 | |
|     nsACString& aPathPrefix, const SurfaceMemoryCounter& aCounter,
 | |
|     layers::SharedSurfacesMemoryReport& aSharedSurfaces) {
 | |
|   uint64_t extId = aCounter.Values().ExternalId();
 | |
|   if (extId) {
 | |
|     auto gpuEntry = aSharedSurfaces.mSurfaces.find(extId);
 | |
| 
 | |
|     if (StaticPrefs::image_mem_debug_reporting()) {
 | |
|       aPathPrefix.AppendLiteral(", external_id:");
 | |
|       aPathPrefix.AppendInt(extId, 16);
 | |
|       if (gpuEntry != aSharedSurfaces.mSurfaces.end()) {
 | |
|         aPathPrefix.AppendLiteral(", compositor_ref:");
 | |
|         aPathPrefix.AppendInt(gpuEntry->second.mConsumers);
 | |
|       } else {
 | |
|         aPathPrefix.AppendLiteral(", compositor_ref:missing");
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (gpuEntry != aSharedSurfaces.mSurfaces.end()) {
 | |
|       MOZ_ASSERT(gpuEntry->second.mCreatorRef);
 | |
|       aSharedSurfaces.mSurfaces.erase(gpuEntry);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void ImageMemoryReporter::TrimSharedSurfaces(
 | |
|     const ImageMemoryCounter& aCounter,
 | |
|     layers::SharedSurfacesMemoryReport& aSharedSurfaces) {
 | |
|   if (aSharedSurfaces.mSurfaces.empty()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   for (const SurfaceMemoryCounter& counter : aCounter.Surfaces()) {
 | |
|     uint64_t extId = counter.Values().ExternalId();
 | |
|     if (extId) {
 | |
|       auto gpuEntry = aSharedSurfaces.mSurfaces.find(extId);
 | |
|       if (gpuEntry != aSharedSurfaces.mSurfaces.end()) {
 | |
|         MOZ_ASSERT(gpuEntry->second.mCreatorRef);
 | |
|         aSharedSurfaces.mSurfaces.erase(gpuEntry);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace image
 | |
| }  // namespace mozilla
 | 
