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 ~NonCachedProgramInfoManager() override
;
22 void CreateInfo(GLuint program
) override
;
24 void DeleteInfo(GLuint program
) override
;
26 bool GetProgramiv(GLES2Implementation
* gl
,
29 GLint
* params
) override
;
31 GLint
GetAttribLocation(GLES2Implementation
* gl
,
33 const char* name
) override
;
35 GLint
GetUniformLocation(GLES2Implementation
* gl
,
37 const char* name
) override
;
39 bool GetActiveAttrib(GLES2Implementation
* gl
,
48 bool GetActiveUniform(GLES2Implementation
* gl
,
58 NonCachedProgramInfoManager::NonCachedProgramInfoManager() {
61 NonCachedProgramInfoManager::~NonCachedProgramInfoManager() {
64 void NonCachedProgramInfoManager::CreateInfo(GLuint
/* program */) {
67 void NonCachedProgramInfoManager::DeleteInfo(GLuint
/* program */) {
70 bool NonCachedProgramInfoManager::GetProgramiv(
71 GLES2Implementation
* /* gl */,
74 GLint
* /* params */) {
78 GLint
NonCachedProgramInfoManager::GetAttribLocation(
79 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
80 return gl
->GetAttribLocationHelper(program
, name
);
83 GLint
NonCachedProgramInfoManager::GetUniformLocation(
84 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
85 return gl
->GetUniformLocationHelper(program
, name
);
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
);
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
);
104 class CachedProgramInfoManager
: public ProgramInfoManager
{
106 CachedProgramInfoManager();
107 ~CachedProgramInfoManager() override
;
109 void CreateInfo(GLuint program
) override
;
111 void DeleteInfo(GLuint program
) override
;
113 bool GetProgramiv(GLES2Implementation
* gl
,
116 GLint
* params
) override
;
118 GLint
GetAttribLocation(GLES2Implementation
* gl
,
120 const char* name
) override
;
122 GLint
GetUniformLocation(GLES2Implementation
* gl
,
124 const char* name
) override
;
126 bool GetActiveAttrib(GLES2Implementation
* gl
,
133 char* name
) override
;
135 bool GetActiveUniform(GLES2Implementation
* gl
,
142 char* name
) override
;
148 UniformInfo(GLsizei _size
, GLenum _type
, const std::string
& _name
);
154 std::vector
<GLint
> element_locations
;
156 struct VertexAttrib
{
157 VertexAttrib(GLsizei _size
, GLenum _type
, const std::string
& _name
,
170 typedef std::vector
<UniformInfo
> UniformInfoVector
;
171 typedef std::vector
<VertexAttrib
> AttribInfoVector
;
175 const AttribInfoVector
& GetAttribInfos() const {
176 return attrib_infos_
;
179 const VertexAttrib
* GetAttribInfo(GLint index
) const {
180 return (static_cast<size_t>(index
) < attrib_infos_
.size()) ?
181 &attrib_infos_
[index
] : NULL
;
184 GLint
GetAttribLocation(const std::string
& name
) const;
186 const UniformInfo
* GetUniformInfo(GLint index
) const {
187 return (static_cast<size_t>(index
) < uniform_infos_
.size()) ?
188 &uniform_infos_
[index
] : NULL
;
191 // Gets the location of a uniform by name.
192 GLint
GetUniformLocation(const std::string
& name
) const;
194 bool GetProgramiv(GLenum pname
, GLint
* params
);
196 // Updates the program info after a successful link.
197 void Update(GLES2Implementation
* gl
, GLuint program
);
202 GLsizei max_attrib_name_length_
;
205 AttribInfoVector attrib_infos_
;
207 GLsizei max_uniform_name_length_
;
209 // Uniform info by index.
210 UniformInfoVector uniform_infos_
;
212 // This is true if glLinkProgram was successful last time it was called.
216 Program
* GetProgramInfo(GLES2Implementation
* gl
, GLuint program
);
218 // TODO(gman): Switch to a faster container.
219 typedef std::map
<GLuint
, Program
> ProgramInfoMap
;
221 ProgramInfoMap program_infos_
;
223 mutable base::Lock lock_
;
226 CachedProgramInfoManager::Program::UniformInfo::UniformInfo(
227 GLsizei _size
, GLenum _type
, const std::string
& _name
)
231 is_array
= (!name
.empty() && name
[name
.size() - 1] == ']');
232 DCHECK(!(size
> 1 && !is_array
));
235 CachedProgramInfoManager::Program::Program()
237 max_attrib_name_length_(0),
238 max_uniform_name_length_(0),
239 link_status_(false) {
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
;
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
;
259 if (!GLES2Util::ParseUniformName(
260 name
, &open_pos
, &index
, &getting_array_location
)) {
263 for (GLuint ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
264 const UniformInfo
& info
= uniform_infos_
[ii
];
265 if (info
.name
== name
||
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
];
283 bool CachedProgramInfoManager::Program::GetProgramiv(
284 GLenum pname
, GLint
* params
) {
287 *params
= link_status_
;
289 case GL_ACTIVE_ATTRIBUTES
:
290 *params
= attrib_infos_
.size();
292 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
:
293 *params
= max_attrib_name_length_
;
295 case GL_ACTIVE_UNIFORMS
:
296 *params
= uniform_infos_
.size();
298 case GL_ACTIVE_UNIFORM_MAX_LENGTH
:
299 *params
= max_uniform_name_length_
;
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()) {
314 return static_cast<T
>(static_cast<const void*>(p
));
317 void CachedProgramInfoManager::Program::Update(
318 GLES2Implementation
* gl
, GLuint program
) {
322 std::vector
<int8
> result
;
323 gl
->GetProgramInfoCHROMIUMHelper(program
, &result
);
324 if (result
.empty()) {
325 // This should only happen on a lost context.
328 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;
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_
);
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
]);
367 uniform_infos_
.push_back(info
);
370 DCHECK_EQ(header
->num_attribs
+ header
->num_uniforms
,
371 static_cast<uint32
>(input
- inputs
));
375 CachedProgramInfoManager::CachedProgramInfoManager() {
378 CachedProgramInfoManager::~CachedProgramInfoManager() {
382 CachedProgramInfoManager::Program
*
383 CachedProgramInfoManager::GetProgramInfo(
384 GLES2Implementation
* gl
, GLuint program
) {
385 lock_
.AssertAcquired();
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_
);
397 program_infos_
.erase(program
);
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 base::AutoLock
auto_lock(lock_
);
406 program_infos_
.erase(program
);
409 bool CachedProgramInfoManager::GetProgramiv(
410 GLES2Implementation
* gl
, GLuint program
, GLenum pname
, GLint
* params
) {
411 base::AutoLock
auto_lock(lock_
);
412 Program
* info
= GetProgramInfo(gl
, program
);
416 return info
->GetProgramiv(pname
, params
);
419 GLint
CachedProgramInfoManager::GetAttribLocation(
420 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
421 base::AutoLock
auto_lock(lock_
);
422 Program
* info
= GetProgramInfo(gl
, program
);
424 return info
->GetAttribLocation(name
);
426 return gl
->GetAttribLocationHelper(program
, name
);
429 GLint
CachedProgramInfoManager::GetUniformLocation(
430 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
431 base::AutoLock
auto_lock(lock_
);
432 Program
* info
= GetProgramInfo(gl
, program
);
434 return info
->GetUniformLocation(name
);
436 return gl
->GetUniformLocationHelper(program
, name
);
439 bool CachedProgramInfoManager::GetActiveAttrib(
440 GLES2Implementation
* gl
,
441 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
,
442 GLint
* size
, GLenum
* type
, char* name
) {
443 base::AutoLock
auto_lock(lock_
);
444 Program
* info
= GetProgramInfo(gl
, program
);
446 const Program::VertexAttrib
* attrib_info
=
447 info
->GetAttribInfo(index
);
450 *size
= attrib_info
->size
;
453 *type
= attrib_info
->type
;
455 if (length
|| name
) {
456 GLsizei max_size
= std::min(static_cast<size_t>(bufsize
) - 1,
457 std::max(static_cast<size_t>(0),
458 attrib_info
->name
.size()));
462 if (name
&& bufsize
> 0) {
463 memcpy(name
, attrib_info
->name
.c_str(), max_size
);
464 name
[max_size
] = '\0';
470 return gl
->GetActiveAttribHelper(
471 program
, index
, bufsize
, length
, size
, type
, name
);
474 bool CachedProgramInfoManager::GetActiveUniform(
475 GLES2Implementation
* gl
,
476 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
,
477 GLint
* size
, GLenum
* type
, char* name
) {
478 base::AutoLock
auto_lock(lock_
);
479 Program
* info
= GetProgramInfo(gl
, program
);
481 const Program::UniformInfo
* uniform_info
= info
->GetUniformInfo(index
);
484 *size
= uniform_info
->size
;
487 *type
= uniform_info
->type
;
489 if (length
|| name
) {
490 GLsizei max_size
= std::min(static_cast<size_t>(bufsize
) - 1,
491 std::max(static_cast<size_t>(0),
492 uniform_info
->name
.size()));
496 if (name
&& bufsize
> 0) {
497 memcpy(name
, uniform_info
->name
.c_str(), max_size
);
498 name
[max_size
] = '\0';
504 return gl
->GetActiveUniformHelper(
505 program
, index
, bufsize
, length
, size
, type
, name
);
508 ProgramInfoManager::ProgramInfoManager() {
511 ProgramInfoManager::~ProgramInfoManager() {
514 ProgramInfoManager
* ProgramInfoManager::Create(
515 bool shared_resources_across_processes
) {
516 if (shared_resources_across_processes
) {
517 return new NonCachedProgramInfoManager();
519 return new CachedProgramInfoManager();