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 "gpu/command_buffer/client/program_info_manager.h"
      6 
      7 #include <map>
      8 
      9 #include "base/compiler_specific.h"
     10 #include "base/synchronization/lock.h"
     11 #include "gpu/command_buffer/client/gles2_implementation.h"
     12 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
     13 
     14 namespace gpu {
     15 namespace gles2 {
     16 
     17 class NonCachedProgramInfoManager : public ProgramInfoManager {
     18  public:
     19   NonCachedProgramInfoManager();
     20   virtual ~NonCachedProgramInfoManager();
     21 
     22   virtual void CreateInfo(GLuint program) OVERRIDE;
     23 
     24   virtual void DeleteInfo(GLuint program) OVERRIDE;
     25 
     26   virtual bool GetProgramiv(GLES2Implementation* gl,
     27                             GLuint program,
     28                             GLenum pname,
     29                             GLint* params) OVERRIDE;
     30 
     31   virtual GLint GetAttribLocation(GLES2Implementation* gl,
     32                                   GLuint program,
     33                                   const char* name) OVERRIDE;
     34 
     35   virtual GLint GetUniformLocation(GLES2Implementation* gl,
     36                                    GLuint program,
     37                                    const char* name) OVERRIDE;
     38 
     39   virtual bool GetActiveAttrib(GLES2Implementation* gl,
     40                                GLuint program,
     41                                GLuint index,
     42                                GLsizei bufsize,
     43                                GLsizei* length,
     44                                GLint* size,
     45                                GLenum* type,
     46                                char* name) OVERRIDE;
     47 
     48   virtual bool GetActiveUniform(GLES2Implementation* gl,
     49                                 GLuint program,
     50                                 GLuint index,
     51                                 GLsizei bufsize,
     52                                 GLsizei* length,
     53                                 GLint* size,
     54                                 GLenum* type,
     55                                 char* name) OVERRIDE;
     56 
     57 };
     58 
     59 NonCachedProgramInfoManager::NonCachedProgramInfoManager() {
     60 }
     61 
     62 NonCachedProgramInfoManager::~NonCachedProgramInfoManager() {
     63 }
     64 
     65 void NonCachedProgramInfoManager::CreateInfo(GLuint /* program */) {
     66 }
     67 
     68 void NonCachedProgramInfoManager::DeleteInfo(GLuint /* program */) {
     69 }
     70 
     71 bool NonCachedProgramInfoManager::GetProgramiv(
     72     GLES2Implementation* /* gl */,
     73     GLuint /* program */,
     74     GLenum /* pname */,
     75     GLint* /* params */) {
     76   return false;
     77 }
     78 
     79 GLint NonCachedProgramInfoManager::GetAttribLocation(
     80     GLES2Implementation* gl, GLuint program, const char* name) {
     81   return gl->GetAttribLocationHelper(program, name);
     82 }
     83 
     84 GLint NonCachedProgramInfoManager::GetUniformLocation(
     85     GLES2Implementation* gl, GLuint program, const char* name) {
     86   return gl->GetUniformLocationHelper(program, name);
     87 }
     88 
     89 bool NonCachedProgramInfoManager::GetActiveAttrib(
     90     GLES2Implementation* gl,
     91     GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
     92     GLint* size, GLenum* type, char* name) {
     93   return gl->GetActiveAttribHelper(
     94       program, index, bufsize, length, size, type, name);
     95 }
     96 
     97 bool NonCachedProgramInfoManager::GetActiveUniform(
     98     GLES2Implementation* gl,
     99     GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
    100     GLint* size, GLenum* type, char* name) {
    101   return gl->GetActiveUniformHelper(
    102       program, index, bufsize, length, size, type, name);
    103 }
    104 
    105 class CachedProgramInfoManager : public ProgramInfoManager {
    106  public:
    107   CachedProgramInfoManager();
    108   virtual ~CachedProgramInfoManager();
    109 
    110   virtual void CreateInfo(GLuint program) OVERRIDE;
    111 
    112   virtual void DeleteInfo(GLuint program) OVERRIDE;
    113 
    114   virtual bool GetProgramiv(GLES2Implementation* gl,
    115                             GLuint program,
    116                             GLenum pname,
    117                             GLint* params) OVERRIDE;
    118 
    119   virtual GLint GetAttribLocation(GLES2Implementation* gl,
    120                                   GLuint program,
    121                                   const char* name) OVERRIDE;
    122 
    123   virtual GLint GetUniformLocation(GLES2Implementation* gl,
    124                                    GLuint program,
    125                                    const char* name) OVERRIDE;
    126 
    127   virtual bool GetActiveAttrib(GLES2Implementation* gl,
    128                                GLuint program,
    129                                GLuint index,
    130                                GLsizei bufsize,
    131                                GLsizei* length,
    132                                GLint* size,
    133                                GLenum* type,
    134                                char* name) OVERRIDE;
    135 
    136   virtual bool GetActiveUniform(GLES2Implementation* gl,
    137                                 GLuint program,
    138                                 GLuint index,
    139                                 GLsizei bufsize,
    140                                 GLsizei* length,
    141                                 GLint* size,
    142                                 GLenum* type,
    143                                 char* name) OVERRIDE;
    144 
    145  private:
    146   class Program {
    147    public:
    148     struct UniformInfo {
    149       UniformInfo(GLsizei _size, GLenum _type, const std::string& _name);
    150 
    151       GLsizei size;
    152       GLenum type;
    153       bool is_array;
    154       std::string name;
    155       std::vector<GLint> element_locations;
    156     };
    157     struct VertexAttrib {
    158       VertexAttrib(GLsizei _size, GLenum _type, const std::string& _name,
    159                        GLint _location)
    160           : size(_size),
    161             type(_type),
    162             location(_location),
    163             name(_name) {
    164       }
    165       GLsizei size;
    166       GLenum type;
    167       GLint location;
    168       std::string name;
    169     };
    170 
    171     typedef std::vector<UniformInfo> UniformInfoVector;
    172     typedef std::vector<VertexAttrib> AttribInfoVector;
    173 
    174     Program();
    175 
    176     const AttribInfoVector& GetAttribInfos() const {
    177       return attrib_infos_;
    178     }
    179 
    180     const VertexAttrib* GetAttribInfo(GLint index) const {
    181       return (static_cast<size_t>(index) < attrib_infos_.size()) ?
    182          &attrib_infos_[index] : NULL;
    183     }
    184 
    185     GLint GetAttribLocation(const std::string& name) const;
    186 
    187     const UniformInfo* GetUniformInfo(GLint index) const {
    188       return (static_cast<size_t>(index) < uniform_infos_.size()) ?
    189          &uniform_infos_[index] : NULL;
    190     }
    191 
    192     // Gets the location of a uniform by name.
    193     GLint GetUniformLocation(const std::string& name) const;
    194 
    195     bool GetProgramiv(GLenum pname, GLint* params);
    196 
    197     // Updates the program info after a successful link.
    198     void Update(GLES2Implementation* gl, GLuint program);
    199 
    200    private:
    201     bool cached_;
    202 
    203     GLsizei max_attrib_name_length_;
    204 
    205     // Attrib by index.
    206     AttribInfoVector attrib_infos_;
    207 
    208     GLsizei max_uniform_name_length_;
    209 
    210     // Uniform info by index.
    211     UniformInfoVector uniform_infos_;
    212 
    213     // This is true if glLinkProgram was successful last time it was called.
    214     bool link_status_;
    215   };
    216 
    217   Program* GetProgramInfo(GLES2Implementation* gl, GLuint program);
    218 
    219   // TODO(gman): Switch to a faster container.
    220   typedef std::map<GLuint, Program> ProgramInfoMap;
    221 
    222   ProgramInfoMap program_infos_;
    223 
    224   mutable base::Lock lock_;
    225 };
    226 
    227 CachedProgramInfoManager::Program::UniformInfo::UniformInfo(
    228     GLsizei _size, GLenum _type, const std::string& _name)
    229     : size(_size),
    230       type(_type),
    231       name(_name) {
    232   is_array = (!name.empty() && name[name.size() - 1] == ']');
    233   DCHECK(!(size > 1 && !is_array));
    234 }
    235 
    236 CachedProgramInfoManager::Program::Program()
    237     : cached_(false),
    238       max_attrib_name_length_(0),
    239       max_uniform_name_length_(0),
    240       link_status_(false) {
    241 }
    242 
    243 // TODO(gman): Add a faster lookup.
    244 GLint CachedProgramInfoManager::Program::GetAttribLocation(
    245     const std::string& name) const {
    246   for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
    247     const VertexAttrib& info = attrib_infos_[ii];
    248     if (info.name == name) {
    249       return info.location;
    250     }
    251   }
    252   return -1;
    253 }
    254 
    255 GLint CachedProgramInfoManager::Program::GetUniformLocation(
    256     const std::string& name) const {
    257   bool getting_array_location = false;
    258   size_t open_pos = std::string::npos;
    259   int index = 0;
    260   if (!GLES2Util::ParseUniformName(
    261       name, &open_pos, &index, &getting_array_location)) {
    262     return -1;
    263   }
    264   for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
    265     const UniformInfo& info = uniform_infos_[ii];
    266     if (info.name == name ||
    267         (info.is_array &&
    268          info.name.compare(0, info.name.size() - 3, name) == 0)) {
    269       return info.element_locations[0];
    270     } else if (getting_array_location && info.is_array) {
    271       // Look for an array specification.
    272       size_t open_pos_2 = info.name.find_last_of('[');
    273       if (open_pos_2 == open_pos &&
    274           name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
    275         if (index >= 0 && index < info.size) {
    276           return info.element_locations[index];
    277         }
    278       }
    279     }
    280   }
    281   return -1;
    282 }
    283 
    284 bool CachedProgramInfoManager::Program::GetProgramiv(
    285     GLenum pname, GLint* params) {
    286   switch (pname) {
    287     case GL_LINK_STATUS:
    288       *params = link_status_;
    289       return true;
    290     case GL_ACTIVE_ATTRIBUTES:
    291       *params = attrib_infos_.size();
    292       return true;
    293     case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
    294       *params = max_attrib_name_length_;
    295       return true;
    296     case GL_ACTIVE_UNIFORMS:
    297       *params = uniform_infos_.size();
    298       return true;
    299     case GL_ACTIVE_UNIFORM_MAX_LENGTH:
    300       *params = max_uniform_name_length_;
    301       return true;
    302     default:
    303       break;
    304   }
    305   return false;
    306 }
    307 
    308 template<typename T> static T LocalGetAs(
    309     const std::vector<int8>& data, uint32 offset, size_t size) {
    310   const int8* p = &data[0] + offset;
    311   if (offset + size > data.size()) {
    312     NOTREACHED();
    313     return NULL;
    314   }
    315   return static_cast<T>(static_cast<const void*>(p));
    316 }
    317 
    318 void CachedProgramInfoManager::Program::Update(
    319     GLES2Implementation* gl, GLuint program) {
    320   if (cached_) {
    321     return;
    322   }
    323   std::vector<int8> result;
    324   gl->GetProgramInfoCHROMIUMHelper(program, &result);
    325   if (result.empty()) {
    326     // This should only happen on a lost context.
    327     return;
    328   }
    329   DCHECK_GE(result.size(), sizeof(ProgramInfoHeader));
    330   const ProgramInfoHeader* header = LocalGetAs<const ProgramInfoHeader*>(
    331       result, 0, sizeof(header));
    332   link_status_ = header->link_status != 0;
    333   if (!link_status_) {
    334     return;
    335   }
    336   attrib_infos_.clear();
    337   uniform_infos_.clear();
    338   max_attrib_name_length_ = 0;
    339   max_uniform_name_length_ = 0;
    340   const ProgramInput* inputs = LocalGetAs<const ProgramInput*>(
    341       result, sizeof(*header),
    342       sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms));
    343   const ProgramInput* input = inputs;
    344   for (uint32 ii = 0; ii < header->num_attribs; ++ii) {
    345     const int32* location = LocalGetAs<const int32*>(
    346         result, input->location_offset, sizeof(int32));
    347     const char* name_buf = LocalGetAs<const char*>(
    348         result, input->name_offset, input->name_length);
    349     std::string name(name_buf, input->name_length);
    350     attrib_infos_.push_back(
    351         VertexAttrib(input->size, input->type, name, *location));
    352     max_attrib_name_length_ = std::max(
    353         static_cast<GLsizei>(name.size() + 1), max_attrib_name_length_);
    354     ++input;
    355   }
    356   for (uint32 ii = 0; ii < header->num_uniforms; ++ii) {
    357     const int32* locations = LocalGetAs<const int32*>(
    358         result, input->location_offset, sizeof(int32) * input->size);
    359     const char* name_buf = LocalGetAs<const char*>(
    360         result, input->name_offset, input->name_length);
    361     std::string name(name_buf, input->name_length);
    362     UniformInfo info(input->size, input->type, name);
    363     max_uniform_name_length_ = std::max(
    364         static_cast<GLsizei>(name.size() + 1), max_uniform_name_length_);
    365     for (int32 jj = 0; jj < input->size; ++jj) {
    366       info.element_locations.push_back(locations[jj]);
    367     }
    368     uniform_infos_.push_back(info);
    369     ++input;
    370   }
    371   DCHECK_EQ(header->num_attribs + header->num_uniforms,
    372                 static_cast<uint32>(input - inputs));
    373   cached_ = true;
    374 }
    375 
    376 CachedProgramInfoManager::CachedProgramInfoManager() {
    377 }
    378 
    379 CachedProgramInfoManager::~CachedProgramInfoManager() {
    380 
    381 }
    382 
    383 CachedProgramInfoManager::Program*
    384     CachedProgramInfoManager::GetProgramInfo(
    385         GLES2Implementation* gl, GLuint program) {
    386   lock_.AssertAcquired();
    387   ProgramInfoMap::iterator it = program_infos_.find(program);
    388   if (it == program_infos_.end()) {
    389     return NULL;
    390   }
    391   Program* info = &it->second;
    392   info->Update(gl, program);
    393   return info;
    394 }
    395 
    396 void CachedProgramInfoManager::CreateInfo(GLuint program) {
    397   base::AutoLock auto_lock(lock_);
    398   program_infos_.erase(program);
    399   std::pair<ProgramInfoMap::iterator, bool> result =
    400       program_infos_.insert(std::make_pair(program, Program()));
    401 
    402   DCHECK(result.second);
    403 }
    404 
    405 void CachedProgramInfoManager::DeleteInfo(GLuint program) {
    406   base::AutoLock auto_lock(lock_);
    407   program_infos_.erase(program);
    408 }
    409 
    410 bool CachedProgramInfoManager::GetProgramiv(
    411     GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) {
    412   base::AutoLock auto_lock(lock_);
    413   Program* info = GetProgramInfo(gl, program);
    414   if (!info) {
    415     return false;
    416   }
    417   return info->GetProgramiv(pname, params);
    418 }
    419 
    420 GLint CachedProgramInfoManager::GetAttribLocation(
    421     GLES2Implementation* gl, GLuint program, const char* name) {
    422   base::AutoLock auto_lock(lock_);
    423   Program* info = GetProgramInfo(gl, program);
    424   if (info) {
    425     return info->GetAttribLocation(name);
    426   }
    427   return gl->GetAttribLocationHelper(program, name);
    428 }
    429 
    430 GLint CachedProgramInfoManager::GetUniformLocation(
    431     GLES2Implementation* gl, GLuint program, const char* name) {
    432   base::AutoLock auto_lock(lock_);
    433   Program* info = GetProgramInfo(gl, program);
    434   if (info) {
    435     return info->GetUniformLocation(name);
    436   }
    437   return gl->GetUniformLocationHelper(program, name);
    438 }
    439 
    440 bool CachedProgramInfoManager::GetActiveAttrib(
    441     GLES2Implementation* gl,
    442     GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
    443     GLint* size, GLenum* type, char* name) {
    444   base::AutoLock auto_lock(lock_);
    445   Program* info = GetProgramInfo(gl, program);
    446   if (info) {
    447     const Program::VertexAttrib* attrib_info =
    448         info->GetAttribInfo(index);
    449     if (attrib_info) {
    450       if (size) {
    451         *size = attrib_info->size;
    452       }
    453       if (type) {
    454         *type = attrib_info->type;
    455       }
    456       if (length || name) {
    457         GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
    458                                     std::max(static_cast<size_t>(0),
    459                                              attrib_info->name.size()));
    460         if (length) {
    461           *length = max_size;
    462         }
    463         if (name && bufsize > 0) {
    464           memcpy(name, attrib_info->name.c_str(), max_size);
    465           name[max_size] = '\0';
    466         }
    467       }
    468       return true;
    469     }
    470   }
    471   return gl->GetActiveAttribHelper(
    472       program, index, bufsize, length, size, type, name);
    473 }
    474 
    475 bool CachedProgramInfoManager::GetActiveUniform(
    476     GLES2Implementation* gl,
    477     GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
    478     GLint* size, GLenum* type, char* name) {
    479   base::AutoLock auto_lock(lock_);
    480   Program* info = GetProgramInfo(gl, program);
    481   if (info) {
    482     const Program::UniformInfo* uniform_info = info->GetUniformInfo(index);
    483     if (uniform_info) {
    484       if (size) {
    485         *size = uniform_info->size;
    486       }
    487       if (type) {
    488         *type = uniform_info->type;
    489       }
    490       if (length || name) {
    491         GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
    492                                     std::max(static_cast<size_t>(0),
    493                                              uniform_info->name.size()));
    494         if (length) {
    495           *length = max_size;
    496         }
    497         if (name && bufsize > 0) {
    498           memcpy(name, uniform_info->name.c_str(), max_size);
    499           name[max_size] = '\0';
    500         }
    501       }
    502       return true;
    503     }
    504   }
    505   return gl->GetActiveUniformHelper(
    506       program, index, bufsize, length, size, type, name);
    507 }
    508 
    509 ProgramInfoManager::ProgramInfoManager() {
    510 }
    511 
    512 ProgramInfoManager::~ProgramInfoManager() {
    513 }
    514 
    515 ProgramInfoManager* ProgramInfoManager::Create(
    516     bool shared_resources_across_processes) {
    517   if (shared_resources_across_processes) {
    518     return new NonCachedProgramInfoManager();
    519   } else {
    520     return new CachedProgramInfoManager();
    521   }
    522 }
    523 
    524 }  // namespace gles2
    525 }  // namespace gpu
    526 
    527