• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NonCachedProgramInfoManager()59 NonCachedProgramInfoManager::NonCachedProgramInfoManager() {
60 }
61 
~NonCachedProgramInfoManager()62 NonCachedProgramInfoManager::~NonCachedProgramInfoManager() {
63 }
64 
CreateInfo(GLuint)65 void NonCachedProgramInfoManager::CreateInfo(GLuint /* program */) {
66 }
67 
DeleteInfo(GLuint)68 void NonCachedProgramInfoManager::DeleteInfo(GLuint /* program */) {
69 }
70 
GetProgramiv(GLES2Implementation *,GLuint,GLenum,GLint *)71 bool NonCachedProgramInfoManager::GetProgramiv(
72     GLES2Implementation* /* gl */,
73     GLuint /* program */,
74     GLenum /* pname */,
75     GLint* /* params */) {
76   return false;
77 }
78 
GetAttribLocation(GLES2Implementation * gl,GLuint program,const char * name)79 GLint NonCachedProgramInfoManager::GetAttribLocation(
80     GLES2Implementation* gl, GLuint program, const char* name) {
81   return gl->GetAttribLocationHelper(program, name);
82 }
83 
GetUniformLocation(GLES2Implementation * gl,GLuint program,const char * name)84 GLint NonCachedProgramInfoManager::GetUniformLocation(
85     GLES2Implementation* gl, GLuint program, const char* name) {
86   return gl->GetUniformLocationHelper(program, name);
87 }
88 
GetActiveAttrib(GLES2Implementation * gl,GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)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 
GetActiveUniform(GLES2Implementation * gl,GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)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 {
VertexAttribgpu::gles2::CachedProgramInfoManager::Program::VertexAttrib158       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 
GetAttribInfos() const176     const AttribInfoVector& GetAttribInfos() const {
177       return attrib_infos_;
178     }
179 
GetAttribInfo(GLint index) const180     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 
GetUniformInfo(GLint index) const187     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 
UniformInfo(GLsizei _size,GLenum _type,const std::string & _name)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 
Program()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.
GetAttribLocation(const std::string & name) const244 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 
GetUniformLocation(const std::string & name) const255 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 
GetProgramiv(GLenum pname,GLint * params)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 
LocalGetAs(const std::vector<int8> & data,uint32 offset,size_t size)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 
Update(GLES2Implementation * gl,GLuint program)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 
CachedProgramInfoManager()376 CachedProgramInfoManager::CachedProgramInfoManager() {
377 }
378 
~CachedProgramInfoManager()379 CachedProgramInfoManager::~CachedProgramInfoManager() {
380 
381 }
382 
383 CachedProgramInfoManager::Program*
GetProgramInfo(GLES2Implementation * gl,GLuint 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 
CreateInfo(GLuint program)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 
DeleteInfo(GLuint program)405 void CachedProgramInfoManager::DeleteInfo(GLuint program) {
406   base::AutoLock auto_lock(lock_);
407   program_infos_.erase(program);
408 }
409 
GetProgramiv(GLES2Implementation * gl,GLuint program,GLenum pname,GLint * params)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 
GetAttribLocation(GLES2Implementation * gl,GLuint program,const char * name)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 
GetUniformLocation(GLES2Implementation * gl,GLuint program,const char * name)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 
GetActiveAttrib(GLES2Implementation * gl,GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)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 
GetActiveUniform(GLES2Implementation * gl,GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)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 
ProgramInfoManager()509 ProgramInfoManager::ProgramInfoManager() {
510 }
511 
~ProgramInfoManager()512 ProgramInfoManager::~ProgramInfoManager() {
513 }
514 
Create(bool shared_resources_across_processes)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