Roll leveldb 3f7758:803d69 (v1.17 -> v1.18)
[chromium-blink-merge.git] / gpu / command_buffer / client / program_info_manager.cc
blobc0f8600aa87567360a93116217f01e229c93173d
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"
7 #include <map>
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"
14 namespace gpu {
15 namespace gles2 {
17 class NonCachedProgramInfoManager : public ProgramInfoManager {
18 public:
19 NonCachedProgramInfoManager();
20 ~NonCachedProgramInfoManager() override;
22 void CreateInfo(GLuint program) override;
24 void DeleteInfo(GLuint program) override;
26 bool GetProgramiv(GLES2Implementation* gl,
27 GLuint program,
28 GLenum pname,
29 GLint* params) override;
31 GLint GetAttribLocation(GLES2Implementation* gl,
32 GLuint program,
33 const char* name) override;
35 GLint GetUniformLocation(GLES2Implementation* gl,
36 GLuint program,
37 const char* name) override;
39 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;
48 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;
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 */,
72 GLuint /* program */,
73 GLenum /* pname */,
74 GLint* /* params */) {
75 return false;
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 {
105 public:
106 CachedProgramInfoManager();
107 ~CachedProgramInfoManager() override;
109 void CreateInfo(GLuint program) override;
111 void DeleteInfo(GLuint program) override;
113 bool GetProgramiv(GLES2Implementation* gl,
114 GLuint program,
115 GLenum pname,
116 GLint* params) override;
118 GLint GetAttribLocation(GLES2Implementation* gl,
119 GLuint program,
120 const char* name) override;
122 GLint GetUniformLocation(GLES2Implementation* gl,
123 GLuint program,
124 const char* name) override;
126 bool GetActiveAttrib(GLES2Implementation* gl,
127 GLuint program,
128 GLuint index,
129 GLsizei bufsize,
130 GLsizei* length,
131 GLint* size,
132 GLenum* type,
133 char* name) override;
135 bool GetActiveUniform(GLES2Implementation* gl,
136 GLuint program,
137 GLuint index,
138 GLsizei bufsize,
139 GLsizei* length,
140 GLint* size,
141 GLenum* type,
142 char* name) override;
144 private:
145 class Program {
146 public:
147 struct UniformInfo {
148 UniformInfo(GLsizei _size, GLenum _type, const std::string& _name);
150 GLsizei size;
151 GLenum type;
152 bool is_array;
153 std::string name;
154 std::vector<GLint> element_locations;
156 struct VertexAttrib {
157 VertexAttrib(GLsizei _size, GLenum _type, const std::string& _name,
158 GLint _location)
159 : size(_size),
160 type(_type),
161 location(_location),
162 name(_name) {
164 GLsizei size;
165 GLenum type;
166 GLint location;
167 std::string name;
170 typedef std::vector<UniformInfo> UniformInfoVector;
171 typedef std::vector<VertexAttrib> AttribInfoVector;
173 Program();
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);
199 private:
200 bool cached_;
202 GLsizei max_attrib_name_length_;
204 // Attrib by index.
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.
213 bool link_status_;
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)
228 : size(_size),
229 type(_type),
230 name(_name) {
231 is_array = (!name.empty() && name[name.size() - 1] == ']');
232 DCHECK(!(size > 1 && !is_array));
235 CachedProgramInfoManager::Program::Program()
236 : cached_(false),
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;
251 return -1;
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;
258 int index = 0;
259 if (!GLES2Util::ParseUniformName(
260 name, &open_pos, &index, &getting_array_location)) {
261 return -1;
263 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
264 const UniformInfo& info = uniform_infos_[ii];
265 if (info.name == name ||
266 (info.is_array &&
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];
280 return -1;
283 bool CachedProgramInfoManager::Program::GetProgramiv(
284 GLenum pname, GLint* params) {
285 switch (pname) {
286 case GL_LINK_STATUS:
287 *params = link_status_;
288 return true;
289 case GL_ACTIVE_ATTRIBUTES:
290 *params = attrib_infos_.size();
291 return true;
292 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
293 *params = max_attrib_name_length_;
294 return true;
295 case GL_ACTIVE_UNIFORMS:
296 *params = uniform_infos_.size();
297 return true;
298 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
299 *params = max_uniform_name_length_;
300 return true;
301 default:
302 break;
304 return false;
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()) {
311 NOTREACHED();
312 return NULL;
314 return static_cast<T>(static_cast<const void*>(p));
317 void CachedProgramInfoManager::Program::Update(
318 GLES2Implementation* gl, GLuint program) {
319 if (cached_) {
320 return;
322 std::vector<int8> result;
323 gl->GetProgramInfoCHROMIUMHelper(program, &result);
324 if (result.empty()) {
325 // This should only happen on a lost context.
326 return;
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;
332 if (!link_status_) {
333 return;
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_);
353 ++input;
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);
368 ++input;
370 DCHECK_EQ(header->num_attribs + header->num_uniforms,
371 static_cast<uint32>(input - inputs));
372 cached_ = true;
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()) {
388 return NULL;
390 Program* info = &it->second;
391 info->Update(gl, program);
392 return info;
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);
413 if (!info) {
414 return false;
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);
423 if (info) {
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);
433 if (info) {
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);
445 if (info) {
446 const Program::VertexAttrib* attrib_info =
447 info->GetAttribInfo(index);
448 if (attrib_info) {
449 if (size) {
450 *size = attrib_info->size;
452 if (type) {
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()));
459 if (length) {
460 *length = max_size;
462 if (name && bufsize > 0) {
463 memcpy(name, attrib_info->name.c_str(), max_size);
464 name[max_size] = '\0';
467 return true;
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);
480 if (info) {
481 const Program::UniformInfo* uniform_info = info->GetUniformInfo(index);
482 if (uniform_info) {
483 if (size) {
484 *size = uniform_info->size;
486 if (type) {
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()));
493 if (length) {
494 *length = max_size;
496 if (name && bufsize > 0) {
497 memcpy(name, uniform_info->name.c_str(), max_size);
498 name[max_size] = '\0';
501 return true;
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();
518 } else {
519 return new CachedProgramInfoManager();
523 } // namespace gles2
524 } // namespace gpu