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   ProgramInfoMap::iterator it = program_infos_.find(program);
    387   if (it == program_infos_.end()) {
    388     return NULL;
    389   }
    390   Program* info = &it->second;
    391   info->Update(gl, program);
    392   return info;
    393 }
    394 
    395 void CachedProgramInfoManager::CreateInfo(GLuint program) {
    396   base::AutoLock auto_lock(lock_);
    397   DeleteInfo(program);
    398   std::pair<ProgramInfoMap::iterator, bool> result =
    399       program_infos_.insert(std::make_pair(program, Program()));
    400 
    401   DCHECK(result.second);
    402 }
    403 
    404 void CachedProgramInfoManager::DeleteInfo(GLuint program) {
    405   program_infos_.erase(program);
    406 }
    407 
    408 bool CachedProgramInfoManager::GetProgramiv(
    409     GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) {
    410   base::AutoLock auto_lock(lock_);
    411   Program* info = GetProgramInfo(gl, program);
    412   if (!info) {
    413     return false;
    414   }
    415   return info->GetProgramiv(pname, params);
    416 }
    417 
    418 GLint CachedProgramInfoManager::GetAttribLocation(
    419     GLES2Implementation* gl, GLuint program, const char* name) {
    420   base::AutoLock auto_lock(lock_);
    421   Program* info = GetProgramInfo(gl, program);
    422   if (info) {
    423     return info->GetAttribLocation(name);
    424   }
    425   return gl->GetAttribLocationHelper(program, name);
    426 }
    427 
    428 GLint CachedProgramInfoManager::GetUniformLocation(
    429     GLES2Implementation* gl, GLuint program, const char* name) {
    430   base::AutoLock auto_lock(lock_);
    431   Program* info = GetProgramInfo(gl, program);
    432   if (info) {
    433     return info->GetUniformLocation(name);
    434   }
    435   return gl->GetUniformLocationHelper(program, name);
    436 }
    437 
    438 bool CachedProgramInfoManager::GetActiveAttrib(
    439     GLES2Implementation* gl,
    440     GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
    441     GLint* size, GLenum* type, char* name) {
    442   base::AutoLock auto_lock(lock_);
    443   Program* info = GetProgramInfo(gl, program);
    444   if (info) {
    445     const Program::VertexAttrib* attrib_info =
    446         info->GetAttribInfo(index);
    447     if (attrib_info) {
    448       if (size) {
    449         *size = attrib_info->size;
    450       }
    451       if (type) {
    452         *type = attrib_info->type;
    453       }
    454       if (length || name) {
    455         GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
    456                                     std::max(static_cast<size_t>(0),
    457                                              attrib_info->name.size()));
    458         if (length) {
    459           *length = max_size;
    460         }
    461         if (name && bufsize > 0) {
    462           memcpy(name, attrib_info->name.c_str(), max_size);
    463           name[max_size] = '\0';
    464         }
    465       }
    466       return true;
    467     }
    468   }
    469   return gl->GetActiveAttribHelper(
    470       program, index, bufsize, length, size, type, name);
    471 }
    472 
    473 bool CachedProgramInfoManager::GetActiveUniform(
    474     GLES2Implementation* gl,
    475     GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
    476     GLint* size, GLenum* type, char* name) {
    477   base::AutoLock auto_lock(lock_);
    478   Program* info = GetProgramInfo(gl, program);
    479   if (info) {
    480     const Program::UniformInfo* uniform_info = info->GetUniformInfo(index);
    481     if (uniform_info) {
    482       if (size) {
    483         *size = uniform_info->size;
    484       }
    485       if (type) {
    486         *type = uniform_info->type;
    487       }
    488       if (length || name) {
    489         GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
    490                                     std::max(static_cast<size_t>(0),
    491                                              uniform_info->name.size()));
    492         if (length) {
    493           *length = max_size;
    494         }
    495         if (name && bufsize > 0) {
    496           memcpy(name, uniform_info->name.c_str(), max_size);
    497           name[max_size] = '\0';
    498         }
    499       }
    500       return true;
    501     }
    502   }
    503   return gl->GetActiveUniformHelper(
    504       program, index, bufsize, length, size, type, name);
    505 }
    506 
    507 ProgramInfoManager::ProgramInfoManager() {
    508 }
    509 
    510 ProgramInfoManager::~ProgramInfoManager() {
    511 }
    512 
    513 ProgramInfoManager* ProgramInfoManager::Create(
    514     bool shared_resources_across_processes) {
    515   if (shared_resources_across_processes) {
    516     return new NonCachedProgramInfoManager();
    517   } else {
    518     return new CachedProgramInfoManager();
    519   }
    520 }
    521 
    522 }  // namespace gles2
    523 }  // namespace gpu
    524 
    525