blob: e66c6d50f9f94c26c670a7890c1b2e42bd4fc7b7 [file] [log] [blame]
// 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, &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(base::as_byte_span(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