blob: 0af4c49b00af369fad6b8e760985c68deca68a3b [file] [log] [blame]
// 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/client/client_font_manager.h"
#include <bit>
#include <type_traits>
#include "base/bits.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_span.h"
namespace gpu {
namespace raster {
namespace {
class Serializer {
public:
explicit Serializer(base::span<uint8_t> memory) : memory_(memory) {}
~Serializer() = default;
template <typename T>
void Write(const T& val) {
static_assert(std::is_trivially_copyable_v<T>);
WriteData(base::byte_span_from_ref(val), alignof(T));
}
void WriteData(base::span<const uint8_t> input, size_t alignment) {
AlignMemory(input.size(), alignment);
if (input.empty()) {
return;
}
memory_.take_first(input.size()).copy_from(input);
}
private:
void AlignMemory(uint32_t size, size_t alignment) {
// Due to the math below, alignment must be a power of two.
DCHECK(std::has_single_bit(alignment));
size_t memory = reinterpret_cast<size_t>(memory_.data());
size_t padding = base::bits::AlignUp(memory, alignment) - memory;
DCHECK_LE(size + padding, memory_.size());
memory_ = memory_.subspan(padding);
}
base::raw_span<uint8_t> memory_;
};
} // namespace
ClientFontManager::ClientFontManager(Client* client,
CommandBuffer* command_buffer)
: client_(client), command_buffer_(command_buffer), strike_server_(this) {}
ClientFontManager::~ClientFontManager() = default;
SkDiscardableHandleId ClientFontManager::createHandle() {
auto client_handle =
client_discardable_manager_.CreateHandle(command_buffer_);
if (client_handle.is_null())
return kInvalidSkDiscardableHandleId;
SkDiscardableHandleId handle_id = ++last_allocated_handle_id_;
discardable_handle_map_[handle_id] = client_handle;
// Handles start with a ref-count.
locked_handles_.insert(handle_id);
return handle_id;
}
bool ClientFontManager::lockHandle(SkDiscardableHandleId handle_id) {
// Already locked.
if (locked_handles_.find(handle_id) != locked_handles_.end())
return true;
auto it = discardable_handle_map_.find(handle_id);
if (it == discardable_handle_map_.end())
return false;
bool locked = client_discardable_manager_.LockHandle(it->second);
if (locked) {
locked_handles_.insert(handle_id);
return true;
}
discardable_handle_map_.erase(it);
return false;
}
bool ClientFontManager::isHandleDeleted(SkDiscardableHandleId handle_id) {
auto it = discardable_handle_map_.find(handle_id);
if (it == discardable_handle_map_.end())
return true;
if (client_discardable_manager_.HandleIsDeleted(it->second)) {
discardable_handle_map_.erase(it);
return true;
}
return false;
}
void ClientFontManager::Serialize() {
// TODO(khushalsagar): May be skia can track the size required so we avoid
// this copy.
std::vector<uint8_t> strike_data;
strike_server_.writeStrikeData(&strike_data);
const uint32_t num_handles_created =
last_allocated_handle_id_ - last_serialized_handle_id_;
if (strike_data.size() == 0u && num_handles_created == 0u &&
locked_handles_.size() == 0u) {
// No font data to serialize.
return;
}
// Size required for serialization.
base::CheckedNumeric<uint32_t> checked_bytes_required = 0;
// Skia data size.
checked_bytes_required += sizeof(uint32_t) + alignof(uint32_t) + 16;
checked_bytes_required += strike_data.size();
// num of handles created + SerializableHandles.
checked_bytes_required +=
sizeof(uint32_t) + alignof(uint32_t) + alignof(SerializableSkiaHandle);
checked_bytes_required +=
base::CheckMul(num_handles_created, sizeof(SerializableSkiaHandle));
// num of handles locked + DiscardableHandleIds.
checked_bytes_required +=
sizeof(uint32_t) + alignof(uint32_t) + alignof(SkDiscardableHandleId);
checked_bytes_required +=
base::CheckMul(locked_handles_.size(), sizeof(SkDiscardableHandleId));
uint32_t bytes_required = 0;
if (!checked_bytes_required.AssignIfValid(&bytes_required)) {
DLOG(FATAL) << "ClientFontManager::Serialize: font buffer overflow";
return;
}
// Allocate memory.
base::span<uint8_t> memory = client_->MapFontBuffer(bytes_required);
if (memory.empty()) {
// We are likely in a context loss situation if mapped memory allocation
// for font buffer failed.
return;
}
Serializer serializer(memory);
// Serialize all new handles.
serializer.Write<uint32_t>(num_handles_created);
for (SkDiscardableHandleId handle_id = last_serialized_handle_id_ + 1;
handle_id <= last_allocated_handle_id_; handle_id++) {
auto it = discardable_handle_map_.find(handle_id);
CHECK(it != discardable_handle_map_.end());
// We must have a valid |client_handle| here since all new handles are
// currently in locked state.
auto client_handle = client_discardable_manager_.GetHandle(it->second);
DCHECK(client_handle.IsValid());
SerializableSkiaHandle handle(handle_id, client_handle.shm_id(),
client_handle.byte_offset());
serializer.Write<SerializableSkiaHandle>(handle);
}
// Serialize all locked handle ids, so the raster unlocks them when done.
DCHECK(base::IsValueInRangeForNumericType<uint32_t>(locked_handles_.size()));
const uint32_t num_locked_handles = locked_handles_.size();
serializer.Write<uint32_t>(num_locked_handles);
for (auto handle_id : locked_handles_)
serializer.Write<SkDiscardableHandleId>(handle_id);
// Serialize skia data.
DCHECK(base::IsValueInRangeForNumericType<uint32_t>(strike_data.size()));
const uint32_t skia_data_size = strike_data.size();
serializer.Write<uint32_t>(skia_data_size);
serializer.WriteData(strike_data, 16);
// Reset all state for what has been serialized.
last_serialized_handle_id_ = last_allocated_handle_id_;
locked_handles_.clear();
return;
}
} // namespace raster
} // namespace gpu