blob: b762dacadaeb6d1899e3fe430ee968fefebb6942 [file] [log] [blame]
// Copyright (c) 2017 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_transfer_cache.h"
namespace gpu {
ClientTransferCache::ClientTransferCache(Client* client) : client_(client) {}
ClientTransferCache::~ClientTransferCache() = default;
void* 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_ = base::nullopt;
return nullptr;
}
return mapped_ptr_->address();
}
void* 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_ = base::nullopt;
return nullptr;
}
return transfer_buffer_ptr_->address();
}
void ClientTransferCache::UnmapAndCreateEntry(uint32_t type, uint32_t id) {
EntryKey key(type, id);
base::AutoLock hold(lock_);
auto handle = CreateDiscardableHandle(key);
if (!handle.IsValid())
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_ = base::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_ = base::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) {
lock_.AssertAcquired();
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) {
lock_.AssertAcquired();
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