Fix crash on app list start page keyboard navigation with <4 apps.
[chromium-blink-merge.git] / gpu / command_buffer / client / share_group.cc
blob64632005493a03902c9d40cea05c1f67c4e0ce17
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 <stack>
6 #include <vector>
8 #include "gpu/command_buffer/client/share_group.h"
10 #include "base/logging.h"
11 #include "base/synchronization/lock.h"
12 #include "gpu/command_buffer/client/gles2_implementation.h"
13 #include "gpu/command_buffer/client/program_info_manager.h"
14 #include "gpu/command_buffer/common/id_allocator.h"
16 namespace gpu {
17 namespace gles2 {
19 ShareGroupContextData::IdHandlerData::IdHandlerData() : flush_generation_(0) {}
20 ShareGroupContextData::IdHandlerData::~IdHandlerData() {}
22 static_assert(gpu::kInvalidResource == 0,
23 "GL expects kInvalidResource to be 0");
25 // The standard id handler.
26 class IdHandler : public IdHandlerInterface {
27 public:
28 IdHandler() { }
29 ~IdHandler() override {}
31 // Overridden from IdHandlerInterface.
32 void MakeIds(GLES2Implementation* /* gl_impl */,
33 GLuint id_offset,
34 GLsizei n,
35 GLuint* ids) override {
36 base::AutoLock auto_lock(lock_);
37 if (id_offset == 0) {
38 for (GLsizei ii = 0; ii < n; ++ii) {
39 ids[ii] = id_allocator_.AllocateID();
41 } else {
42 for (GLsizei ii = 0; ii < n; ++ii) {
43 ids[ii] = id_allocator_.AllocateIDAtOrAbove(id_offset);
44 id_offset = ids[ii] + 1;
49 // Overridden from IdHandlerInterface.
50 bool FreeIds(GLES2Implementation* gl_impl,
51 GLsizei n,
52 const GLuint* ids,
53 DeleteFn delete_fn) override {
54 base::AutoLock auto_lock(lock_);
56 for (GLsizei ii = 0; ii < n; ++ii) {
57 id_allocator_.FreeID(ids[ii]);
60 (gl_impl->*delete_fn)(n, ids);
61 // We need to ensure that the delete call is evaluated on the service side
62 // before any other contexts issue commands using these client ids.
63 // TODO(vmiura): Can remove this by virtualizing internal ids, however
64 // this code only affects PPAPI for now.
65 gl_impl->helper()->CommandBufferHelper::Flush();
66 return true;
69 // Overridden from IdHandlerInterface.
70 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
71 GLenum target,
72 GLuint id,
73 BindFn bind_fn) override {
74 base::AutoLock auto_lock(lock_);
75 bool result = id ? id_allocator_.MarkAsUsed(id) : true;
76 (gl_impl->*bind_fn)(target, id);
77 return result;
79 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
80 GLenum target,
81 GLuint index,
82 GLuint id,
83 BindIndexedFn bind_fn) override {
84 base::AutoLock auto_lock(lock_);
85 bool result = id ? id_allocator_.MarkAsUsed(id) : true;
86 (gl_impl->*bind_fn)(target, index, id);
87 return result;
89 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
90 GLenum target,
91 GLuint index,
92 GLuint id,
93 GLintptr offset,
94 GLsizeiptr size,
95 BindIndexedRangeFn bind_fn) override {
96 base::AutoLock auto_lock(lock_);
97 bool result = id ? id_allocator_.MarkAsUsed(id) : true;
98 (gl_impl->*bind_fn)(target, index, id, offset, size);
99 return result;
102 void FreeContext(GLES2Implementation* gl_impl) override {}
104 private:
105 base::Lock lock_;
106 IdAllocator id_allocator_;
109 // An id handler that requires Gen before Bind.
110 class StrictIdHandler : public IdHandlerInterface {
111 public:
112 explicit StrictIdHandler(int id_namespace) : id_namespace_(id_namespace) {}
113 ~StrictIdHandler() override {}
115 // Overridden from IdHandler.
116 void MakeIds(GLES2Implementation* gl_impl,
117 GLuint /* id_offset */,
118 GLsizei n,
119 GLuint* ids) override {
120 base::AutoLock auto_lock(lock_);
122 // Collect pending FreeIds from other flush_generation.
123 CollectPendingFreeIds(gl_impl);
125 for (GLsizei ii = 0; ii < n; ++ii) {
126 if (!free_ids_.empty()) {
127 // Allocate a previously freed Id.
128 ids[ii] = free_ids_.top();
129 free_ids_.pop();
131 // Record kIdInUse state.
132 DCHECK(id_states_[ids[ii] - 1] == kIdFree);
133 id_states_[ids[ii] - 1] = kIdInUse;
134 } else {
135 // Allocate a new Id.
136 id_states_.push_back(kIdInUse);
137 ids[ii] = id_states_.size();
142 // Overridden from IdHandler.
143 bool FreeIds(GLES2Implementation* gl_impl,
144 GLsizei n,
145 const GLuint* ids,
146 DeleteFn delete_fn) override {
147 // Delete stub must run before CollectPendingFreeIds.
148 (gl_impl->*delete_fn)(n, ids);
151 base::AutoLock auto_lock(lock_);
153 // Collect pending FreeIds from other flush_generation.
154 CollectPendingFreeIds(gl_impl);
156 // Save Ids to free in a later flush_generation.
157 ShareGroupContextData::IdHandlerData* ctxt_data =
158 gl_impl->share_group_context_data()->id_handler_data(id_namespace_);
160 for (GLsizei ii = 0; ii < n; ++ii) {
161 GLuint id = ids[ii];
162 if (id != 0) {
163 // Save freed Id for later.
164 DCHECK(id_states_[id - 1] == kIdInUse);
165 id_states_[id - 1] = kIdPendingFree;
166 ctxt_data->freed_ids_.push_back(id);
171 return true;
174 // Overridden from IdHandler.
175 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
176 GLenum target,
177 GLuint id,
178 BindFn bind_fn) override {
179 #ifndef NDEBUG
180 if (id != 0) {
181 base::AutoLock auto_lock(lock_);
182 DCHECK(id_states_[id - 1] == kIdInUse);
184 #endif
185 // StrictIdHandler is used if |bind_generates_resource| is false. In that
186 // case, |bind_fn| will not use Flush() after helper->Bind*(), so it is OK
187 // to call |bind_fn| without holding the lock.
188 (gl_impl->*bind_fn)(target, id);
189 return true;
191 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
192 GLenum target,
193 GLuint index,
194 GLuint id,
195 BindIndexedFn bind_fn) override {
196 #ifndef NDEBUG
197 if (id != 0) {
198 base::AutoLock auto_lock(lock_);
199 DCHECK(id_states_[id - 1] == kIdInUse);
201 #endif
202 // StrictIdHandler is used if |bind_generates_resource| is false. In that
203 // case, |bind_fn| will not use Flush() after helper->Bind*(), so it is OK
204 // to call |bind_fn| without holding the lock.
205 (gl_impl->*bind_fn)(target, index, id);
206 return true;
208 bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
209 GLenum target,
210 GLuint index,
211 GLuint id,
212 GLintptr offset,
213 GLsizeiptr size,
214 BindIndexedRangeFn bind_fn) override {
215 #ifndef NDEBUG
216 if (id != 0) {
217 base::AutoLock auto_lock(lock_);
218 DCHECK(id_states_[id - 1] == kIdInUse);
220 #endif
221 // StrictIdHandler is used if |bind_generates_resource| is false. In that
222 // case, |bind_fn| will not use Flush() after helper->Bind*(), so it is OK
223 // to call |bind_fn| without holding the lock.
224 (gl_impl->*bind_fn)(target, index, id, offset, size);
225 return true;
228 // Overridden from IdHandlerInterface.
229 void FreeContext(GLES2Implementation* gl_impl) override {
230 base::AutoLock auto_lock(lock_);
231 CollectPendingFreeIds(gl_impl);
234 private:
235 enum IdState { kIdFree, kIdPendingFree, kIdInUse };
237 void CollectPendingFreeIds(GLES2Implementation* gl_impl) {
238 uint32 flush_generation = gl_impl->helper()->flush_generation();
239 ShareGroupContextData::IdHandlerData* ctxt_data =
240 gl_impl->share_group_context_data()->id_handler_data(id_namespace_);
242 if (ctxt_data->flush_generation_ != flush_generation) {
243 ctxt_data->flush_generation_ = flush_generation;
244 for (uint32 ii = 0; ii < ctxt_data->freed_ids_.size(); ++ii) {
245 const GLuint id = ctxt_data->freed_ids_[ii];
246 DCHECK(id_states_[id - 1] == kIdPendingFree);
247 id_states_[id - 1] = kIdFree;
248 free_ids_.push(id);
250 ctxt_data->freed_ids_.clear();
254 int id_namespace_;
256 base::Lock lock_;
257 std::vector<uint8> id_states_;
258 std::stack<uint32> free_ids_;
261 // An id handler for ids that are never reused.
262 class NonReusedIdHandler : public IdHandlerInterface {
263 public:
264 NonReusedIdHandler() : last_id_(0) {}
265 ~NonReusedIdHandler() override {}
267 // Overridden from IdHandlerInterface.
268 void MakeIds(GLES2Implementation* /* gl_impl */,
269 GLuint id_offset,
270 GLsizei n,
271 GLuint* ids) override {
272 base::AutoLock auto_lock(lock_);
273 for (GLsizei ii = 0; ii < n; ++ii) {
274 ids[ii] = ++last_id_ + id_offset;
278 // Overridden from IdHandlerInterface.
279 bool FreeIds(GLES2Implementation* gl_impl,
280 GLsizei n,
281 const GLuint* ids,
282 DeleteFn delete_fn) override {
283 // Ids are never freed.
284 (gl_impl->*delete_fn)(n, ids);
285 return true;
288 // Overridden from IdHandlerInterface.
289 bool MarkAsUsedForBind(GLES2Implementation* /* gl_impl */,
290 GLenum /* target */,
291 GLuint /* id */,
292 BindFn /* bind_fn */) override {
293 // This is only used for Shaders and Programs which have no bind.
294 return false;
296 bool MarkAsUsedForBind(GLES2Implementation* /* gl_impl */,
297 GLenum /* target */,
298 GLuint /* index */,
299 GLuint /* id */,
300 BindIndexedFn /* bind_fn */) override {
301 // This is only used for Shaders and Programs which have no bind.
302 return false;
304 bool MarkAsUsedForBind(GLES2Implementation* /* gl_impl */,
305 GLenum /* target */,
306 GLuint /* index */,
307 GLuint /* id */,
308 GLintptr /* offset */,
309 GLsizeiptr /* size */,
310 BindIndexedRangeFn /* bind_fn */) override {
311 // This is only used for Shaders and Programs which have no bind.
312 return false;
315 void FreeContext(GLES2Implementation* gl_impl) override {}
317 private:
318 base::Lock lock_;
319 GLuint last_id_;
322 ShareGroup::ShareGroup(bool bind_generates_resource)
323 : bind_generates_resource_(bind_generates_resource) {
324 if (bind_generates_resource) {
325 for (int i = 0; i < id_namespaces::kNumIdNamespaces; ++i) {
326 if (i == id_namespaces::kProgramsAndShaders) {
327 id_handlers_[i].reset(new NonReusedIdHandler());
328 } else {
329 id_handlers_[i].reset(new IdHandler());
332 } else {
333 for (int i = 0; i < id_namespaces::kNumIdNamespaces; ++i) {
334 if (i == id_namespaces::kProgramsAndShaders) {
335 id_handlers_[i].reset(new NonReusedIdHandler());
336 } else {
337 id_handlers_[i].reset(new StrictIdHandler(i));
341 program_info_manager_.reset(new ProgramInfoManager);
344 void ShareGroup::set_program_info_manager(ProgramInfoManager* manager) {
345 program_info_manager_.reset(manager);
348 ShareGroup::~ShareGroup() {}
350 } // namespace gles2
351 } // namespace gpu