Home | History | Annotate | Download | only in client
      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