910e62b5创建于 1月15日历史提交
// Copyright 2017 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_transfer_cache.h"

namespace gpu {

ClientTransferCache::ClientTransferCache(Client* client) : client_(client) {}

ClientTransferCache::~ClientTransferCache() = default;

base::span<uint8_t> ClientTransferCache::MapEntry(
    MappedMemoryManager* mapped_memory,
    uint32_t size) {
  DCHECK(!mapped_ptr_);
  DCHECK(!transfer_buffer_ptr_);
  mapped_ptr_.emplace(size, client_->cmd_buffer_helper(), mapped_memory);
  if (!mapped_ptr_->valid()) {
    mapped_ptr_ = std::nullopt;
    return {};
  }
  return mapped_ptr_->as_byte_span();
}

base::span<uint8_t> ClientTransferCache::MapTransferBufferEntry(
    TransferBufferInterface* transfer_buffer,
    uint32_t size) {
  DCHECK(!mapped_ptr_);
  DCHECK(!transfer_buffer_ptr_);
  transfer_buffer_ptr_.emplace(size, client_->cmd_buffer_helper(),
                               transfer_buffer);
  if (!transfer_buffer_ptr_->valid()) {
    transfer_buffer_ptr_ = std::nullopt;
    return {};
  }
  return transfer_buffer_ptr_->as_byte_span();
}

void ClientTransferCache::UnmapAndCreateEntry(uint32_t type, uint32_t id) {
  EntryKey key(type, id);

  base::AutoLock hold(lock_);
  auto handle = CreateDiscardableHandle(key);
  if (!handle.IsValid()) {
    // Release any data pointers. Keeping these alive longer can lead to issues
    // with transfer buffer reallocation.
    mapped_ptr_ = std::nullopt;
    transfer_buffer_ptr_ = std::nullopt;
    return;
  }

  if (mapped_ptr_) {
    DCHECK(!transfer_buffer_ptr_);
    client_->IssueCreateTransferCacheEntry(
        type, id, handle.shm_id(), handle.byte_offset(), mapped_ptr_->shm_id(),
        mapped_ptr_->offset(), mapped_ptr_->size());
    mapped_ptr_ = std::nullopt;
  } else {
    DCHECK(!mapped_ptr_);
    client_->IssueCreateTransferCacheEntry(
        type, id, handle.shm_id(), handle.byte_offset(),
        transfer_buffer_ptr_->shm_id(), transfer_buffer_ptr_->offset(),
        transfer_buffer_ptr_->size());
    transfer_buffer_ptr_ = std::nullopt;
  }
}

void ClientTransferCache::AddTransferCacheEntry(uint32_t type,
                                                uint32_t id,
                                                uint32_t shm_id,
                                                uint32_t shm_offset,
                                                uint32_t size) {
  DCHECK(!mapped_ptr_);
  EntryKey key(type, id);

  base::AutoLock hold(lock_);
  auto handle = CreateDiscardableHandle(key);
  if (!handle.IsValid())
    return;

  client_->IssueCreateTransferCacheEntry(type, id, handle.shm_id(),
                                         handle.byte_offset(), shm_id,
                                         shm_offset, size);
}

void ClientTransferCache::StartTransferCacheEntry(
    uint32_t type,
    uint32_t id,
    base::OnceCallback<void(ClientDiscardableHandle)> create_entry_cb) {
  DCHECK(!mapped_ptr_);
  EntryKey key(type, id);

  base::AutoLock hold(lock_);
  auto handle = CreateDiscardableHandle(key);
  if (!handle.IsValid())
    return;

  // Call |create_entry_cb| while |lock_| is held so that in case another thread
  // tries to lock the cache entry later, it can assume that the creation of the
  // service-side cache entry has been triggered.
  std::move(create_entry_cb).Run(handle);
}

ClientDiscardableHandle ClientTransferCache::CreateDiscardableHandle(
    const EntryKey& key) {
  ClientDiscardableHandle::Id discardable_handle_id =
      discardable_manager_.CreateHandle(client_->command_buffer());
  if (discardable_handle_id.is_null())
    return ClientDiscardableHandle();

  // We must have a valid handle here, since the id was generated above and
  // should be in locked state.
  ClientDiscardableHandle handle =
      discardable_manager_.GetHandle(discardable_handle_id);

  // Store the mapping from the given namespace/discardable_handle_id to the
  // transfer cache discardable_handle_id.
  DCHECK(FindDiscardableHandleId(key).is_null());
  discardable_handle_id_map_.emplace(key, discardable_handle_id);
  return handle;
}

bool ClientTransferCache::LockEntry(uint32_t type, uint32_t id) {
  EntryKey key(type, id);

  base::AutoLock hold(lock_);
  auto discardable_handle_id = FindDiscardableHandleId(key);
  if (discardable_handle_id.is_null())
    return false;

  if (discardable_manager_.LockHandle(discardable_handle_id))
    return true;

  // Could not lock. Entry is already deleted service side.
  discardable_handle_id_map_.erase(key);
  return false;
}

void ClientTransferCache::UnlockEntries(
    const std::vector<std::pair<uint32_t, uint32_t>>& entries) {
  base::AutoLock hold(lock_);
  for (const auto& entry : entries) {
    DCHECK(!FindDiscardableHandleId(entry).is_null());
    client_->IssueUnlockTransferCacheEntry(entry.first, entry.second);
  }
}

void ClientTransferCache::DeleteEntry(uint32_t type, uint32_t id) {
  EntryKey key(type, id);
  base::AutoLock hold(lock_);
  auto discardable_handle_id = FindDiscardableHandleId(key);
  if (discardable_handle_id.is_null())
    return;

  discardable_manager_.FreeHandle(discardable_handle_id);
  client_->IssueDeleteTransferCacheEntry(type, id);
  discardable_handle_id_map_.erase(key);
}

ClientDiscardableHandle::Id ClientTransferCache::FindDiscardableHandleId(
    const EntryKey& key) {
  auto id_map_it = discardable_handle_id_map_.find(key);
  if (id_map_it == discardable_handle_id_map_.end())
    return ClientDiscardableHandle::Id();
  return id_map_it->second;
}

}  // namespace gpu