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