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.
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"
16 class NonCachedProgramInfoManager
: public ProgramInfoManager
{
18 NonCachedProgramInfoManager();
19 virtual ~NonCachedProgramInfoManager();
21 virtual void CreateInfo(GLuint program
) OVERRIDE
;
23 virtual void DeleteInfo(GLuint program
) OVERRIDE
;
25 virtual bool GetProgramiv(GLES2Implementation
* gl
,
28 GLint
* params
) OVERRIDE
;
30 virtual GLint
GetAttribLocation(GLES2Implementation
* gl
,
32 const char* name
) OVERRIDE
;
34 virtual GLint
GetUniformLocation(GLES2Implementation
* gl
,
36 const char* name
) OVERRIDE
;
38 virtual bool GetActiveAttrib(GLES2Implementation
* gl
,
47 virtual 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 virtual ~CachedProgramInfoManager();
109 virtual void CreateInfo(GLuint program
) OVERRIDE
;
111 virtual void DeleteInfo(GLuint program
) OVERRIDE
;
113 virtual bool GetProgramiv(GLES2Implementation
* gl
,
116 GLint
* params
) OVERRIDE
;
118 virtual GLint
GetAttribLocation(GLES2Implementation
* gl
,
120 const char* name
) OVERRIDE
;
122 virtual GLint
GetUniformLocation(GLES2Implementation
* gl
,
124 const char* name
) OVERRIDE
;
126 virtual bool GetActiveAttrib(GLES2Implementation
* gl
,
133 char* name
) OVERRIDE
;
135 virtual 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_
;
226 CachedProgramInfoManager::Program::UniformInfo::UniformInfo(
227 GLsizei _size
, GLenum _type
, const std::string
& _name
)
231 is_array
= (!name
.empty() && name
[name
.size() - 1] == ']');
232 GPU_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 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;
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 GPU_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 ProgramInfoMap::iterator it
= program_infos_
.find(program
);
386 if (it
== program_infos_
.end()) {
389 Program
* info
= &it
->second
;
390 info
->Update(gl
, program
);
394 void CachedProgramInfoManager::CreateInfo(GLuint program
) {
395 AutoLock
auto_lock(lock_
);
397 std::pair
<ProgramInfoMap::iterator
, bool> result
=
398 program_infos_
.insert(std::make_pair(program
, Program()));
400 GPU_DCHECK(result
.second
);
403 void CachedProgramInfoManager::DeleteInfo(GLuint program
) {
404 program_infos_
.erase(program
);
407 bool CachedProgramInfoManager::GetProgramiv(
408 GLES2Implementation
* gl
, GLuint program
, GLenum pname
, GLint
* params
) {
409 AutoLock
auto_lock(lock_
);
410 Program
* info
= GetProgramInfo(gl
, program
);
414 return info
->GetProgramiv(pname
, params
);
417 GLint
CachedProgramInfoManager::GetAttribLocation(
418 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
419 AutoLock
auto_lock(lock_
);
420 Program
* info
= GetProgramInfo(gl
, program
);
422 return info
->GetAttribLocation(name
);
424 return gl
->GetAttribLocationHelper(program
, name
);
427 GLint
CachedProgramInfoManager::GetUniformLocation(
428 GLES2Implementation
* gl
, GLuint program
, const char* name
) {
429 AutoLock
auto_lock(lock_
);
430 Program
* info
= GetProgramInfo(gl
, program
);
432 return info
->GetUniformLocation(name
);
434 return gl
->GetUniformLocationHelper(program
, name
);
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
);
444 const Program::VertexAttrib
* attrib_info
=
445 info
->GetAttribInfo(index
);
448 *size
= attrib_info
->size
;
451 *type
= attrib_info
->type
;
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()));
460 if (name
&& bufsize
> 0) {
461 memcpy(name
, attrib_info
->name
.c_str(), max_size
);
462 name
[max_size
] = '\0';
468 return gl
->GetActiveAttribHelper(
469 program
, index
, bufsize
, length
, size
, type
, name
);
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
);
479 const Program::UniformInfo
* uniform_info
= info
->GetUniformInfo(index
);
482 *size
= uniform_info
->size
;
485 *type
= uniform_info
->type
;
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()));
494 if (name
&& bufsize
> 0) {
495 memcpy(name
, uniform_info
->name
.c_str(), max_size
);
496 name
[max_size
] = '\0';
502 return gl
->GetActiveUniformHelper(
503 program
, index
, bufsize
, length
, size
, type
, name
);
506 ProgramInfoManager::ProgramInfoManager() {
509 ProgramInfoManager::~ProgramInfoManager() {
512 ProgramInfoManager
* ProgramInfoManager::Create(
513 bool shared_resources_across_processes
) {
514 if (shared_resources_across_processes
) {
515 return new NonCachedProgramInfoManager();
517 return new CachedProgramInfoManager();