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.
4
5 #include <stack>
6 #include <vector>
7
8 #include "gpu/command_buffer/client/share_group.h"
9
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"
15
16 namespace gpu {
17 namespace gles2 {
18
IdHandlerData()19 ShareGroupContextData::IdHandlerData::IdHandlerData() : flush_generation_(0) {}
~IdHandlerData()20 ShareGroupContextData::IdHandlerData::~IdHandlerData() {}
21
22 COMPILE_ASSERT(gpu::kInvalidResource == 0,
23 INVALID_RESOURCE_NOT_0_AS_GL_EXPECTS);
24
25 // The standard id handler.
26 class IdHandler : public IdHandlerInterface {
27 public:
IdHandler()28 IdHandler() { }
~IdHandler()29 virtual ~IdHandler() { }
30
31 // Overridden from IdHandlerInterface.
MakeIds(GLES2Implementation *,GLuint id_offset,GLsizei n,GLuint * ids)32 virtual void MakeIds(
33 GLES2Implementation* /* gl_impl */,
34 GLuint id_offset, GLsizei n, GLuint* ids) OVERRIDE {
35 base::AutoLock auto_lock(lock_);
36 if (id_offset == 0) {
37 for (GLsizei ii = 0; ii < n; ++ii) {
38 ids[ii] = id_allocator_.AllocateID();
39 }
40 } else {
41 for (GLsizei ii = 0; ii < n; ++ii) {
42 ids[ii] = id_allocator_.AllocateIDAtOrAbove(id_offset);
43 id_offset = ids[ii] + 1;
44 }
45 }
46 }
47
48 // Overridden from IdHandlerInterface.
FreeIds(GLES2Implementation * gl_impl,GLsizei n,const GLuint * ids,DeleteFn delete_fn)49 virtual bool FreeIds(
50 GLES2Implementation* gl_impl,
51 GLsizei n, const GLuint* ids, DeleteFn delete_fn) OVERRIDE {
52 base::AutoLock auto_lock(lock_);
53
54 for (GLsizei ii = 0; ii < n; ++ii) {
55 id_allocator_.FreeID(ids[ii]);
56 }
57
58 (gl_impl->*delete_fn)(n, ids);
59 // We need to ensure that the delete call is evaluated on the service side
60 // before any other contexts issue commands using these client ids.
61 // TODO(vmiura): Can remove this by virtualizing internal ids, however
62 // this code only affects PPAPI for now.
63 gl_impl->helper()->CommandBufferHelper::Flush();
64 return true;
65 }
66
67 // Overridden from IdHandlerInterface.
MarkAsUsedForBind(GLuint id)68 virtual bool MarkAsUsedForBind(GLuint id) OVERRIDE {
69 if (id == 0)
70 return true;
71 base::AutoLock auto_lock(lock_);
72 return id_allocator_.MarkAsUsed(id);
73 }
74
FreeContext(GLES2Implementation * gl_impl)75 virtual void FreeContext(GLES2Implementation* gl_impl) OVERRIDE {}
76
77 private:
78 base::Lock lock_;
79 IdAllocator id_allocator_;
80 };
81
82 // An id handler that requires Gen before Bind.
83 class StrictIdHandler : public IdHandlerInterface {
84 public:
StrictIdHandler(int id_namespace)85 explicit StrictIdHandler(int id_namespace) : id_namespace_(id_namespace) {}
~StrictIdHandler()86 virtual ~StrictIdHandler() {}
87
88 // Overridden from IdHandler.
MakeIds(GLES2Implementation * gl_impl,GLuint,GLsizei n,GLuint * ids)89 virtual void MakeIds(GLES2Implementation* gl_impl,
90 GLuint /* id_offset */,
91 GLsizei n,
92 GLuint* ids) OVERRIDE {
93 base::AutoLock auto_lock(lock_);
94
95 // Collect pending FreeIds from other flush_generation.
96 CollectPendingFreeIds(gl_impl);
97
98 for (GLsizei ii = 0; ii < n; ++ii) {
99 if (!free_ids_.empty()) {
100 // Allocate a previously freed Id.
101 ids[ii] = free_ids_.top();
102 free_ids_.pop();
103
104 // Record kIdInUse state.
105 DCHECK(id_states_[ids[ii] - 1] == kIdFree);
106 id_states_[ids[ii] - 1] = kIdInUse;
107 } else {
108 // Allocate a new Id.
109 id_states_.push_back(kIdInUse);
110 ids[ii] = id_states_.size();
111 }
112 }
113 }
114
115 // Overridden from IdHandler.
FreeIds(GLES2Implementation * gl_impl,GLsizei n,const GLuint * ids,DeleteFn delete_fn)116 virtual bool FreeIds(GLES2Implementation* gl_impl,
117 GLsizei n,
118 const GLuint* ids,
119 DeleteFn delete_fn) OVERRIDE {
120
121 // Delete stub must run before CollectPendingFreeIds.
122 (gl_impl->*delete_fn)(n, ids);
123
124 {
125 base::AutoLock auto_lock(lock_);
126
127 // Collect pending FreeIds from other flush_generation.
128 CollectPendingFreeIds(gl_impl);
129
130 // Save Ids to free in a later flush_generation.
131 ShareGroupContextData::IdHandlerData* ctxt_data =
132 gl_impl->share_group_context_data()->id_handler_data(id_namespace_);
133
134 for (GLsizei ii = 0; ii < n; ++ii) {
135 GLuint id = ids[ii];
136 if (id != 0) {
137 // Save freed Id for later.
138 DCHECK(id_states_[id - 1] == kIdInUse);
139 id_states_[id - 1] = kIdPendingFree;
140 ctxt_data->freed_ids_.push_back(id);
141 }
142 }
143 }
144
145 return true;
146 }
147
148 // Overridden from IdHandler.
MarkAsUsedForBind(GLuint id)149 virtual bool MarkAsUsedForBind(GLuint id) OVERRIDE {
150 #ifndef NDEBUG
151 if (id != 0) {
152 base::AutoLock auto_lock(lock_);
153 DCHECK(id_states_[id - 1] == kIdInUse);
154 }
155 #endif
156 return true;
157 }
158
159 // Overridden from IdHandlerInterface.
FreeContext(GLES2Implementation * gl_impl)160 virtual void FreeContext(GLES2Implementation* gl_impl) OVERRIDE {
161 base::AutoLock auto_lock(lock_);
162 CollectPendingFreeIds(gl_impl);
163 }
164
165 private:
166 enum IdState { kIdFree, kIdPendingFree, kIdInUse };
167
CollectPendingFreeIds(GLES2Implementation * gl_impl)168 void CollectPendingFreeIds(GLES2Implementation* gl_impl) {
169 uint32 flush_generation = gl_impl->helper()->flush_generation();
170 ShareGroupContextData::IdHandlerData* ctxt_data =
171 gl_impl->share_group_context_data()->id_handler_data(id_namespace_);
172
173 if (ctxt_data->flush_generation_ != flush_generation) {
174 ctxt_data->flush_generation_ = flush_generation;
175 for (uint32 ii = 0; ii < ctxt_data->freed_ids_.size(); ++ii) {
176 const GLuint id = ctxt_data->freed_ids_[ii];
177 DCHECK(id_states_[id - 1] == kIdPendingFree);
178 id_states_[id - 1] = kIdFree;
179 free_ids_.push(id);
180 }
181 ctxt_data->freed_ids_.clear();
182 }
183 }
184
185 int id_namespace_;
186
187 base::Lock lock_;
188 std::vector<uint8> id_states_;
189 std::stack<uint32> free_ids_;
190 };
191
192 // An id handler for ids that are never reused.
193 class NonReusedIdHandler : public IdHandlerInterface {
194 public:
NonReusedIdHandler()195 NonReusedIdHandler() : last_id_(0) {}
~NonReusedIdHandler()196 virtual ~NonReusedIdHandler() {}
197
198 // Overridden from IdHandlerInterface.
MakeIds(GLES2Implementation *,GLuint id_offset,GLsizei n,GLuint * ids)199 virtual void MakeIds(
200 GLES2Implementation* /* gl_impl */,
201 GLuint id_offset, GLsizei n, GLuint* ids) OVERRIDE {
202 base::AutoLock auto_lock(lock_);
203 for (GLsizei ii = 0; ii < n; ++ii) {
204 ids[ii] = ++last_id_ + id_offset;
205 }
206 }
207
208 // Overridden from IdHandlerInterface.
FreeIds(GLES2Implementation * gl_impl,GLsizei n,const GLuint * ids,DeleteFn delete_fn)209 virtual bool FreeIds(
210 GLES2Implementation* gl_impl,
211 GLsizei n, const GLuint* ids, DeleteFn delete_fn) OVERRIDE {
212 // Ids are never freed.
213 (gl_impl->*delete_fn)(n, ids);
214 return true;
215 }
216
217 // Overridden from IdHandlerInterface.
MarkAsUsedForBind(GLuint)218 virtual bool MarkAsUsedForBind(GLuint /* id */) OVERRIDE {
219 // This is only used for Shaders and Programs which have no bind.
220 return false;
221 }
222
FreeContext(GLES2Implementation * gl_impl)223 virtual void FreeContext(GLES2Implementation* gl_impl) OVERRIDE {}
224
225 private:
226 base::Lock lock_;
227 GLuint last_id_;
228 };
229
ShareGroup(bool bind_generates_resource)230 ShareGroup::ShareGroup(bool bind_generates_resource)
231 : bind_generates_resource_(bind_generates_resource) {
232 if (bind_generates_resource) {
233 for (int i = 0; i < id_namespaces::kNumIdNamespaces; ++i) {
234 if (i == id_namespaces::kProgramsAndShaders) {
235 id_handlers_[i].reset(new NonReusedIdHandler());
236 } else {
237 id_handlers_[i].reset(new IdHandler());
238 }
239 }
240 } else {
241 for (int i = 0; i < id_namespaces::kNumIdNamespaces; ++i) {
242 if (i == id_namespaces::kProgramsAndShaders) {
243 id_handlers_[i].reset(new NonReusedIdHandler());
244 } else {
245 id_handlers_[i].reset(new StrictIdHandler(i));
246 }
247 }
248 }
249 program_info_manager_.reset(ProgramInfoManager::Create(false));
250 }
251
set_program_info_manager(ProgramInfoManager * manager)252 void ShareGroup::set_program_info_manager(ProgramInfoManager* manager) {
253 program_info_manager_.reset(manager);
254 }
255
~ShareGroup()256 ShareGroup::~ShareGroup() {}
257
258 } // namespace gles2
259 } // namespace gpu
260