| // 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 |