910e62b5创建于 1月15日历史提交
// 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