| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 
 |    2 // Use of this source code is governed by a BSD-style license that can be | 
 |    3 // found in the LICENSE file. | 
 |    4  | 
 |    5 #include "gpu/command_buffer/client/client_discardable_manager.h" | 
 |    6  | 
 |    7 #include "base/memory/ptr_util.h" | 
 |    8 #include "base/sys_info.h" | 
 |    9  | 
 |   10 namespace gpu { | 
 |   11 namespace { | 
 |   12  | 
 |   13 // Stores a set of offsets, initially 0 to |element_count_|. Allows callers to | 
 |   14 // take and return offsets from the set. Internally stores the offsets as a set | 
 |   15 // of ranges. This means that in the worst case (every other offset taken), the | 
 |   16 // set will use |element_count_| uints, but should typically use fewer. | 
 |   17 class FreeOffsetSet { | 
 |   18  public: | 
 |   19   // Creates a new set, containing 0 to |element_count|. | 
 |   20   FreeOffsetSet(uint32_t element_count); | 
 |   21  | 
 |   22   // Returns true if the set contains at least one element. | 
 |   23   bool HasFreeOffset() const; | 
 |   24  | 
 |   25   // Returns true if any element from the set has been taken. | 
 |   26   bool HasUsedOffset() const; | 
 |   27  | 
 |   28   // Takes a free offset from the set. Should only be called if HasFreeOffset(). | 
 |   29   uint32_t TakeFreeOffset(); | 
 |   30  | 
 |   31   // Returns an offset to the set. | 
 |   32   void ReturnFreeOffset(uint32_t offset); | 
 |   33  | 
 |   34  private: | 
 |   35   struct FreeRange { | 
 |   36     uint32_t start; | 
 |   37     uint32_t end; | 
 |   38   }; | 
 |   39   struct CompareFreeRanges { | 
 |   40     bool operator()(const FreeRange& a, const FreeRange& b) const { | 
 |   41       return a.start < b.start; | 
 |   42     } | 
 |   43   }; | 
 |   44  | 
 |   45   const uint32_t element_count_; | 
 |   46   std::set<FreeRange, CompareFreeRanges> free_ranges_; | 
 |   47  | 
 |   48   DISALLOW_COPY_AND_ASSIGN(FreeOffsetSet); | 
 |   49 }; | 
 |   50  | 
 |   51 FreeOffsetSet::FreeOffsetSet(uint32_t element_count) | 
 |   52     : element_count_(element_count) { | 
 |   53   free_ranges_.insert({0, element_count_}); | 
 |   54 } | 
 |   55  | 
 |   56 bool FreeOffsetSet::HasFreeOffset() const { | 
 |   57   return !free_ranges_.empty(); | 
 |   58 } | 
 |   59  | 
 |   60 bool FreeOffsetSet::HasUsedOffset() const { | 
 |   61   if (free_ranges_.size() != 1 || free_ranges_.begin()->start != 0 || | 
 |   62       free_ranges_.begin()->end != element_count_) | 
 |   63     return true; | 
 |   64  | 
 |   65   return false; | 
 |   66 } | 
 |   67  | 
 |   68 uint32_t FreeOffsetSet::TakeFreeOffset() { | 
 |   69   DCHECK(HasFreeOffset()); | 
 |   70  | 
 |   71   auto it = free_ranges_.begin(); | 
 |   72   uint32_t offset_to_return = it->start; | 
 |   73  | 
 |   74   FreeRange new_range{it->start + 1, it->end}; | 
 |   75   free_ranges_.erase(it); | 
 |   76   if (new_range.start != new_range.end) | 
 |   77     free_ranges_.insert(new_range); | 
 |   78  | 
 |   79   return offset_to_return; | 
 |   80 } | 
 |   81  | 
 |   82 void FreeOffsetSet::ReturnFreeOffset(uint32_t offset) { | 
 |   83   FreeRange new_range{offset, offset + 1}; | 
 |   84  | 
 |   85   // Find the FreeRange directly before/after our new range. | 
 |   86   auto next_range = free_ranges_.lower_bound(new_range); | 
 |   87   auto prev_range = free_ranges_.end(); | 
 |   88   if (next_range != free_ranges_.begin()) { | 
 |   89     prev_range = std::prev(next_range); | 
 |   90   } | 
 |   91  | 
 |   92   // Collapse ranges if possible. | 
 |   93   if (next_range != free_ranges_.end() && next_range->start == new_range.end) { | 
 |   94     new_range.end = next_range->end; | 
 |   95     free_ranges_.erase(next_range); | 
 |   96   } | 
 |   97  | 
 |   98   if (prev_range != free_ranges_.end() && prev_range->end == new_range.start) { | 
 |   99     new_range.start = prev_range->start; | 
 |  100     free_ranges_.erase(prev_range); | 
 |  101   } | 
 |  102  | 
 |  103   free_ranges_.insert(new_range); | 
 |  104 } | 
 |  105  | 
 |  106 // Returns the size of the allocation which ClientDiscardableManager will | 
 |  107 // sub-allocate from. This should be at least as big as the minimum shared | 
 |  108 // memory allocation size. | 
 |  109 size_t AllocationSize() { | 
 |  110   size_t allocation_size = base::SysInfo::VMAllocationGranularity(); | 
 |  111   // If the allocation is small (less than 2K), round it up to at least 4K. | 
 |  112   allocation_size = std::max(static_cast<size_t>(2048), allocation_size); | 
 |  113   return allocation_size; | 
 |  114 } | 
 |  115  | 
 |  116 }  // namespace | 
 |  117  | 
 |  118 struct ClientDiscardableManager::Allocation { | 
 |  119   Allocation(uint32_t element_count) : free_offsets(element_count) {} | 
 |  120  | 
 |  121   scoped_refptr<Buffer> buffer; | 
 |  122   int32_t shm_id = 0; | 
 |  123   FreeOffsetSet free_offsets; | 
 |  124 }; | 
 |  125  | 
 |  126 ClientDiscardableManager::ClientDiscardableManager() | 
 |  127     : allocation_size_(AllocationSize()) {} | 
 |  128 ClientDiscardableManager::~ClientDiscardableManager() = default; | 
 |  129  | 
 |  130 ClientDiscardableHandle ClientDiscardableManager::GetForTexture( | 
 |  131     CommandBuffer* command_buffer, | 
 |  132     uint32_t texture_id) { | 
 |  133   auto found = texture_handles_.find(texture_id); | 
 |  134   if (found != texture_handles_.end()) | 
 |  135     return found->second; | 
 |  136  | 
 |  137   scoped_refptr<Buffer> buffer; | 
 |  138   uint32_t offset = 0; | 
 |  139   int32_t shm_id = 0; | 
 |  140   FindAllocation(command_buffer, &buffer, &shm_id, &offset); | 
 |  141   uint32_t byte_offset = offset * element_size_; | 
 |  142   ClientDiscardableHandle handle(std::move(buffer), byte_offset, shm_id); | 
 |  143   texture_handles_.emplace(texture_id, handle); | 
 |  144   return handle; | 
 |  145 } | 
 |  146  | 
 |  147 void ClientDiscardableManager::FreeForTexture(uint32_t texture_id) { | 
 |  148   auto found = texture_handles_.find(texture_id); | 
 |  149   DCHECK(found != texture_handles_.end()); | 
 |  150   pending_handles_.push(found->second); | 
 |  151   texture_handles_.erase(found); | 
 |  152 } | 
 |  153  | 
 |  154 void ClientDiscardableManager::FindAllocation(CommandBuffer* command_buffer, | 
 |  155                                               scoped_refptr<Buffer>* buffer, | 
 |  156                                               int32_t* shm_id, | 
 |  157                                               uint32_t* offset) { | 
 |  158   CheckPending(command_buffer); | 
 |  159  | 
 |  160   for (auto& allocation : allocations_) { | 
 |  161     if (!allocation->free_offsets.HasFreeOffset()) | 
 |  162       continue; | 
 |  163  | 
 |  164     *offset = allocation->free_offsets.TakeFreeOffset(); | 
 |  165     *shm_id = allocation->shm_id; | 
 |  166     *buffer = allocation->buffer; | 
 |  167     return; | 
 |  168   } | 
 |  169  | 
 |  170   // We couldn't find an existing free entry. Allocate more space. | 
 |  171   auto allocation = base::MakeUnique<Allocation>(elements_per_allocation_); | 
 |  172   allocation->buffer = command_buffer->CreateTransferBuffer( | 
 |  173       allocation_size_, &allocation->shm_id); | 
 |  174  | 
 |  175   *offset = allocation->free_offsets.TakeFreeOffset(); | 
 |  176   *shm_id = allocation->shm_id; | 
 |  177   *buffer = allocation->buffer; | 
 |  178   allocations_.push_back(std::move(allocation)); | 
 |  179 } | 
 |  180  | 
 |  181 void ClientDiscardableManager::ReturnAllocation( | 
 |  182     CommandBuffer* command_buffer, | 
 |  183     const ClientDiscardableHandle& handle) { | 
 |  184   for (auto it = allocations_.begin(); it != allocations_.end(); ++it) { | 
 |  185     Allocation* allocation = it->get(); | 
 |  186     if (allocation->shm_id != handle.shm_id()) | 
 |  187       continue; | 
 |  188  | 
 |  189     allocation->free_offsets.ReturnFreeOffset(handle.byte_offset() / | 
 |  190                                               element_size_); | 
 |  191  | 
 |  192     if (!allocation->free_offsets.HasUsedOffset()) { | 
 |  193       command_buffer->DestroyTransferBuffer(allocation->shm_id); | 
 |  194       allocations_.erase(it); | 
 |  195       return; | 
 |  196     } | 
 |  197   } | 
 |  198 } | 
 |  199  | 
 |  200 void ClientDiscardableManager::CheckPending(CommandBuffer* command_buffer) { | 
 |  201   while (pending_handles_.size() > 0 && | 
 |  202          pending_handles_.front().CanBeReUsed()) { | 
 |  203     ReturnAllocation(command_buffer, pending_handles_.front()); | 
 |  204     pending_handles_.pop(); | 
 |  205   } | 
 |  206 } | 
 |  207  | 
 |  208 }  // namespace gpu | 
| OLD | NEW |