| // 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; | 
 |  | 
 | 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_ = std::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_ = std::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()) { | 
 |     // 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 |