| // Copyright 2018 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "gpu/command_buffer/common/skia_utils.h" | |
| #include "base/system/sys_info.h" | |
| #include "base/trace_event/memory_dump_manager.h" | |
| #include "base/trace_event/process_memory_dump.h" | |
| #include "build/build_config.h" | |
| #include "third_party/skia/include/core/SkTraceMemoryDump.h" | |
| #include "third_party/skia/include/gpu/GrContext.h" | |
| #include "ui/gl/trace_util.h" | |
| namespace gpu { | |
| namespace raster { | |
| namespace { | |
| // Derives from SkTraceMemoryDump and implements graphics specific memory | |
| // backing functionality. | |
| class SkiaGpuTraceMemoryDump : public SkTraceMemoryDump { | |
| public: | |
| // This should never outlive the provided ProcessMemoryDump, as it should | |
| // always be scoped to a single OnMemoryDump funciton call. | |
| SkiaGpuTraceMemoryDump(base::trace_event::ProcessMemoryDump* pmd, | |
| base::Optional<uint64_t> share_group_tracing_guid) | |
| : pmd_(pmd), | |
| share_group_tracing_guid_(share_group_tracing_guid), | |
| tracing_process_id_(base::trace_event::MemoryDumpManager::GetInstance() | |
| ->GetTracingProcessId()) {} | |
| ~SkiaGpuTraceMemoryDump() override = default; | |
| // Overridden from SkTraceMemoryDump: | |
| void dumpNumericValue(const char* dump_name, | |
| const char* value_name, | |
| const char* units, | |
| uint64_t value) override { | |
| auto* dump = GetOrCreateAllocatorDump(dump_name); | |
| dump->AddScalar(value_name, units, value); | |
| } | |
| void setMemoryBacking(const char* dump_name, | |
| const char* backing_type, | |
| const char* backing_object_id) override { | |
| // For uniformity, skia provides this value as a string. Convert back to a | |
| // uint32_t. | |
| uint32_t gl_id = | |
| std::strtoul(backing_object_id, nullptr /* str_end */, 10 /* base */); | |
| // Constants used by SkiaGpuTraceMemoryDump to identify different memory | |
| // types. | |
| const char* kGLTextureBackingType = "gl_texture"; | |
| const char* kGLBufferBackingType = "gl_buffer"; | |
| const char* kGLRenderbufferBackingType = "gl_renderbuffer"; | |
| // Populated in if statements below. | |
| base::trace_event::MemoryAllocatorDumpGuid guid; | |
| if (share_group_tracing_guid_) { | |
| // If we have a |share_group_tracing_guid_|, we are in a render process | |
| // and need to create client texture GUIDs for aliasing with the GPU | |
| // process. | |
| if (strcmp(backing_type, kGLTextureBackingType) == 0) { | |
| guid = gl::GetGLTextureClientGUIDForTracing(*share_group_tracing_guid_, | |
| gl_id); | |
| } else if (strcmp(backing_type, kGLBufferBackingType) == 0) { | |
| guid = gl::GetGLBufferGUIDForTracing(tracing_process_id_, gl_id); | |
| } else if (strcmp(backing_type, kGLRenderbufferBackingType) == 0) { | |
| guid = gl::GetGLRenderbufferGUIDForTracing(tracing_process_id_, gl_id); | |
| } | |
| } else { | |
| // If we do not have a |share_group_tracing_guid_|, we are in the GPU | |
| // process, being used for OOP-R. We need to create Raster dumps for | |
| // aliasing with the transfer cache. Note that this is currently only | |
| // needed for textures (not buffers or renderbuffers). | |
| if (strcmp(backing_type, kGLTextureBackingType) == 0) { | |
| guid = gl::GetGLTextureRasterGUIDForTracing(gl_id); | |
| } | |
| } | |
| if (!guid.empty()) { | |
| pmd_->CreateSharedGlobalAllocatorDump(guid); | |
| auto* dump = GetOrCreateAllocatorDump(dump_name); | |
| const int kImportance = 2; | |
| pmd_->AddOwnershipEdge(dump->guid(), guid, kImportance); | |
| } | |
| } | |
| void setDiscardableMemoryBacking( | |
| const char* dump_name, | |
| const SkDiscardableMemory& discardable_memory_object) override { | |
| // We don't use this class for dumping discardable memory. | |
| NOTREACHED(); | |
| } | |
| LevelOfDetail getRequestedDetails() const override { | |
| // TODO(ssid): Use MemoryDumpArgs to create light dumps when requested | |
| // (crbug.com/499731). | |
| return kObjectsBreakdowns_LevelOfDetail; | |
| } | |
| bool shouldDumpWrappedObjects() const override { | |
| // Chrome already dumps objects it imports into Skia. Avoid duplicate dumps | |
| // by asking Skia not to dump them. | |
| return false; | |
| } | |
| private: | |
| // Helper to create allocator dumps. | |
| base::trace_event::MemoryAllocatorDump* GetOrCreateAllocatorDump( | |
| const char* dump_name) { | |
| auto* dump = pmd_->GetAllocatorDump(dump_name); | |
| if (!dump) | |
| dump = pmd_->CreateAllocatorDump(dump_name); | |
| return dump; | |
| } | |
| base::trace_event::ProcessMemoryDump* pmd_; | |
| base::Optional<uint64_t> share_group_tracing_guid_; | |
| uint64_t tracing_process_id_; | |
| DISALLOW_COPY_AND_ASSIGN(SkiaGpuTraceMemoryDump); | |
| }; | |
| } // namespace | |
| void DetermineGrCacheLimitsFromAvailableMemory( | |
| size_t* max_resource_cache_bytes, | |
| size_t* max_glyph_cache_texture_bytes) { | |
| // Default limits. | |
| constexpr size_t kMaxGaneshResourceCacheBytes = 96 * 1024 * 1024; | |
| constexpr size_t kMaxDefaultGlyphCacheTextureBytes = 2048 * 1024 * 4; | |
| *max_resource_cache_bytes = kMaxGaneshResourceCacheBytes; | |
| *max_glyph_cache_texture_bytes = kMaxDefaultGlyphCacheTextureBytes; | |
| // We can't call AmountOfPhysicalMemory under NACL, so leave the default. | |
| #if !defined(OS_NACL) | |
| // The limit of the bytes allocated toward GPU resources in the GrContext's | |
| // GPU cache. | |
| constexpr size_t kMaxLowEndGaneshResourceCacheBytes = 48 * 1024 * 1024; | |
| constexpr size_t kMaxHighEndGaneshResourceCacheBytes = 256 * 1024 * 1024; | |
| // Limits for glyph cache textures. | |
| constexpr size_t kMaxLowEndGlyphCacheTextureBytes = 1024 * 512 * 4; | |
| // High-end / low-end memory cutoffs. | |
| constexpr int64_t kHighEndMemoryThreshold = (int64_t)4096 * 1024 * 1024; | |
| constexpr int64_t kLowEndMemoryThreshold = (int64_t)512 * 1024 * 1024; | |
| int64_t amount_of_physical_memory = base::SysInfo::AmountOfPhysicalMemory(); | |
| if (amount_of_physical_memory <= kLowEndMemoryThreshold) { | |
| *max_resource_cache_bytes = kMaxLowEndGaneshResourceCacheBytes; | |
| *max_glyph_cache_texture_bytes = kMaxLowEndGlyphCacheTextureBytes; | |
| } else if (amount_of_physical_memory >= kHighEndMemoryThreshold) { | |
| *max_resource_cache_bytes = kMaxHighEndGaneshResourceCacheBytes; | |
| } | |
| #endif | |
| } | |
| void DefaultGrCacheLimitsForTests(size_t* max_resource_cache_bytes, | |
| size_t* max_glyph_cache_texture_bytes) { | |
| constexpr size_t kDefaultGlyphCacheTextureBytes = 2048 * 1024 * 4; | |
| constexpr size_t kDefaultGaneshResourceCacheBytes = 96 * 1024 * 1024; | |
| *max_resource_cache_bytes = kDefaultGaneshResourceCacheBytes; | |
| *max_glyph_cache_texture_bytes = kDefaultGlyphCacheTextureBytes; | |
| } | |
| void DumpGrMemoryStatistics(const GrContext* context, | |
| base::trace_event::ProcessMemoryDump* pmd, | |
| base::Optional<uint64_t> tracing_guid) { | |
| SkiaGpuTraceMemoryDump trace_memory_dump(pmd, tracing_guid); | |
| context->dumpMemoryStatistics(&trace_memory_dump); | |
| } | |
| } // namespace raster | |
| } // namespace gpu |