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
16namespace gpu {
17namespace gles2 {
18
19ShareGroupContextData::IdHandlerData::IdHandlerData() : flush_generation_(0) {}
20ShareGroupContextData::IdHandlerData::~IdHandlerData() {}
21
22COMPILE_ASSERT(gpu::kInvalidResource == 0,
23               INVALID_RESOURCE_NOT_0_AS_GL_EXPECTS);
24
25// The standard id handler.
26class IdHandler : public IdHandlerInterface {
27 public:
28  IdHandler() { }
29  virtual ~IdHandler() { }
30
31  // Overridden from IdHandlerInterface.
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.
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.
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
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.
83class StrictIdHandler : public IdHandlerInterface {
84 public:
85  explicit StrictIdHandler(int id_namespace) : id_namespace_(id_namespace) {}
86  virtual ~StrictIdHandler() {}
87
88  // Overridden from IdHandler.
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.
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.
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.
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
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.
193class NonReusedIdHandler : public IdHandlerInterface {
194 public:
195  NonReusedIdHandler() : last_id_(0) {}
196  virtual ~NonReusedIdHandler() {}
197
198  // Overridden from IdHandlerInterface.
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.
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.
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
223  virtual void FreeContext(GLES2Implementation* gl_impl) OVERRIDE {}
224
225 private:
226  base::Lock lock_;
227  GLuint last_id_;
228};
229
230ShareGroup::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
252void ShareGroup::set_program_info_manager(ProgramInfoManager* manager) {
253  program_info_manager_.reset(manager);
254}
255
256ShareGroup::~ShareGroup() {}
257
258}  // namespace gles2
259}  // namespace gpu
260