• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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