| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" |
| |
| #include <stdint.h> |
| |
| #include <string> |
| #include <utility> |
| |
| #include "base/containers/contains.h" |
| #include "base/lazy_instance.h" |
| #include "base/memory/read_only_shared_memory_region.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/shared_memory_mapping.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/trace_event/process_memory_dump.h" |
| #include "components/viz/common/resources/bitmap_allocation.h" |
| #include "components/viz/common/resources/resource_sizes.h" |
| #include "mojo/public/cpp/system/platform_handle.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace viz { |
| |
| class BitmapData : public base::RefCounted<BitmapData> { |
| public: |
| BitmapData() = default; |
| BitmapData(const BitmapData& other) = delete; |
| BitmapData& operator=(const BitmapData& other) = delete; |
| |
| virtual const void* GetMemory() const = 0; |
| virtual size_t GetSize() const = 0; |
| virtual const base::UnguessableToken& GetGUID() const = 0; |
| |
| protected: |
| friend class base::RefCounted<BitmapData>; |
| virtual ~BitmapData() = default; |
| }; |
| |
| // Holds a bitmap stored in local memory. |
| class LocalBitmapData : public BitmapData { |
| public: |
| explicit LocalBitmapData(SkBitmap bitmap) |
| : bitmap_(std::move(bitmap)), guid_(base::UnguessableToken::Create()) {} |
| |
| const void* GetMemory() const override { return bitmap_.getPixels(); } |
| size_t GetSize() const override { return bitmap_.computeByteSize(); } |
| const base::UnguessableToken& GetGUID() const override { return guid_; } |
| |
| private: |
| ~LocalBitmapData() override = default; |
| |
| SkBitmap bitmap_; |
| // GUID to identify this bitmap in memory dumps. |
| base::UnguessableToken guid_; |
| }; |
| |
| // Holds a bitmap stored in shared memory. |
| class SharedMemoryBitmapData : public BitmapData { |
| public: |
| explicit SharedMemoryBitmapData(base::ReadOnlySharedMemoryMapping mapping) |
| : mapping_(std::move(mapping)) {} |
| |
| const void* GetMemory() const override { return mapping_.memory(); } |
| size_t GetSize() const override { return mapping_.size(); } |
| const base::UnguessableToken& GetGUID() const override { |
| return mapping_.guid(); |
| } |
| |
| private: |
| ~SharedMemoryBitmapData() override = default; |
| |
| base::ReadOnlySharedMemoryMapping mapping_; |
| }; |
| |
| namespace { |
| |
| // Holds a reference on the BitmapData so that the WritableSharedMemoryMapping |
| // can outlive the SharedBitmapId registration as long as this SharedBitmap |
| // object is held alive. |
| class ServerSharedBitmap : public SharedBitmap { |
| public: |
| // NOTE: bitmap_data->GetMemory() is read-only but SharedBitmap expects a |
| // uint8_t* pointer, even though all instances returned by a |
| // SharedBitmapManager will be used read-only. |
| explicit ServerSharedBitmap(scoped_refptr<BitmapData> bitmap_data) |
| : SharedBitmap( |
| static_cast<uint8_t*>(const_cast<void*>(bitmap_data->GetMemory()))), |
| bitmap_data_(std::move(bitmap_data)) {} |
| |
| ~ServerSharedBitmap() override { |
| // Drop unowned reference before destroying `bitmap_data_`. |
| pixels_ = nullptr; |
| } |
| |
| private: |
| scoped_refptr<BitmapData> bitmap_data_; |
| }; |
| |
| } // namespace |
| |
| ServerSharedBitmapManager::ServerSharedBitmapManager() = default; |
| |
| ServerSharedBitmapManager::~ServerSharedBitmapManager() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| DCHECK(handle_map_.empty()); |
| } |
| |
| std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::GetSharedBitmapFromId( |
| const gfx::Size& size, |
| SharedImageFormat format, |
| const SharedBitmapId& id) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| auto it = handle_map_.find(id); |
| if (it == handle_map_.end()) { |
| return nullptr; |
| } |
| |
| BitmapData* data = it->second.get(); |
| |
| size_t bitmap_size; |
| if (!ResourceSizes::MaybeSizeInBytes(size, format.resource_format(), |
| &bitmap_size) || |
| bitmap_size > data->GetSize()) { |
| return nullptr; |
| } |
| |
| if (!data->GetMemory()) { |
| return nullptr; |
| } |
| |
| return std::make_unique<ServerSharedBitmap>(data); |
| } |
| |
| base::UnguessableToken |
| ServerSharedBitmapManager::GetSharedBitmapTracingGUIDFromId( |
| const SharedBitmapId& id) { |
| auto it = handle_map_.find(id); |
| if (it == handle_map_.end()) |
| return {}; |
| BitmapData* data = it->second.get(); |
| return data->GetGUID(); |
| } |
| |
| bool ServerSharedBitmapManager::LocalAllocatedSharedBitmap( |
| SkBitmap bitmap, |
| const SharedBitmapId& id) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| DCHECK(!bitmap.drawsNothing()); |
| |
| // Duplicate ids are not allowed. |
| if (base::Contains(handle_map_, id)) |
| return false; |
| |
| handle_map_[id] = base::MakeRefCounted<LocalBitmapData>(std::move(bitmap)); |
| |
| return true; |
| } |
| |
| bool ServerSharedBitmapManager::ChildAllocatedSharedBitmap( |
| base::ReadOnlySharedMemoryMapping mapping, |
| const SharedBitmapId& id) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| // Duplicate ids are not allowed. |
| if (base::Contains(handle_map_, id)) |
| return false; |
| |
| // This function handles public API requests, so verify we unwrapped a shared |
| // memory handle before trying to use the handle. |
| if (!mapping.IsValid()) |
| return false; |
| |
| handle_map_[id] = |
| base::MakeRefCounted<SharedMemoryBitmapData>(std::move(mapping)); |
| |
| // Note: |region| will be destroyed at scope exit, releasing the fd. |
| return true; |
| } |
| |
| void ServerSharedBitmapManager::ChildDeletedSharedBitmap( |
| const SharedBitmapId& id) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| handle_map_.erase(id); |
| } |
| |
| bool ServerSharedBitmapManager::OnMemoryDump( |
| const base::trace_event::MemoryDumpArgs& args, |
| base::trace_event::ProcessMemoryDump* pmd) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| for (const auto& pair : handle_map_) { |
| const SharedBitmapId& id = pair.first; |
| BitmapData* data = pair.second.get(); |
| |
| std::string dump_str = base::StringPrintf( |
| "sharedbitmap/%s", base::HexEncode(id.name, sizeof(id.name)).c_str()); |
| base::trace_event::MemoryAllocatorDump* dump = |
| pmd->CreateAllocatorDump(dump_str); |
| if (!dump) |
| return false; |
| |
| dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
| base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| data->GetSize()); |
| |
| // This GUID is the same returned by GetSharedBitmapTracingGUIDFromId() so |
| // other components use a consistent GUID for a given SharedBitmapId. |
| base::UnguessableToken bitmap_guid = data->GetGUID(); |
| DCHECK(!bitmap_guid.is_empty()); |
| pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), bitmap_guid, |
| /*importance=*/0); |
| } |
| |
| return true; |
| } |
| |
| } // namespace viz |