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

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

Powered by Google App Engine
This is Rietveld 408576698