blob: 6dc6f269cdb30383665476571bbc381489ca0704 [file] [log] [blame]
// Copyright (c) 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/client/client_font_manager.h"
namespace gpu {
namespace raster {
namespace {
class Serializer {
public:
Serializer(char* memory, uint32_t memory_size)
: memory_(memory), memory_size_(memory_size) {}
~Serializer() = default;
template <typename T>
void Write(const T* val) {
static_assert(base::is_trivially_copyable<T>::value, "");
WriteData(val, sizeof(T), alignof(T));
}
void WriteData(const void* input, uint32_t bytes, size_t alignment) {
AlignMemory(bytes, alignment);
if (bytes == 0)
return;
memcpy(memory_, input, bytes);
memory_ += bytes;
bytes_written_ += bytes;
}
private:
void AlignMemory(uint32_t size, size_t alignment) {
// Due to the math below, alignment must be a power of two.
DCHECK_GT(alignment, 0u);
DCHECK_EQ(alignment & (alignment - 1), 0u);
uintptr_t memory = reinterpret_cast<uintptr_t>(memory_);
size_t padding = ((memory + alignment - 1) & ~(alignment - 1)) - memory;
DCHECK_LE(bytes_written_ + size + padding, memory_size_);
memory_ += padding;
bytes_written_ += padding;
}
char* memory_ = nullptr;
uint32_t memory_size_ = 0u;
uint32_t bytes_written_ = 0u;
};
} // 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.
void* memory = client_->MapFontBuffer(bytes_required);
if (!memory) {
// We are likely in a context loss situation if mapped memory allocation
// for font buffer failed.
return;
}
Serializer serializer(reinterpret_cast<char*>(memory), bytes_required);
// 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);
DCHECK(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.data(), strike_data.size(), 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