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 19 ShareGroupContextData::IdHandlerData::IdHandlerData() : flush_generation_(0) {} 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: 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. 83 class 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. 193 class 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 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 252 void ShareGroup::set_program_info_manager(ProgramInfoManager* manager) { 253 program_info_manager_.reset(manager); 254 } 255 256 ShareGroup::~ShareGroup() {} 257 258 } // namespace gles2 259 } // namespace gpu 260