Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(457)

Unified Diff: gpu/command_buffer/client/client_discardable_manager.cc

Issue 2814583002: Service/ClientDiscardableManager (Closed)
Patch Set: rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: gpu/command_buffer/client/client_discardable_manager.cc
diff --git a/gpu/command_buffer/client/client_discardable_manager.cc b/gpu/command_buffer/client/client_discardable_manager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d657751f66fe40e949f76f15d34d0b02908f0039
--- /dev/null
+++ b/gpu/command_buffer/client/client_discardable_manager.cc
@@ -0,0 +1,232 @@
+// 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_discardable_manager.h"
+
+#include "base/containers/flat_set.h"
+#include "base/memory/ptr_util.h"
+#include "base/sys_info.h"
+
+namespace gpu {
+namespace {
+
+// Stores a set of offsets, initially 0 to |element_count_|. Allows callers to
+// take and return offsets from the set. Internally stores the offsets as a set
+// of ranges. This means that in the worst case (every other offset taken), the
+// set will use |element_count_| uints, but should typically use fewer.
+class FreeOffsetSet {
+ public:
+ // Creates a new set, containing 0 to |element_count|.
+ explicit FreeOffsetSet(uint32_t element_count);
+
+ // Returns true if the set contains at least one element.
+ bool HasFreeOffset() const;
+
+ // Returns true if any element from the set has been taken.
+ bool HasUsedOffset() const;
+
+ // Takes a free offset from the set. Should only be called if HasFreeOffset().
+ uint32_t TakeFreeOffset();
+
+ // Returns an offset to the set.
+ void ReturnFreeOffset(uint32_t offset);
+
+ private:
+ struct FreeRange {
+ uint32_t start;
+ uint32_t end;
+ };
+ struct CompareFreeRanges {
+ bool operator()(const FreeRange& a, const FreeRange& b) const {
+ return a.start < b.start;
+ }
+ };
+
+ const uint32_t element_count_;
+ base::flat_set<FreeRange, CompareFreeRanges> free_ranges_;
+
+ DISALLOW_COPY_AND_ASSIGN(FreeOffsetSet);
+};
+
+FreeOffsetSet::FreeOffsetSet(uint32_t element_count)
+ : element_count_(element_count) {
+ free_ranges_.insert({0, element_count_});
+}
+
+bool FreeOffsetSet::HasFreeOffset() const {
+ return !free_ranges_.empty();
+}
+
+bool FreeOffsetSet::HasUsedOffset() const {
+ if (free_ranges_.size() != 1 || free_ranges_.begin()->start != 0 ||
+ free_ranges_.begin()->end != element_count_)
+ return true;
+
+ return false;
+}
+
+uint32_t FreeOffsetSet::TakeFreeOffset() {
+ DCHECK(HasFreeOffset());
+
+ auto it = free_ranges_.begin();
+ uint32_t offset_to_return = it->start;
+
+ FreeRange new_range{it->start + 1, it->end};
+ free_ranges_.erase(it);
+ if (new_range.start != new_range.end)
+ free_ranges_.insert(new_range);
+
+ return offset_to_return;
+}
+
+void FreeOffsetSet::ReturnFreeOffset(uint32_t offset) {
+ FreeRange new_range{offset, offset + 1};
+
+ // Find the FreeRange directly before/after our new range.
+ auto next_range = free_ranges_.lower_bound(new_range);
+ auto prev_range = free_ranges_.end();
+ if (next_range != free_ranges_.begin()) {
+ prev_range = std::prev(next_range);
+ }
+
+ // Collapse ranges if possible.
+ if (prev_range != free_ranges_.end() && prev_range->end == new_range.start) {
+ new_range.start = prev_range->start;
+ // Erase invalidates the next_range iterator, so re-acquire it.
+ next_range = free_ranges_.erase(prev_range);
+ }
+
+ if (next_range != free_ranges_.end() && next_range->start == new_range.end) {
+ new_range.end = next_range->end;
+ free_ranges_.erase(next_range);
+ }
+
+ free_ranges_.insert(new_range);
+}
+
+// Returns the size of the allocation which ClientDiscardableManager will
+// sub-allocate from. This should be at least as big as the minimum shared
+// memory allocation size.
+size_t AllocationSize() {
+#if defined(OS_NACL)
+ // base::SysInfo isn't available under NaCl.
+ size_t allocation_size = getpagesize();
+#else
+ size_t allocation_size = base::SysInfo::VMAllocationGranularity();
+#endif
+
+ // If the allocation is small (less than 2K), round it up to at least 2K.
+ allocation_size = std::max(static_cast<size_t>(2048), allocation_size);
+ return allocation_size;
+}
+
+} // namespace
+
+struct ClientDiscardableManager::Allocation {
+ Allocation(uint32_t element_count) : free_offsets(element_count) {}
+
+ scoped_refptr<Buffer> buffer;
+ int32_t shm_id = 0;
+ FreeOffsetSet free_offsets;
+};
+
+ClientDiscardableManager::ClientDiscardableManager()
+ : allocation_size_(AllocationSize()) {}
+ClientDiscardableManager::~ClientDiscardableManager() = default;
+
+ClientDiscardableHandle ClientDiscardableManager::InitializeTexture(
+ CommandBuffer* command_buffer,
+ uint32_t texture_id) {
+ DCHECK(texture_handles_.find(texture_id) == texture_handles_.end());
+
+ scoped_refptr<Buffer> buffer;
+ uint32_t offset = 0;
+ int32_t shm_id = 0;
+ FindAllocation(command_buffer, &buffer, &shm_id, &offset);
+ uint32_t byte_offset = offset * element_size_;
+ ClientDiscardableHandle handle(std::move(buffer), byte_offset, shm_id);
+ texture_handles_.emplace(texture_id, handle);
+ return handle;
+}
+
+bool ClientDiscardableManager::LockTexture(uint32_t texture_id) {
+ auto found = texture_handles_.find(texture_id);
+ DCHECK(found != texture_handles_.end());
+ return found->second.Lock();
+}
+
+void ClientDiscardableManager::FreeTexture(uint32_t texture_id) {
+ auto found = texture_handles_.find(texture_id);
+ if (found == texture_handles_.end())
+ return;
+ pending_handles_.push(found->second);
+ texture_handles_.erase(found);
+}
+
+bool ClientDiscardableManager::TextureIsValid(uint32_t texture_id) const {
+ return texture_handles_.find(texture_id) != texture_handles_.end();
+}
+
+void ClientDiscardableManager::FindAllocation(CommandBuffer* command_buffer,
+ scoped_refptr<Buffer>* buffer,
+ int32_t* shm_id,
+ uint32_t* offset) {
+ CheckPending(command_buffer);
+
+ for (auto& allocation : allocations_) {
+ if (!allocation->free_offsets.HasFreeOffset())
+ continue;
+
+ *offset = allocation->free_offsets.TakeFreeOffset();
+ *shm_id = allocation->shm_id;
+ *buffer = allocation->buffer;
+ return;
+ }
+
+ // We couldn't find an existing free entry. Allocate more space.
+ auto allocation = base::MakeUnique<Allocation>(elements_per_allocation_);
+ allocation->buffer = command_buffer->CreateTransferBuffer(
+ allocation_size_, &allocation->shm_id);
+
+ *offset = allocation->free_offsets.TakeFreeOffset();
+ *shm_id = allocation->shm_id;
+ *buffer = allocation->buffer;
+ allocations_.push_back(std::move(allocation));
+}
+
+void ClientDiscardableManager::ReturnAllocation(
+ CommandBuffer* command_buffer,
+ const ClientDiscardableHandle& handle) {
+ for (auto it = allocations_.begin(); it != allocations_.end(); ++it) {
+ Allocation* allocation = it->get();
+ if (allocation->shm_id != handle.shm_id())
+ continue;
+
+ allocation->free_offsets.ReturnFreeOffset(handle.byte_offset() /
+ element_size_);
+
+ if (!allocation->free_offsets.HasUsedOffset()) {
+ command_buffer->DestroyTransferBuffer(allocation->shm_id);
+ allocations_.erase(it);
+ return;
+ }
+ }
+}
+
+void ClientDiscardableManager::CheckPending(CommandBuffer* command_buffer) {
+ while (pending_handles_.size() > 0 &&
+ pending_handles_.front().CanBeReUsed()) {
+ ReturnAllocation(command_buffer, pending_handles_.front());
+ pending_handles_.pop();
+ }
+}
+
+ClientDiscardableHandle ClientDiscardableManager::GetHandleForTesting(
+ uint32_t texture_id) {
+ auto found = texture_handles_.find(texture_id);
+ DCHECK(found != texture_handles_.end());
+ return found->second;
+}
+
+} // namespace gpu

Powered by Google App Engine
This is Rietveld 408576698