1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "gpu/command_buffer/common/skia_utils.h"
6 
7 #include <inttypes.h>
8 
9 #include "base/strings/stringprintf.h"
10 #include "base/trace_event/memory_dump_manager.h"
11 #include "base/trace_event/process_memory_dump.h"
12 #include "build/build_config.h"
13 #include "third_party/skia/include/core/SkTraceMemoryDump.h"
14 #include "third_party/skia/include/gpu/GrDirectContext.h"
15 #include "ui/gl/trace_util.h"
16 
17 namespace gpu {
18 namespace raster {
19 namespace {
20 
21 // Derives from SkTraceMemoryDump and implements graphics specific memory
22 // backing functionality.
23 class SkiaGpuTraceMemoryDump : public SkTraceMemoryDump {
24  public:
25   // This should never outlive the provided ProcessMemoryDump, as it should
26   // always be scoped to a single OnMemoryDump funciton call.
SkiaGpuTraceMemoryDump(base::trace_event::ProcessMemoryDump * pmd,base::Optional<uint64_t> share_group_tracing_guid)27   SkiaGpuTraceMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
28                          base::Optional<uint64_t> share_group_tracing_guid)
29       : pmd_(pmd),
30         share_group_tracing_guid_(share_group_tracing_guid),
31         tracing_process_id_(base::trace_event::MemoryDumpManager::GetInstance()
32                                 ->GetTracingProcessId()) {}
33 
34   ~SkiaGpuTraceMemoryDump() override = default;
35 
36   // Overridden from SkTraceMemoryDump:
dumpNumericValue(const char * dump_name,const char * value_name,const char * units,uint64_t value)37   void dumpNumericValue(const char* dump_name,
38                         const char* value_name,
39                         const char* units,
40                         uint64_t value) override {
41     auto* dump = GetOrCreateAllocatorDump(dump_name);
42     dump->AddScalar(value_name, units, value);
43   }
dumpStringValue(const char * dump_name,const char * value_name,const char * value)44   void dumpStringValue(const char* dump_name,
45                        const char* value_name,
46                        const char* value) override {
47     auto* dump = GetOrCreateAllocatorDump(dump_name);
48     dump->AddString(value_name, "", value);
49   }
50 
setMemoryBacking(const char * dump_name,const char * backing_type,const char * backing_object_id)51   void setMemoryBacking(const char* dump_name,
52                         const char* backing_type,
53                         const char* backing_object_id) override {
54     // For uniformity, skia provides this value as a string. Convert back to a
55     // uint32_t.
56     uint32_t gl_id =
57         std::strtoul(backing_object_id, nullptr /* str_end */, 10 /* base */);
58 
59     // Constants used by SkiaGpuTraceMemoryDump to identify different memory
60     // types.
61     const char* kGLTextureBackingType = "gl_texture";
62     const char* kGLBufferBackingType = "gl_buffer";
63     const char* kGLRenderbufferBackingType = "gl_renderbuffer";
64 
65     // Populated in if statements below.
66     base::trace_event::MemoryAllocatorDumpGuid guid;
67 
68     if (share_group_tracing_guid_) {
69       // If we have a |share_group_tracing_guid_|, we are in a render process
70       // and need to create client texture GUIDs for aliasing with the GPU
71       // process.
72       if (strcmp(backing_type, kGLTextureBackingType) == 0) {
73         guid = gl::GetGLTextureClientGUIDForTracing(*share_group_tracing_guid_,
74                                                     gl_id);
75       } else if (strcmp(backing_type, kGLBufferBackingType) == 0) {
76         guid = gl::GetGLBufferGUIDForTracing(tracing_process_id_, gl_id);
77       } else if (strcmp(backing_type, kGLRenderbufferBackingType) == 0) {
78         guid = gl::GetGLRenderbufferGUIDForTracing(tracing_process_id_, gl_id);
79       }
80     } else {
81       // If we do not have a |share_group_tracing_guid_|, we are in the GPU
82       // process, being used for OOP-R. We need to create Raster dumps for
83       // aliasing with the transfer cache. Note that this is currently only
84       // needed for textures (not buffers or renderbuffers).
85       if (strcmp(backing_type, kGLTextureBackingType) == 0) {
86         guid = gl::GetGLTextureRasterGUIDForTracing(gl_id);
87       }
88     }
89 
90     if (!guid.empty()) {
91       pmd_->CreateSharedGlobalAllocatorDump(guid);
92 
93       auto* dump = GetOrCreateAllocatorDump(dump_name);
94 
95       const int kImportance = 2;
96       pmd_->AddOwnershipEdge(dump->guid(), guid, kImportance);
97     }
98   }
99 
setDiscardableMemoryBacking(const char * dump_name,const SkDiscardableMemory & discardable_memory_object)100   void setDiscardableMemoryBacking(
101       const char* dump_name,
102       const SkDiscardableMemory& discardable_memory_object) override {
103     // We don't use this class for dumping discardable memory.
104     NOTREACHED();
105   }
106 
getRequestedDetails() const107   LevelOfDetail getRequestedDetails() const override {
108     // TODO(ssid): Use MemoryDumpArgs to create light dumps when requested
109     // (crbug.com/499731).
110     return kObjectsBreakdowns_LevelOfDetail;
111   }
112 
shouldDumpWrappedObjects() const113   bool shouldDumpWrappedObjects() const override {
114     // Chrome already dumps objects it imports into Skia. Avoid duplicate dumps
115     // by asking Skia not to dump them.
116     return false;
117   }
118 
119  private:
120   // Helper to create allocator dumps.
GetOrCreateAllocatorDump(const char * dump_name)121   base::trace_event::MemoryAllocatorDump* GetOrCreateAllocatorDump(
122       const char* dump_name) {
123     auto* dump = pmd_->GetAllocatorDump(dump_name);
124     if (!dump)
125       dump = pmd_->CreateAllocatorDump(dump_name);
126     return dump;
127   }
128 
129   base::trace_event::ProcessMemoryDump* pmd_;
130   base::Optional<uint64_t> share_group_tracing_guid_;
131   uint64_t tracing_process_id_;
132 
133   DISALLOW_COPY_AND_ASSIGN(SkiaGpuTraceMemoryDump);
134 };
135 
136 }  // namespace
137 
DumpGrMemoryStatistics(const GrDirectContext * context,base::trace_event::ProcessMemoryDump * pmd,base::Optional<uint64_t> tracing_guid)138 void DumpGrMemoryStatistics(const GrDirectContext* context,
139                             base::trace_event::ProcessMemoryDump* pmd,
140                             base::Optional<uint64_t> tracing_guid) {
141   SkiaGpuTraceMemoryDump trace_memory_dump(pmd, tracing_guid);
142   context->dumpMemoryStatistics(&trace_memory_dump);
143 }
144 
DumpBackgroundGrMemoryStatistics(const GrDirectContext * context,base::trace_event::ProcessMemoryDump * pmd)145 void DumpBackgroundGrMemoryStatistics(
146     const GrDirectContext* context,
147     base::trace_event::ProcessMemoryDump* pmd) {
148   using base::trace_event::MemoryAllocatorDump;
149 
150   size_t skia_gr_cache_size;
151   context->getResourceCacheUsage(nullptr /* resourceCount */,
152                                  &skia_gr_cache_size);
153   std::string dump_name =
154       base::StringPrintf("skia/gpu_resources/context_0x%" PRIXPTR,
155                          reinterpret_cast<uintptr_t>(context));
156   MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_name);
157   dump->AddScalar(MemoryAllocatorDump::kNameSize,
158                   MemoryAllocatorDump::kUnitsBytes, skia_gr_cache_size);
159 }
160 
161 }  // namespace raster
162 }  // namespace gpu
163