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.
5 #include "gpu/command_buffer/client/program_info_manager.h"
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"
17 class NonCachedProgramInfoManager
: public ProgramInfoManager
{
19 NonCachedProgramInfoManager();
20 virtual ~NonCachedProgramInfoManager();
22 virtual void CreateInfo(GLuint program
) OVERRIDE
;
24 virtual void DeleteInfo(GLuint program
) OVERRIDE
;
26 virtual bool GetProgramiv(GLES2Implementation
* gl
,
29 GLint
* params
) OVERRIDE
;
31 virtual GLint
GetAttribLocation(GLES2Implementation
* gl
,
33 const char* name
) OVERRIDE
;
35 virtual GLint
GetUniformLocation(GLES2Implementation
* gl
,
37 const char* name
) OVERRIDE
;
39 virtual bool GetActiveAttrib(GLES2Implementation
* gl
,
48 virtual bool GetActiveUniform(GLES2Implementation
* gl
,
59 NonCachedProgramInfoManager::NonCachedProgramInfoManager() {
62 NonCachedProgramInfoManager::~NonCachedProgramInfoManager() {
65 void NonCachedProgramInfoManager::CreateInfo(GLuint
/* program */) {
68 void NonCachedProgramInfoManager::DeleteInfo(GLuint
/* program */) {
71 bool NonCachedProgramInfoManager::GetProgramiv(
72 GLES2Implementation
* /* gl */,
75 GLint
* /* params */) {
79 GLint
NonCachedProgramInfoManager::GetAttribLocation(
80 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
81 return gl
->GetAttribLocationHelper(program
, name
);
84 GLint
NonCachedProgramInfoManager::GetUniformLocation(
85 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
86 return gl
->GetUniformLocationHelper(program
, 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
);
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
);
105 class CachedProgramInfoManager
: public ProgramInfoManager
{
107 CachedProgramInfoManager();
108 virtual ~CachedProgramInfoManager();
110 virtual void CreateInfo(GLuint program
) OVERRIDE
;
112 virtual void DeleteInfo(GLuint program
) OVERRIDE
;
114 virtual bool GetProgramiv(GLES2Implementation
* gl
,
117 GLint
* params
) OVERRIDE
;
119 virtual GLint
GetAttribLocation(GLES2Implementation
* gl
,
121 const char* name
) OVERRIDE
;
123 virtual GLint
GetUniformLocation(GLES2Implementation
* gl
,
125 const char* name
) OVERRIDE
;
127 virtual bool GetActiveAttrib(GLES2Implementation
* gl
,
134 char* name
) OVERRIDE
;
136 virtual bool GetActiveUniform(GLES2Implementation
* gl
,
143 char* name
) OVERRIDE
;
149 UniformInfo(GLsizei _size
, GLenum _type
, const std::string
& _name
);
155 std::vector
<GLint
> element_locations
;
157 struct VertexAttrib
{
158 VertexAttrib(GLsizei _size
, GLenum _type
, const std::string
& _name
,
171 typedef std::vector
<UniformInfo
> UniformInfoVector
;
172 typedef std::vector
<VertexAttrib
> AttribInfoVector
;
176 const AttribInfoVector
& GetAttribInfos() const {
177 return attrib_infos_
;
180 const VertexAttrib
* GetAttribInfo(GLint index
) const {
181 return (static_cast<size_t>(index
) < attrib_infos_
.size()) ?
182 &attrib_infos_
[index
] : NULL
;
185 GLint
GetAttribLocation(const std::string
& name
) const;
187 const UniformInfo
* GetUniformInfo(GLint index
) const {
188 return (static_cast<size_t>(index
) < uniform_infos_
.size()) ?
189 &uniform_infos_
[index
] : NULL
;
192 // Gets the location of a uniform by name.
193 GLint
GetUniformLocation(const std::string
& name
) const;
195 bool GetProgramiv(GLenum pname
, GLint
* params
);
197 // Updates the program info after a successful link.
198 void Update(GLES2Implementation
* gl
, GLuint program
);
203 GLsizei max_attrib_name_length_
;
206 AttribInfoVector attrib_infos_
;
208 GLsizei max_uniform_name_length_
;
210 // Uniform info by index.
211 UniformInfoVector uniform_infos_
;
213 // This is true if glLinkProgram was successful last time it was called.
217 Program
* GetProgramInfo(GLES2Implementation
* gl
, GLuint program
);
219 // TODO(gman): Switch to a faster container.
220 typedef std::map
<GLuint
, Program
> ProgramInfoMap
;
222 ProgramInfoMap program_infos_
;
224 mutable base::Lock lock_
;
227 CachedProgramInfoManager::Program::UniformInfo::UniformInfo(
228 GLsizei _size
, GLenum _type
, const std::string
& _name
)
232 is_array
= (!name
.empty() && name
[name
.size() - 1] == ']');
233 DCHECK(!(size
> 1 && !is_array
));
236 CachedProgramInfoManager::Program::Program()
238 max_attrib_name_length_(0),
239 max_uniform_name_length_(0),
240 link_status_(false) {
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
;
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
;
260 if (!GLES2Util::ParseUniformName(
261 name
, &open_pos
, &index
, &getting_array_location
)) {
264 for (GLuint ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
265 const UniformInfo
& info
= uniform_infos_
[ii
];
266 if (info
.name
== name
||
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
];
284 bool CachedProgramInfoManager::Program::GetProgramiv(
285 GLenum pname
, GLint
* params
) {
288 *params
= link_status_
;
290 case GL_ACTIVE_ATTRIBUTES
:
291 *params
= attrib_infos_
.size();
293 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
:
294 *params
= max_attrib_name_length_
;
296 case GL_ACTIVE_UNIFORMS
:
297 *params
= uniform_infos_
.size();
299 case GL_ACTIVE_UNIFORM_MAX_LENGTH
:
300 *params
= max_uniform_name_length_
;
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()) {
315 return static_cast<T
>(static_cast<const void*>(p
));
318 void CachedProgramInfoManager::Program::Update(
319 GLES2Implementation
* gl
, GLuint program
) {
323 std::vector
<int8
> result
;
324 gl
->GetProgramInfoCHROMIUMHelper(program
, &result
);
325 if (result
.empty()) {
326 // This should only happen on a lost context.
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;
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_
);
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
]);
368 uniform_infos_
.push_back(info
);
371 DCHECK_EQ(header
->num_attribs
+ header
->num_uniforms
,
372 static_cast<uint32
>(input
- inputs
));
376 CachedProgramInfoManager::CachedProgramInfoManager() {
379 CachedProgramInfoManager::~CachedProgramInfoManager() {
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()) {
390 Program
* info
= &it
->second
;
391 info
->Update(gl
, program
);
395 void CachedProgramInfoManager::CreateInfo(GLuint program
) {
396 base::AutoLock
auto_lock(lock_
);
398 std::pair
<ProgramInfoMap::iterator
, bool> result
=
399 program_infos_
.insert(std::make_pair(program
, Program()));
401 DCHECK(result
.second
);
404 void CachedProgramInfoManager::DeleteInfo(GLuint program
) {
405 program_infos_
.erase(program
);
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
);
415 return info
->GetProgramiv(pname
, params
);
418 GLint
CachedProgramInfoManager::GetAttribLocation(
419 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
420 base::AutoLock
auto_lock(lock_
);
421 Program
* info
= GetProgramInfo(gl
, program
);
423 return info
->GetAttribLocation(name
);
425 return gl
->GetAttribLocationHelper(program
, name
);
428 GLint
CachedProgramInfoManager::GetUniformLocation(
429 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
430 base::AutoLock
auto_lock(lock_
);
431 Program
* info
= GetProgramInfo(gl
, program
);
433 return info
->GetUniformLocation(name
);
435 return gl
->GetUniformLocationHelper(program
, name
);
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
);
445 const Program::VertexAttrib
* attrib_info
=
446 info
->GetAttribInfo(index
);
449 *size
= attrib_info
->size
;
452 *type
= attrib_info
->type
;
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()));
461 if (name
&& bufsize
> 0) {
462 memcpy(name
, attrib_info
->name
.c_str(), max_size
);
463 name
[max_size
] = '\0';
469 return gl
->GetActiveAttribHelper(
470 program
, index
, bufsize
, length
, size
, type
, name
);
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
);
480 const Program::UniformInfo
* uniform_info
= info
->GetUniformInfo(index
);
483 *size
= uniform_info
->size
;
486 *type
= uniform_info
->type
;
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()));
495 if (name
&& bufsize
> 0) {
496 memcpy(name
, uniform_info
->name
.c_str(), max_size
);
497 name
[max_size
] = '\0';
503 return gl
->GetActiveUniformHelper(
504 program
, index
, bufsize
, length
, size
, type
, name
);
507 ProgramInfoManager::ProgramInfoManager() {
510 ProgramInfoManager::~ProgramInfoManager() {
513 ProgramInfoManager
* ProgramInfoManager::Create(
514 bool shared_resources_across_processes
) {
515 if (shared_resources_across_processes
) {
516 return new NonCachedProgramInfoManager();
518 return new CachedProgramInfoManager();