blob: 53bcf2194cbd60b38477c50d5f206c67358017f2 [file] [log] [blame]
// Copyright 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/service/service_font_manager.h"
#include "base/debug/dump_without_crashing.h"
#include "base/metrics/histogram_macros.h"
#include "gpu/command_buffer/common/buffer.h"
#include "gpu/command_buffer/common/discardable_handle.h"
namespace gpu {
namespace {
class Deserializer {
public:
Deserializer(const volatile char* memory, uint32_t memory_size)
: memory_(memory), memory_size_(memory_size) {}
~Deserializer() = default;
template <typename T>
bool Read(T* val) {
static_assert(base::is_trivially_copyable<T>::value,
"Not trivially copyable");
if (!AlignMemory(sizeof(T), alignof(T)))
return false;
*val = *reinterpret_cast<const T*>(const_cast<const char*>(memory_));
memory_ += sizeof(T);
bytes_read_ += sizeof(T);
return true;
}
bool ReadStrikeData(SkStrikeClient* strike_client, uint32_t size) {
if (size == 0u)
return true;
if (!AlignMemory(size, 16))
return false;
if (!strike_client->readStrikeData(memory_, size))
return false;
bytes_read_ += size;
memory_ += size;
return true;
}
private:
bool 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;
base::CheckedNumeric<uint32_t> checked_padded_size = bytes_read_;
checked_padded_size += padding;
checked_padded_size += size;
uint32_t padded_size = 0;
if (!checked_padded_size.AssignIfValid(&padded_size) ||
padded_size > memory_size_)
return false;
memory_ += padding;
bytes_read_ += padding;
return true;
}
const volatile char* memory_;
uint32_t memory_size_;
uint32_t bytes_read_ = 0u;
};
} // namespace
class ServiceFontManager::SkiaDiscardableManager
: public SkStrikeClient::DiscardableHandleManager {
public:
SkiaDiscardableManager(scoped_refptr<ServiceFontManager> font_manager)
: font_manager_(std::move(font_manager)) {}
~SkiaDiscardableManager() override = default;
bool deleteHandle(SkDiscardableHandleId handle_id) override {
if (!font_manager_)
return true;
return font_manager_->DeleteHandle(handle_id);
}
void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
UMA_HISTOGRAM_ENUMERATION("GPU.OopRaster.GlyphCacheMiss", type,
SkStrikeClient::CacheMissType::kLast + 1);
// In general, Skia analysis of glyphs should find all cases.
// If this is not happening, please file a bug with a repro so
// it can be fixed.
NOTREACHED();
const bool no_fallback = (type == SkStrikeClient::kGlyphMetrics ||
type == SkStrikeClient::kGlyphPath ||
type == SkStrikeClient::kGlyphImage);
constexpr int kMaxDumps = 10;
if (no_fallback && dump_count_ < kMaxDumps) {
++dump_count_;
base::debug::DumpWithoutCrashing();
}
}
private:
int dump_count_ = 0;
scoped_refptr<ServiceFontManager> font_manager_;
};
ServiceFontManager::ServiceFontManager(Client* client)
: client_(client),
strike_client_(std::make_unique<SkStrikeClient>(
sk_make_sp<SkiaDiscardableManager>(this))) {}
ServiceFontManager::~ServiceFontManager() {
DCHECK(destroyed_);
}
void ServiceFontManager::Destroy() {
base::AutoLock hold(lock_);
client_ = nullptr;
strike_client_.reset();
discardable_handle_map_.clear();
destroyed_ = true;
}
bool ServiceFontManager::Deserialize(
const volatile char* memory,
uint32_t memory_size,
std::vector<SkDiscardableHandleId>* locked_handles) {
base::AutoLock hold(lock_);
DCHECK(locked_handles->empty());
DCHECK(!destroyed_);
// All new handles.
Deserializer deserializer(memory, memory_size);
uint32_t new_handles_created;
if (!deserializer.Read<uint32_t>(&new_handles_created))
return false;
for (uint32_t i = 0; i < new_handles_created; ++i) {
SerializableSkiaHandle handle;
if (!deserializer.Read<SerializableSkiaHandle>(&handle))
return false;
scoped_refptr<gpu::Buffer> buffer = client_->GetShmBuffer(handle.shm_id);
if (!DiscardableHandleBase::ValidateParameters(buffer.get(),
handle.byte_offset))
return false;
if (!AddHandle(handle.handle_id,
ServiceDiscardableHandle(
std::move(buffer), handle.byte_offset, handle.shm_id))) {
return false;
}
}
// All locked handles
uint32_t num_locked_handles;
if (!deserializer.Read<uint32_t>(&num_locked_handles))
return false;
locked_handles->resize(num_locked_handles);
for (uint32_t i = 0; i < num_locked_handles; ++i) {
if (!deserializer.Read<SkDiscardableHandleId>(&locked_handles->at(i)))
return false;
}
// Skia font data.
uint32_t skia_data_size = 0u;
if (!deserializer.Read<uint32_t>(&skia_data_size))
return false;
{
base::AutoUnlock release(lock_);
if (!deserializer.ReadStrikeData(strike_client_.get(), skia_data_size))
return false;
}
return true;
}
bool ServiceFontManager::AddHandle(SkDiscardableHandleId handle_id,
ServiceDiscardableHandle handle) {
lock_.AssertAcquired();
if (discardable_handle_map_.find(handle_id) != discardable_handle_map_.end())
return false;
discardable_handle_map_[handle_id] = std::move(handle);
return true;
}
bool ServiceFontManager::Unlock(
const std::vector<SkDiscardableHandleId>& handles) {
base::AutoLock hold(lock_);
DCHECK(!destroyed_);
for (auto handle_id : handles) {
auto it = discardable_handle_map_.find(handle_id);
if (it == discardable_handle_map_.end())
return false;
it->second.Unlock();
}
return true;
}
bool ServiceFontManager::DeleteHandle(SkDiscardableHandleId handle_id) {
base::AutoLock hold(lock_);
if (destroyed_)
return true;
auto it = discardable_handle_map_.find(handle_id);
if (it == discardable_handle_map_.end()) {
LOG(ERROR) << "Tried to delete invalid SkDiscardableHandleId: "
<< handle_id;
return true;
}
bool deleted = it->second.Delete();
if (!deleted)
return false;
discardable_handle_map_.erase(it);
return true;
}
} // namespace gpu