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 lock_
.AssertAcquired();
387 ProgramInfoMap::iterator it
= program_infos_
.find(program
);
388 if (it
== program_infos_
.end()) {
391 Program
* info
= &it
->second
;
392 info
->Update(gl
, 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()));
402 DCHECK(result
.second
);
405 void CachedProgramInfoManager::DeleteInfo(GLuint program
) {
406 base::AutoLock
auto_lock(lock_
);
407 program_infos_
.erase(program
);
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
);
417 return info
->GetProgramiv(pname
, params
);
420 GLint
CachedProgramInfoManager::GetAttribLocation(
421 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
422 base::AutoLock
auto_lock(lock_
);
423 Program
* info
= GetProgramInfo(gl
, program
);
425 return info
->GetAttribLocation(name
);
427 return gl
->GetAttribLocationHelper(program
, 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
);
435 return info
->GetUniformLocation(name
);
437 return gl
->GetUniformLocationHelper(program
, 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
);
447 const Program::VertexAttrib
* attrib_info
=
448 info
->GetAttribInfo(index
);
451 *size
= attrib_info
->size
;
454 *type
= attrib_info
->type
;
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()));
463 if (name
&& bufsize
> 0) {
464 memcpy(name
, attrib_info
->name
.c_str(), max_size
);
465 name
[max_size
] = '\0';
471 return gl
->GetActiveAttribHelper(
472 program
, index
, bufsize
, length
, size
, type
, 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
);
482 const Program::UniformInfo
* uniform_info
= info
->GetUniformInfo(index
);
485 *size
= uniform_info
->size
;
488 *type
= uniform_info
->type
;
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()));
497 if (name
&& bufsize
> 0) {
498 memcpy(name
, uniform_info
->name
.c_str(), max_size
);
499 name
[max_size
] = '\0';
505 return gl
->GetActiveUniformHelper(
506 program
, index
, bufsize
, length
, size
, type
, name
);
509 ProgramInfoManager::ProgramInfoManager() {
512 ProgramInfoManager::~ProgramInfoManager() {
515 ProgramInfoManager
* ProgramInfoManager::Create(
516 bool shared_resources_across_processes
) {
517 if (shared_resources_across_processes
) {
518 return new NonCachedProgramInfoManager();
520 return new CachedProgramInfoManager();