Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / gpu / command_buffer / client / share_group.cc
blobfb5b886b0526a9c60ba9b3d79676adafb5e97c08
1 // Copyright (c) 2012 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.
5 #include "gpu/command_buffer/client/share_group.h"
7 #include <stack>
8 #include <vector>
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "base/synchronization/lock.h"
12 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
13 #include "gpu/command_buffer/client/gles2_implementation.h"
14 #include "gpu/command_buffer/client/program_info_manager.h"
15 #include "gpu/command_buffer/common/id_allocator.h"
17 namespace gpu {
18 namespace gles2 {
20 ShareGroupContextData::IdHandlerData::IdHandlerData() : flush_generation_(0) {}
21 ShareGroupContextData::IdHandlerData::~IdHandlerData() {}
23 static_assert(gpu::kInvalidResource == 0,
24 "GL expects kInvalidResource to be 0");
26 // The standard id handler.
27 class IdHandler : public IdHandlerInterface {
28 public:
29 IdHandler() { }
30 ~IdHandler() override {}
32 // Overridden from IdHandlerInterface.
33 void MakeIds(GLES2Implementation* /* gl_impl */,
34 GLuint id_offset,
35 GLsizei n,
36 GLuint* ids) override {
37 base::AutoLock auto_lock(lock_);
38 if (id_offset == 0) {
39 for (GLsizei ii = 0; ii < n; ++ii) {
40 ids[ii] = id_allocator_.AllocateID();
42 } else {
43 for (GLsizei ii = 0; ii < n; ++ii) {
44 ids[ii] = id_allocator_.AllocateIDAtOrAbove(id_offset);
45 id_offset = ids[ii] + 1;
50 // Overridden from IdHandlerInterface.
51 bool FreeIds(GLES2Implementation* gl_impl,
52 GLsizei n,
53 const GLuint* ids,
54 DeleteFn delete_fn) override {
55 base::AutoLock auto_lock(lock_);
57 for (GLsizei ii = 0; ii < n; ++ii) {
58 id_allocator_.FreeID(ids[ii]);
61 (gl_impl->*delete_fn)(n, ids);
62 // We need to ensure that the delete call is evaluated on the service side
63 // before any other contexts issue commands using these client ids.
64 gl_impl->helper()->CommandBufferHelper::OrderingBarrier();
65 return true;
68 // Overridden from IdHandlerInterface.
69 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
70 GLenum target,
71 GLuint id,
72 BindFn bind_fn) override {
73 base::AutoLock auto_lock(lock_);
74 bool result = id ? id_allocator_.MarkAsUsed(id) : true;
75 (gl_impl->*bind_fn)(target, id);
76 return result;
78 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
79 GLenum target,
80 GLuint index,
81 GLuint id,
82 BindIndexedFn bind_fn) override {
83 base::AutoLock auto_lock(lock_);
84 bool result = id ? id_allocator_.MarkAsUsed(id) : true;
85 (gl_impl->*bind_fn)(target, index, id);
86 return result;
88 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
89 GLenum target,
90 GLuint index,
91 GLuint id,
92 GLintptr offset,
93 GLsizeiptr size,
94 BindIndexedRangeFn bind_fn) override {
95 base::AutoLock auto_lock(lock_);
96 bool result = id ? id_allocator_.MarkAsUsed(id) : true;
97 (gl_impl->*bind_fn)(target, index, id, offset, size);
98 return result;
101 void FreeContext(GLES2Implementation* gl_impl) override {}
103 private:
104 base::Lock lock_;
105 IdAllocator id_allocator_;
108 // An id handler that requires Gen before Bind.
109 class StrictIdHandler : public IdHandlerInterface {
110 public:
111 explicit StrictIdHandler(int id_namespace) : id_namespace_(id_namespace) {}
112 ~StrictIdHandler() override {}
114 // Overridden from IdHandler.
115 void MakeIds(GLES2Implementation* gl_impl,
116 GLuint /* id_offset */,
117 GLsizei n,
118 GLuint* ids) override {
119 base::AutoLock auto_lock(lock_);
121 // Collect pending FreeIds from other flush_generation.
122 CollectPendingFreeIds(gl_impl);
124 for (GLsizei ii = 0; ii < n; ++ii) {
125 if (!free_ids_.empty()) {
126 // Allocate a previously freed Id.
127 ids[ii] = free_ids_.top();
128 free_ids_.pop();
130 // Record kIdInUse state.
131 DCHECK(id_states_[ids[ii] - 1] == kIdFree);
132 id_states_[ids[ii] - 1] = kIdInUse;
133 } else {
134 // Allocate a new Id.
135 id_states_.push_back(kIdInUse);
136 ids[ii] = id_states_.size();
141 // Overridden from IdHandler.
142 bool FreeIds(GLES2Implementation* gl_impl,
143 GLsizei n,
144 const GLuint* ids,
145 DeleteFn delete_fn) override {
146 // Delete stub must run before CollectPendingFreeIds.
147 (gl_impl->*delete_fn)(n, ids);
150 base::AutoLock auto_lock(lock_);
152 // Collect pending FreeIds from other flush_generation.
153 CollectPendingFreeIds(gl_impl);
155 // Save Ids to free in a later flush_generation.
156 ShareGroupContextData::IdHandlerData* ctxt_data =
157 gl_impl->share_group_context_data()->id_handler_data(id_namespace_);
159 for (GLsizei ii = 0; ii < n; ++ii) {
160 GLuint id = ids[ii];
161 if (id != 0) {
162 // Save freed Id for later.
163 DCHECK(id_states_[id - 1] == kIdInUse);
164 id_states_[id - 1] = kIdPendingFree;
165 ctxt_data->freed_ids_.push_back(id);
170 return true;
173 // Overridden from IdHandler.
174 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
175 GLenum target,
176 GLuint id,
177 BindFn bind_fn) override {
178 #ifndef NDEBUG
179 if (id != 0) {
180 base::AutoLock auto_lock(lock_);
181 DCHECK(id_states_[id - 1] == kIdInUse);
183 #endif
184 // StrictIdHandler is used if |bind_generates_resource| is false. In that
185 // case, |bind_fn| will not use Flush() after helper->Bind*(), so it is OK
186 // to call |bind_fn| without holding the lock.
187 (gl_impl->*bind_fn)(target, id);
188 return true;
190 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
191 GLenum target,
192 GLuint index,
193 GLuint id,
194 BindIndexedFn bind_fn) override {
195 #ifndef NDEBUG
196 if (id != 0) {
197 base::AutoLock auto_lock(lock_);
198 DCHECK(id_states_[id - 1] == kIdInUse);
200 #endif
201 // StrictIdHandler is used if |bind_generates_resource| is false. In that
202 // case, |bind_fn| will not use Flush() after helper->Bind*(), so it is OK
203 // to call |bind_fn| without holding the lock.
204 (gl_impl->*bind_fn)(target, index, id);
205 return true;
207 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
208 GLenum target,
209 GLuint index,
210 GLuint id,
211 GLintptr offset,
212 GLsizeiptr size,
213 BindIndexedRangeFn bind_fn) override {
214 #ifndef NDEBUG
215 if (id != 0) {
216 base::AutoLock auto_lock(lock_);
217 DCHECK(id_states_[id - 1] == kIdInUse);
219 #endif
220 // StrictIdHandler is used if |bind_generates_resource| is false. In that
221 // case, |bind_fn| will not use Flush() after helper->Bind*(), so it is OK
222 // to call |bind_fn| without holding the lock.
223 (gl_impl->*bind_fn)(target, index, id, offset, size);
224 return true;
227 // Overridden from IdHandlerInterface.
228 void FreeContext(GLES2Implementation* gl_impl) override {
229 base::AutoLock auto_lock(lock_);
230 CollectPendingFreeIds(gl_impl);
233 private:
234 enum IdState { kIdFree, kIdPendingFree, kIdInUse };
236 void CollectPendingFreeIds(GLES2Implementation* gl_impl) {
237 uint32 flush_generation = gl_impl->helper()->flush_generation();
238 ShareGroupContextData::IdHandlerData* ctxt_data =
239 gl_impl->share_group_context_data()->id_handler_data(id_namespace_);
241 if (ctxt_data->flush_generation_ != flush_generation) {
242 ctxt_data->flush_generation_ = flush_generation;
243 for (uint32 ii = 0; ii < ctxt_data->freed_ids_.size(); ++ii) {
244 const GLuint id = ctxt_data->freed_ids_[ii];
245 DCHECK(id_states_[id - 1] == kIdPendingFree);
246 id_states_[id - 1] = kIdFree;
247 free_ids_.push(id);
249 ctxt_data->freed_ids_.clear();
253 int id_namespace_;
255 base::Lock lock_;
256 std::vector<uint8> id_states_;
257 std::stack<uint32> free_ids_;
260 // An id handler for ids that are never reused.
261 class NonReusedIdHandler : public IdHandlerInterface {
262 public:
263 NonReusedIdHandler() : last_id_(0) {}
264 ~NonReusedIdHandler() override {}
266 // Overridden from IdHandlerInterface.
267 void MakeIds(GLES2Implementation* /* gl_impl */,
268 GLuint id_offset,
269 GLsizei n,
270 GLuint* ids) override {
271 base::AutoLock auto_lock(lock_);
272 for (GLsizei ii = 0; ii < n; ++ii) {
273 ids[ii] = ++last_id_ + id_offset;
277 // Overridden from IdHandlerInterface.
278 bool FreeIds(GLES2Implementation* gl_impl,
279 GLsizei n,
280 const GLuint* ids,
281 DeleteFn delete_fn) override {
282 // Ids are never freed.
283 (gl_impl->*delete_fn)(n, ids);
284 return true;
287 // Overridden from IdHandlerInterface.
288 bool MarkAsUsedForBind(GLES2Implementation* /* gl_impl */,
289 GLenum /* target */,
290 GLuint /* id */,
291 BindFn /* bind_fn */) override {
292 // This is only used for Shaders and Programs which have no bind.
293 return false;
295 bool MarkAsUsedForBind(GLES2Implementation* /* gl_impl */,
296 GLenum /* target */,
297 GLuint /* index */,
298 GLuint /* id */,
299 BindIndexedFn /* bind_fn */) override {
300 // This is only used for Shaders and Programs which have no bind.
301 return false;
303 bool MarkAsUsedForBind(GLES2Implementation* /* gl_impl */,
304 GLenum /* target */,
305 GLuint /* index */,
306 GLuint /* id */,
307 GLintptr /* offset */,
308 GLsizeiptr /* size */,
309 BindIndexedRangeFn /* bind_fn */) override {
310 // This is only used for Shaders and Programs which have no bind.
311 return false;
314 void FreeContext(GLES2Implementation* gl_impl) override {}
316 private:
317 base::Lock lock_;
318 GLuint last_id_;
321 class RangeIdHandler : public RangeIdHandlerInterface {
322 public:
323 RangeIdHandler() {}
325 void MakeIdRange(GLES2Implementation* /*gl_impl*/,
326 GLsizei n,
327 GLuint* first_id) override {
328 base::AutoLock auto_lock(lock_);
329 *first_id = id_allocator_.AllocateIDRange(n);
332 void FreeIdRange(GLES2Implementation* gl_impl,
333 const GLuint first_id,
334 GLsizei range,
335 DeleteRangeFn delete_fn) override {
336 base::AutoLock auto_lock(lock_);
337 DCHECK(range > 0);
338 id_allocator_.FreeIDRange(first_id, range);
339 (gl_impl->*delete_fn)(first_id, range);
340 gl_impl->helper()->CommandBufferHelper::OrderingBarrier();
343 void FreeContext(GLES2Implementation* gl_impl) override {}
345 private:
346 base::Lock lock_;
347 IdAllocator id_allocator_;
350 ShareGroup::ShareGroup(bool bind_generates_resource, uint64_t tracing_guid)
351 : bind_generates_resource_(bind_generates_resource),
352 tracing_guid_(tracing_guid) {
353 if (bind_generates_resource) {
354 for (int i = 0; i < id_namespaces::kNumIdNamespaces; ++i) {
355 if (i == id_namespaces::kProgramsAndShaders) {
356 id_handlers_[i].reset(new NonReusedIdHandler());
357 } else {
358 id_handlers_[i].reset(new IdHandler());
361 } else {
362 for (int i = 0; i < id_namespaces::kNumIdNamespaces; ++i) {
363 if (i == id_namespaces::kProgramsAndShaders) {
364 id_handlers_[i].reset(new NonReusedIdHandler());
365 } else {
366 id_handlers_[i].reset(new StrictIdHandler(i));
370 program_info_manager_.reset(new ProgramInfoManager);
371 for (auto& range_id_handler : range_id_handlers_) {
372 range_id_handler.reset(new RangeIdHandler());
376 void ShareGroup::set_program_info_manager(ProgramInfoManager* manager) {
377 program_info_manager_.reset(manager);
380 ShareGroup::~ShareGroup() {}
382 } // namespace gles2
383 } // namespace gpu