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