| // Copyright 2018 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "gpu/command_buffer/service/shared_image/shared_image_manager.h" | |
| #include <inttypes.h> | |
| #include <cstdint> | |
| #include <memory> | |
| #include <utility> | |
| #include "base/debug/crash_logging.h" | |
| #include "base/debug/dump_without_crashing.h" | |
| #include "base/logging.h" | |
| #include "base/memory/stack_allocated.h" | |
| #include "base/metrics/histogram_macros.h" | |
| #include "base/strings/stringprintf.h" | |
| #include "base/task/single_thread_task_runner.h" | |
| #include "base/trace_event/memory_dump_manager.h" | |
| #include "base/trace_event/process_memory_dump.h" | |
| #include "base/trace_event/trace_event.h" | |
| #include "build/build_config.h" | |
| #include "components/viz/common/resources/shared_image_format_utils.h" | |
| #include "gpu/command_buffer/common/shared_image_trace_utils.h" | |
| #include "gpu/command_buffer/common/shared_image_usage.h" | |
| #include "gpu/command_buffer/service/shared_context_state.h" | |
| #include "gpu/command_buffer/service/shared_image/shared_image_representation.h" | |
| #include "ui/gl/trace_util.h" | |
| #if BUILDFLAG(IS_WIN) | |
| #include "gpu/command_buffer/service/dxgi_shared_handle_manager.h" | |
| #include "ui/gfx/win/d3d_shared_fence.h" | |
| #include "ui/gl/direct_composition_support.h" | |
| #include "ui/gl/gl_angle_util_win.h" | |
| #endif | |
| #if BUILDFLAG(IS_OZONE) | |
| #include "gpu/command_buffer/service/vulkan_context_provider.h" | |
| #include "gpu/config/gpu_finch_features.h" | |
| #include "ui/ozone/public/ozone_platform.h" | |
| #include "ui/ozone/public/surface_factory_ozone.h" | |
| #endif | |
| #if DCHECK_IS_ON() | |
| #define CALLED_ON_VALID_THREAD() \ | |
| do { \ | |
| if (!this->is_thread_safe()) \ | |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); \ | |
| } while (false) | |
| #else | |
| #define CALLED_ON_VALID_THREAD() | |
| #endif | |
| namespace gpu { | |
| namespace { | |
| // `DCHECKS` and dumps without crashing that `backing`'s usage overlaps with | |
| // `usage`. | |
| void EnforceSharedImageUsage(const SharedImageBacking* backing, | |
| SharedImageUsageSet usage) { | |
| if (!backing->usage().HasAny(usage)) { | |
| SCOPED_CRASH_KEY_STRING32("SharedImageUsage", "debug_label", | |
| backing->debug_label()); | |
| SCOPED_CRASH_KEY_STRING32("SharedImageUsage", "name", backing->GetName()); | |
| SCOPED_CRASH_KEY_NUMBER("SharedImageUsage", "required_usage", | |
| static_cast<uint32_t>(usage)); | |
| SCOPED_CRASH_KEY_NUMBER("SharedImageUsage", "actual_usage", | |
| static_cast<uint32_t>(backing->usage())); | |
| base::debug::DumpWithoutCrashing(); | |
| } | |
| } | |
| } // namespace | |
| class SCOPED_LOCKABLE SharedImageManager::AutoLock { | |
| STACK_ALLOCATED(); | |
| public: | |
| explicit AutoLock(SharedImageManager* manager) | |
| EXCLUSIVE_LOCK_FUNCTION(manager->lock_) | |
| : auto_lock_(manager->is_thread_safe() ? &manager->lock_.value() | |
| : nullptr) {} | |
| AutoLock(const AutoLock&) = delete; | |
| AutoLock& operator=(const AutoLock&) = delete; | |
| ~AutoLock() UNLOCK_FUNCTION() = default; | |
| private: | |
| base::AutoLockMaybe auto_lock_; | |
| }; | |
| SharedImageManager::SharedImageManager( | |
| bool thread_safe, | |
| bool display_context_on_another_thread, | |
| VulkanContextProvider* vulkan_context_provider, | |
| scoped_refptr<base::SingleThreadTaskRunner> io_runner) | |
| : display_context_on_another_thread_(display_context_on_another_thread) | |
| #if BUILDFLAG(IS_WIN) | |
| , | |
| dxgi_shared_handle_manager_( | |
| base::MakeRefCounted<DXGISharedHandleManager>()) | |
| #endif | |
| #if BUILDFLAG(IS_OZONE) | |
| , | |
| vulkan_context_provider_(vulkan_context_provider) | |
| #endif | |
| #if BUILDFLAG(IS_WIN) | |
| , | |
| io_runner_(std::move(io_runner)) | |
| #endif | |
| { | |
| DCHECK(!display_context_on_another_thread || thread_safe); | |
| if (thread_safe) { | |
| lock_.emplace(); | |
| } | |
| CALLED_ON_VALID_THREAD(); | |
| // In tests there might not be a SingleThreadTaskRunner for this thread. | |
| if (base::SingleThreadTaskRunner::HasCurrentDefault()) { | |
| is_registered_as_memory_dump_provider_ = true; | |
| base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( | |
| this, "SharedImageManager", | |
| base::SingleThreadTaskRunner::GetCurrentDefault()); | |
| } | |
| } | |
| SharedImageManager::~SharedImageManager() { | |
| CALLED_ON_VALID_THREAD(); | |
| #if DCHECK_IS_ON() | |
| AutoLock auto_lock(this); | |
| #endif | |
| DCHECK(images_.empty()); | |
| if (is_registered_as_memory_dump_provider_) { | |
| base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( | |
| this); | |
| } | |
| } | |
| std::unique_ptr<SharedImageRepresentationFactoryRef> | |
| SharedImageManager::Register(std::unique_ptr<SharedImageBacking> backing, | |
| MemoryTypeTracker* tracker) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| if (images_.contains(backing->mailbox())) { | |
| LOG(ERROR) << "SharedImageManager::Register: Trying to register an " | |
| "already registered mailbox."; | |
| backing->MarkForDestruction(); | |
| return nullptr; | |
| } | |
| // Log UMA only for standalone backings created outside SI Factory. | |
| // CompoundImageBacking logs UMA for its own constituent elements when | |
| // created. | |
| if (backing->GetType() != SharedImageBackingType::kCompound) { | |
| UMA_HISTOGRAM_ENUMERATION("GPU.SharedImage.BackingType", | |
| backing->GetType()); | |
| } | |
| UMA_HISTOGRAM_ENUMERATION("GPU.SharedImage.SharedImageFormat", | |
| viz::GetSharedImageFormatUMA(backing->format())); | |
| // TODO(jonross): Determine how the direct destruction of a | |
| // SharedImageRepresentationFactoryRef leads to ref-counting issues as | |
| // well as thread-checking failures in tests. | |
| auto factory_ref = std::make_unique<SharedImageRepresentationFactoryRef>( | |
| this, backing.get(), tracker, /*is_primary=*/true); | |
| gpu::Mailbox mailbox = backing->mailbox(); | |
| images_.emplace(std::move(mailbox), std::move(backing)); | |
| return factory_ref; | |
| } | |
| SharedImageBacking* SharedImageManager::GetBacking( | |
| const Mailbox& mailbox) const { | |
| CALLED_ON_VALID_THREAD(); | |
| auto it = images_.find(mailbox); | |
| return it != images_.end() ? it->second.get() : nullptr; | |
| } | |
| std::unique_ptr<SharedImageRepresentationFactoryRef> | |
| SharedImageManager::AddSecondaryReference(const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::AddSecondaryReference: Trying to add " | |
| "reference to non-existent mailbox."; | |
| return nullptr; | |
| } | |
| return std::make_unique<SharedImageRepresentationFactoryRef>( | |
| this, backing, tracker, /*is_primary=*/false); | |
| } | |
| std::unique_ptr<GLTextureImageRepresentation> | |
| SharedImageManager::ProduceGLTexture(const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::ProduceGLTexture: Trying to produce a " | |
| "representation from a non-existent mailbox. " | |
| << mailbox.ToDebugString(); | |
| return nullptr; | |
| } | |
| auto representation = backing->ProduceGLTexture(this, tracker); | |
| if (!representation) { | |
| LOG(ERROR) << "SharedImageManager::ProduceGLTexture: Trying to produce a " | |
| "representation from an incompatible backing: " | |
| << backing->GetName(); | |
| return nullptr; | |
| } | |
| return representation; | |
| } | |
| std::unique_ptr<GLTexturePassthroughImageRepresentation> | |
| SharedImageManager::ProduceGLTexturePassthrough(const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::ProduceGLTexturePassthrough: Trying to " | |
| "produce a representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| auto representation = backing->ProduceGLTexturePassthrough(this, tracker); | |
| if (!representation) { | |
| LOG(ERROR) << "SharedImageManager::ProduceGLTexturePassthrough: Trying to " | |
| "produce a representation from an incompatible backing: " | |
| << backing->GetName(); | |
| return nullptr; | |
| } | |
| return representation; | |
| } | |
| std::unique_ptr<SkiaImageRepresentation> SharedImageManager::ProduceSkia( | |
| const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker, | |
| scoped_refptr<SharedContextState> context_state, | |
| SharedImageUsageSet required_usages) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::ProduceSkia: Trying to Produce a " | |
| "Skia representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| // Required usages must be verified before creating the representation to | |
| // avoid potentially creating a representation on the wrong thread. | |
| if (!required_usages.empty() && !backing->usage().HasAll(required_usages)) { | |
| LOG(ERROR) << "SharedImageManager::ProduceSkia: Trying to Produce a " | |
| "Skia representation from backing without required usages."; | |
| return nullptr; | |
| } | |
| auto representation = backing->ProduceSkia(this, tracker, context_state); | |
| if (!representation) { | |
| LOG(ERROR) << "SharedImageManager::ProduceSkia: Trying to produce a " | |
| "Skia representation from an incompatible backing: " | |
| << backing->GetName(); | |
| return nullptr; | |
| } | |
| return representation; | |
| } | |
| std::unique_ptr<DawnImageRepresentation> SharedImageManager::ProduceDawn( | |
| const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker, | |
| const wgpu::Device& device, | |
| wgpu::BackendType backend_type, | |
| std::vector<wgpu::TextureFormat> view_formats, | |
| scoped_refptr<SharedContextState> context_state) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::ProduceDawn: Trying to Produce a " | |
| "Dawn representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| EnforceSharedImageUsage(backing, {SHARED_IMAGE_USAGE_WEBGPU_READ, | |
| SHARED_IMAGE_USAGE_WEBGPU_WRITE}); | |
| auto representation = | |
| backing->ProduceDawn(this, tracker, device, backend_type, | |
| std::move(view_formats), context_state); | |
| if (!representation) { | |
| LOG(ERROR) << "SharedImageManager::ProduceDawn: Trying to produce a " | |
| "Dawn representation from an incompatible backing: " | |
| << backing->GetName(); | |
| return nullptr; | |
| } | |
| return representation; | |
| } | |
| std::unique_ptr<DawnBufferRepresentation> SharedImageManager::ProduceDawnBuffer( | |
| const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker, | |
| const wgpu::Device& device, | |
| wgpu::BackendType backend_type, | |
| scoped_refptr<SharedContextState> context_state) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::ProduceDawnBuffer: Trying to produce a " | |
| "Dawn buffer representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| auto representation = backing->ProduceDawnBuffer(this, tracker, device, | |
| backend_type, context_state); | |
| if (!representation) { | |
| LOG(ERROR) << "SharedImageManager::ProduceDawnBuffer: Trying to produce a " | |
| "Dawn buffer representation from an incompatible backing: " | |
| << backing->GetName(); | |
| return nullptr; | |
| } | |
| return representation; | |
| } | |
| std::unique_ptr<WebNNTensorRepresentation> | |
| SharedImageManager::ProduceWebNNTensor(const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| SharedImageBacking* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::ProduceWebNNTensor: Trying to produce a " | |
| "WebNN tensor representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| std::unique_ptr<WebNNTensorRepresentation> representation = | |
| backing->ProduceWebNNTensor(this, tracker); | |
| if (!representation) { | |
| LOG(ERROR) << "SharedImageManager::ProduceWebNNTensor: Trying to produce a " | |
| "WebNN tensor representation from an incompatible backing: " | |
| << backing->GetName(); | |
| return nullptr; | |
| } | |
| return representation; | |
| } | |
| std::unique_ptr<OverlayImageRepresentation> SharedImageManager::ProduceOverlay( | |
| const gpu::Mailbox& mailbox, | |
| gpu::MemoryTypeTracker* tracker) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::ProduceOverlay: Trying to Produce a " | |
| "Overlay representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| EnforceSharedImageUsage(backing, {SHARED_IMAGE_USAGE_SCANOUT}); | |
| auto representation = backing->ProduceOverlay(this, tracker); | |
| if (!representation) { | |
| LOG(ERROR) << "SharedImageManager::ProduceOverlay: Trying to produce a " | |
| "Overlay representation from an incompatible backing: " | |
| << backing->GetName(); | |
| return nullptr; | |
| } | |
| return representation; | |
| } | |
| std::unique_ptr<MemoryImageRepresentation> SharedImageManager::ProduceMemory( | |
| const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::ProduceMemory: Trying to Produce a " | |
| "Memory representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| // This is expected to fail based on the SharedImageBacking type, so don't log | |
| // error here. Caller is expected to handle nullptr. | |
| return backing->ProduceMemory(this, tracker); | |
| } | |
| std::unique_ptr<RasterImageRepresentation> SharedImageManager::ProduceRaster( | |
| const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::ProduceRaster: Trying to Produce a " | |
| "Raster representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| // TODO(b/349290188): Add back this enforcement when we plan on shipping | |
| // RawDraw. | |
| // EnforceSharedImageUsage(backing, {SHARED_IMAGE_USAGE_RAW_DRAW}); | |
| // This is expected to fail based on the SharedImageBacking type, so don't log | |
| // error here. Caller is expected to handle nullptr. | |
| return backing->ProduceRaster(this, tracker); | |
| } | |
| std::unique_ptr<VideoImageRepresentation> SharedImageManager::ProduceVideo( | |
| VideoDevice device, | |
| const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) | |
| << "SharedImageManager::ProduceVideoDecode: Trying to Produce a D3D" | |
| "representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| // This is expected to fail based on the SharedImageBacking type, so don't log | |
| // error here. Caller is expected to handle nullptr. | |
| return backing->ProduceVideo(this, tracker, device); | |
| } | |
| #if BUILDFLAG(ENABLE_VULKAN) | |
| std::unique_ptr<VulkanImageRepresentation> SharedImageManager::ProduceVulkan( | |
| const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker, | |
| gpu::VulkanDeviceQueue* vulkan_device_queue, | |
| gpu::VulkanImplementation& vulkan_impl, | |
| bool needs_detiling) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) | |
| << "SharedImageManager::ProduceVulkanImage: Trying to produce vulkan" | |
| "representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| return backing->ProduceVulkan(this, tracker, vulkan_device_queue, vulkan_impl, | |
| needs_detiling); | |
| } | |
| #endif | |
| #if BUILDFLAG(IS_ANDROID) | |
| std::unique_ptr<LegacyOverlayImageRepresentation> | |
| SharedImageManager::ProduceLegacyOverlay(const Mailbox& mailbox, | |
| MemoryTypeTracker* tracker) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) | |
| << "SharedImageManager::ProduceLegacyOverlay: Trying to Produce a " | |
| "Legacy Overlay representation from a non-existent mailbox."; | |
| return nullptr; | |
| } | |
| EnforceSharedImageUsage(backing, {SHARED_IMAGE_USAGE_SCANOUT}); | |
| auto representation = backing->ProduceLegacyOverlay(this, tracker); | |
| if (!representation) { | |
| LOG(ERROR) | |
| << "SharedImageManager::ProduceLegacyOverlay: Trying to produce a " | |
| "Legacy Overlay representation from an incompatible backing: " | |
| << backing->GetName(); | |
| return nullptr; | |
| } | |
| return representation; | |
| } | |
| #endif | |
| #if BUILDFLAG(IS_WIN) | |
| void SharedImageManager::UpdateExternalFence( | |
| const Mailbox& mailbox, | |
| scoped_refptr<gfx::D3DSharedFence> external_fence) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) | |
| << "SharedImageManager::ProduceVideoDecode: Trying to Produce a D3D" | |
| "representation from a non-existent mailbox."; | |
| return; | |
| } | |
| backing->UpdateExternalFence(std::move(external_fence)); | |
| } | |
| #endif | |
| std::optional<SharedImageUsageSet> SharedImageManager::GetUsageForMailbox( | |
| const Mailbox& mailbox) { | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| return backing ? std::make_optional(backing->usage()) : std::nullopt; | |
| } | |
| void SharedImageManager::OnRepresentationDestroyed( | |
| const Mailbox& mailbox, | |
| SharedImageRepresentation* representation) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| { | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::OnRepresentationDestroyed: Trying to " | |
| "destroy a non existent mailbox."; | |
| return; | |
| } | |
| // TODO(piman): When the original (factory) representation is destroyed, we | |
| // should treat the backing as pending destruction and prevent additional | |
| // representations from being created. This will help avoid races due to a | |
| // consumer getting lucky with timing due to a representation inadvertently | |
| // extending a backing's lifetime. | |
| backing->ReleaseRef(representation); | |
| } | |
| { | |
| // TODO(jonross): Once the pending destruction TODO above is addressed then | |
| // this block can be removed, and the deletion can occur directly. Currently | |
| // SharedImageManager::OnRepresentationDestroyed can be nested, so we need | |
| // to get the iterator again. | |
| auto it = images_.find(mailbox); | |
| if (it != images_.end() && !it->second->HasAnyRefs()) { | |
| images_.erase(it); | |
| } | |
| } | |
| } | |
| bool SharedImageManager::UpdateSharedImage(const Mailbox& mailbox, | |
| gfx::GpuFenceHandle in_fence) { | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) | |
| << "SharedImageManager::UpdateSharedImage: Non-existent mailbox."; | |
| return false; | |
| } | |
| backing->Update(std::move(in_fence)); | |
| return true; | |
| } | |
| void SharedImageManager::SetPurgeable(const Mailbox& mailbox, bool purgeable) { | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| if (!backing) { | |
| LOG(ERROR) << "SharedImageManager::SetPurgeable: Non-existent mailbox."; | |
| return; | |
| } | |
| backing->SetPurgeable(purgeable); | |
| } | |
| bool SharedImageManager::OnMemoryDump( | |
| const base::trace_event::MemoryDumpArgs& args, | |
| base::trace_event::ProcessMemoryDump* pmd) { | |
| CALLED_ON_VALID_THREAD(); | |
| AutoLock autolock(this); | |
| const char* base_dump_name = "gpu/shared_images"; | |
| if (args.level_of_detail == | |
| base::trace_event::MemoryDumpLevelOfDetail::kBackground) { | |
| size_t total_size = 0; | |
| size_t total_purgeable_size = 0; | |
| size_t total_non_exo_size = 0; | |
| for (auto& [_, backing] : images_) { | |
| size_t size = backing->GetEstimatedSizeForMemoryDump(); | |
| total_size += size; | |
| total_purgeable_size += backing->IsPurgeable() ? size : 0; | |
| total_non_exo_size += backing->IsImportedFromExo() ? 0 : size; | |
| } | |
| base::trace_event::MemoryAllocatorDump* dump = | |
| pmd->CreateAllocatorDump(base_dump_name); | |
| dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, | |
| base::trace_event::MemoryAllocatorDump::kUnitsBytes, | |
| total_size); | |
| dump->AddScalar("purgeable_size", | |
| base::trace_event::MemoryAllocatorDump::kUnitsBytes, | |
| total_purgeable_size); | |
| dump->AddScalar("non_exo_size", | |
| base::trace_event::MemoryAllocatorDump::kUnitsBytes, | |
| total_non_exo_size); | |
| // Early out, no need for more detail in a BACKGROUND dump. | |
| return true; | |
| } | |
| for (auto& [mailbox, backing] : images_) { | |
| auto* memory_tracker = backing->GetMemoryTracker(); | |
| // All the backings registered here should have a memory tracker. | |
| DCHECK(memory_tracker); | |
| // Unique name in the process. | |
| std::string dump_name = base::StringPrintf( | |
| "%s/client_0x%" PRIX32 "/mailbox_%s", base_dump_name, | |
| memory_tracker->ClientId(), mailbox.ToDebugString().c_str()); | |
| // GUID which expresses shared ownership with the client process. This must | |
| // match the client-side GUID for mailbox. | |
| auto client_guid = GetSharedImageGUIDForTracing(mailbox); | |
| // Backing will produce dump with relevant information along with ownership | |
| // edge to `client_guid`. | |
| backing->OnMemoryDump(dump_name, client_guid, pmd, | |
| memory_tracker->ClientTracingId()); | |
| } | |
| return true; | |
| } | |
| scoped_refptr<gfx::NativePixmap> SharedImageManager::GetNativePixmap( | |
| const gpu::Mailbox& mailbox) { | |
| AutoLock autolock(this); | |
| auto* backing = GetBacking(mailbox); | |
| return backing ? backing->GetNativePixmap() : nullptr; | |
| } | |
| bool SharedImageManager::SupportsScanoutImages() { | |
| #if BUILDFLAG(IS_APPLE) | |
| return true; | |
| #elif BUILDFLAG(IS_ANDROID) | |
| return true; | |
| #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA) | |
| return supports_overlays_on_ozone_; | |
| #elif BUILDFLAG(IS_WIN) | |
| return gl::DirectCompositionTextureSupported(); | |
| #else | |
| return false; | |
| #endif | |
| } | |
| void SharedImageManager::QueryMultiplanarTextureSamplingSupport() { | |
| #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA) | |
| auto* ozone_platform = ui::OzonePlatform::GetInstance(); | |
| auto* surface_factory = ozone_platform->GetSurfaceFactoryOzone(); | |
| supports_ycbcr_nv12_sampling_ = | |
| surface_factory->IsFormatSupportedForTexturing( | |
| viz::MultiPlaneFormat::kNV12) && | |
| ozone_platform->IsNativePixmapConfigSupported( | |
| viz::MultiPlaneFormat::kNV12, | |
| gfx::BufferUsage::GPU_READ_CPU_READ_WRITE); | |
| supports_ycbcr_p010_sampling_ = | |
| surface_factory->IsFormatSupportedForTexturing( | |
| viz::MultiPlaneFormat::kP010); | |
| is_texture_sampling_queried_ = true; | |
| #endif // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA) | |
| } | |
| bool SharedImageManager::SupportsNV12TextureSampling() { | |
| #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA) | |
| AutoLock autolock(this); | |
| if (!is_texture_sampling_queried_) { | |
| QueryMultiplanarTextureSamplingSupport(); | |
| } | |
| return supports_ycbcr_nv12_sampling_; | |
| #elif BUILDFLAG(IS_APPLE) | |
| return true; | |
| #else | |
| return false; | |
| #endif | |
| } | |
| bool SharedImageManager::SupportsP010TextureSampling() { | |
| #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA) | |
| AutoLock autolock(this); | |
| if (!is_texture_sampling_queried_) { | |
| QueryMultiplanarTextureSamplingSupport(); | |
| } | |
| return supports_ycbcr_p010_sampling_; | |
| #elif BUILDFLAG(IS_APPLE) | |
| return true; | |
| #else | |
| return false; | |
| #endif | |
| } | |
| } // namespace gpu |