OLD | NEW |
1 // Copyright (c) 2011 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. | |
4 | 1 |
5 #include "../client/program_info_manager.h" | |
6 #include "../client/gles2_implementation.h" | |
7 | |
8 #include <map> | |
9 | |
10 namespace gpu { | |
11 namespace gles2 { | |
12 | |
13 class NonCachedProgramInfoManager : public ProgramInfoManager { | |
14 public: | |
15 NonCachedProgramInfoManager(); | |
16 virtual ~NonCachedProgramInfoManager(); | |
17 | |
18 virtual void CreateInfo(GLuint program); | |
19 | |
20 virtual void DeleteInfo(GLuint program); | |
21 | |
22 virtual bool GetProgramiv( | |
23 GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params); | |
24 | |
25 virtual GLint GetAttribLocation( | |
26 GLES2Implementation* gl, GLuint program, const char* name); | |
27 | |
28 virtual GLint GetUniformLocation( | |
29 GLES2Implementation* gl, GLuint program, const char* name); | |
30 | |
31 virtual bool GetActiveAttrib( | |
32 GLES2Implementation* gl, | |
33 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, | |
34 GLint* size, GLenum* type, char* name); | |
35 | |
36 virtual bool GetActiveUniform( | |
37 GLES2Implementation* gl, | |
38 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, | |
39 GLint* size, GLenum* type, char* name); | |
40 | |
41 }; | |
42 | |
43 NonCachedProgramInfoManager::NonCachedProgramInfoManager() { | |
44 } | |
45 | |
46 NonCachedProgramInfoManager::~NonCachedProgramInfoManager() { | |
47 } | |
48 | |
49 void NonCachedProgramInfoManager::CreateInfo(GLuint /* program */) { | |
50 } | |
51 | |
52 void NonCachedProgramInfoManager::DeleteInfo(GLuint /* program */) { | |
53 } | |
54 | |
55 bool NonCachedProgramInfoManager::GetProgramiv( | |
56 GLES2Implementation* /* gl */, | |
57 GLuint /* program */, | |
58 GLenum /* pname */, | |
59 GLint* /* params */) { | |
60 return false; | |
61 } | |
62 | |
63 GLint NonCachedProgramInfoManager::GetAttribLocation( | |
64 GLES2Implementation* gl, GLuint program, const char* name) { | |
65 return gl->GetAttribLocationHelper(program, name); | |
66 } | |
67 | |
68 GLint NonCachedProgramInfoManager::GetUniformLocation( | |
69 GLES2Implementation* gl, GLuint program, const char* name) { | |
70 return gl->GetUniformLocationHelper(program, name); | |
71 } | |
72 | |
73 bool NonCachedProgramInfoManager::GetActiveAttrib( | |
74 GLES2Implementation* gl, | |
75 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, | |
76 GLint* size, GLenum* type, char* name) { | |
77 return gl->GetActiveAttribHelper( | |
78 program, index, bufsize, length, size, type, name); | |
79 } | |
80 | |
81 bool NonCachedProgramInfoManager::GetActiveUniform( | |
82 GLES2Implementation* gl, | |
83 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, | |
84 GLint* size, GLenum* type, char* name) { | |
85 return gl->GetActiveUniformHelper( | |
86 program, index, bufsize, length, size, type, name); | |
87 } | |
88 | |
89 class CachedProgramInfoManager : public ProgramInfoManager { | |
90 public: | |
91 CachedProgramInfoManager(); | |
92 virtual ~CachedProgramInfoManager(); | |
93 | |
94 virtual void CreateInfo(GLuint program); | |
95 | |
96 virtual void DeleteInfo(GLuint program); | |
97 | |
98 virtual bool GetProgramiv( | |
99 GLES2Implementation* gl, | |
100 GLuint program, GLenum pname, GLint* params); | |
101 | |
102 virtual GLint GetAttribLocation( | |
103 GLES2Implementation* gl, GLuint program, const char* name); | |
104 | |
105 virtual GLint GetUniformLocation( | |
106 GLES2Implementation* gl, GLuint program, const char* name); | |
107 | |
108 virtual bool GetActiveAttrib( | |
109 GLES2Implementation* gl, | |
110 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, | |
111 GLint* size, GLenum* type, char* name); | |
112 | |
113 virtual bool GetActiveUniform( | |
114 GLES2Implementation* gl, | |
115 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, | |
116 GLint* size, GLenum* type, char* name); | |
117 | |
118 private: | |
119 class ProgramInfo { | |
120 public: | |
121 struct UniformInfo { | |
122 UniformInfo(GLsizei _size, GLenum _type, const std::string& _name); | |
123 | |
124 GLsizei size; | |
125 GLenum type; | |
126 bool is_array; | |
127 std::string name; | |
128 std::vector<GLint> element_locations; | |
129 }; | |
130 struct VertexAttribInfo { | |
131 VertexAttribInfo(GLsizei _size, GLenum _type, const std::string& _name, | |
132 GLint _location) | |
133 : size(_size), | |
134 type(_type), | |
135 location(_location), | |
136 name(_name) { | |
137 } | |
138 GLsizei size; | |
139 GLenum type; | |
140 GLint location; | |
141 std::string name; | |
142 }; | |
143 | |
144 typedef std::vector<UniformInfo> UniformInfoVector; | |
145 typedef std::vector<VertexAttribInfo> AttribInfoVector; | |
146 | |
147 ProgramInfo(); | |
148 | |
149 const AttribInfoVector& GetAttribInfos() const { | |
150 return attrib_infos_; | |
151 } | |
152 | |
153 const VertexAttribInfo* GetAttribInfo(GLint index) const { | |
154 return (static_cast<size_t>(index) < attrib_infos_.size()) ? | |
155 &attrib_infos_[index] : NULL; | |
156 } | |
157 | |
158 GLint GetAttribLocation(const std::string& name) const; | |
159 | |
160 const UniformInfo* GetUniformInfo(GLint index) const { | |
161 return (static_cast<size_t>(index) < uniform_infos_.size()) ? | |
162 &uniform_infos_[index] : NULL; | |
163 } | |
164 | |
165 // Gets the location of a uniform by name. | |
166 GLint GetUniformLocation(const std::string& name) const; | |
167 | |
168 bool GetProgramiv(GLenum pname, GLint* params); | |
169 | |
170 // Updates the program info after a successful link. | |
171 void Update(GLES2Implementation* gl, GLuint program); | |
172 | |
173 private: | |
174 bool cached_; | |
175 | |
176 GLsizei max_attrib_name_length_; | |
177 | |
178 // Attrib by index. | |
179 AttribInfoVector attrib_infos_; | |
180 | |
181 GLsizei max_uniform_name_length_; | |
182 | |
183 // Uniform info by index. | |
184 UniformInfoVector uniform_infos_; | |
185 | |
186 // This is true if glLinkProgram was successful last time it was called. | |
187 bool link_status_; | |
188 }; | |
189 | |
190 ProgramInfo* GetProgramInfo(GLES2Implementation* gl, GLuint program); | |
191 | |
192 // TODO(gman): Switch to a faster container. | |
193 typedef std::map<GLuint, ProgramInfo> ProgramInfoMap; | |
194 | |
195 ProgramInfoMap program_infos_; | |
196 }; | |
197 | |
198 CachedProgramInfoManager::ProgramInfo::UniformInfo::UniformInfo( | |
199 GLsizei _size, GLenum _type, const std::string& _name) | |
200 : size(_size), | |
201 type(_type), | |
202 name(_name) { | |
203 is_array = (!name.empty() && name[name.size() - 1] == ']'); | |
204 GPU_DCHECK(!(size > 1 && !is_array)); | |
205 } | |
206 | |
207 CachedProgramInfoManager::ProgramInfo::ProgramInfo() | |
208 : cached_(false), | |
209 max_attrib_name_length_(0), | |
210 max_uniform_name_length_(0), | |
211 link_status_(false) { | |
212 } | |
213 | |
214 // TODO(gman): Add a faster lookup. | |
215 GLint CachedProgramInfoManager::ProgramInfo::GetAttribLocation( | |
216 const std::string& name) const { | |
217 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) { | |
218 const VertexAttribInfo& info = attrib_infos_[ii]; | |
219 if (info.name == name) { | |
220 return info.location; | |
221 } | |
222 } | |
223 return -1; | |
224 } | |
225 | |
226 // TODO(gman): Add a faster lookup. | |
227 GLint CachedProgramInfoManager::ProgramInfo::GetUniformLocation( | |
228 const std::string& name) const { | |
229 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) { | |
230 const UniformInfo& info = uniform_infos_[ii]; | |
231 if (info.name == name || | |
232 (info.is_array && | |
233 info.name.compare(0, info.name.size() - 3, name) == 0)) { | |
234 return info.element_locations[0]; | |
235 } else if (info.is_array && | |
236 name.size() >= 3 && name[name.size() - 1] == ']') { | |
237 // Look for an array specification. | |
238 size_t open_pos = name.find_last_of('['); | |
239 if (open_pos != std::string::npos && | |
240 open_pos < name.size() - 2 && | |
241 info.name.size() > open_pos && | |
242 name.compare(0, open_pos, info.name, 0, open_pos) == 0) { | |
243 GLint index = 0; | |
244 size_t last = name.size() - 1; | |
245 bool bad = false; | |
246 for (size_t pos = open_pos + 1; pos < last; ++pos) { | |
247 int8 digit = name[pos] - '0'; | |
248 if (digit < 0 || digit > 9) { | |
249 bad = true; | |
250 break; | |
251 } | |
252 index = index * 10 + digit; | |
253 } | |
254 if (!bad && index >= 0 && index < info.size) { | |
255 return info.element_locations[index]; | |
256 } | |
257 } | |
258 } | |
259 } | |
260 return -1; | |
261 } | |
262 | |
263 bool CachedProgramInfoManager::ProgramInfo::GetProgramiv( | |
264 GLenum pname, GLint* params) { | |
265 switch (pname) { | |
266 case GL_LINK_STATUS: | |
267 *params = link_status_; | |
268 return true; | |
269 case GL_ACTIVE_ATTRIBUTES: | |
270 *params = attrib_infos_.size(); | |
271 return true; | |
272 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: | |
273 *params = max_attrib_name_length_; | |
274 return true; | |
275 case GL_ACTIVE_UNIFORMS: | |
276 *params = uniform_infos_.size(); | |
277 return true; | |
278 case GL_ACTIVE_UNIFORM_MAX_LENGTH: | |
279 *params = max_uniform_name_length_; | |
280 return true; | |
281 default: | |
282 break; | |
283 } | |
284 return false; | |
285 } | |
286 | |
287 template<typename T> static T LocalGetAs( | |
288 const std::vector<int8>& data, uint32 offset, size_t size) { | |
289 const int8* p = &data[0] + offset; | |
290 if (offset + size > data.size()) { | |
291 GPU_NOTREACHED(); | |
292 return NULL; | |
293 } | |
294 return static_cast<T>(static_cast<const void*>(p)); | |
295 } | |
296 | |
297 void CachedProgramInfoManager::ProgramInfo::Update( | |
298 GLES2Implementation* gl, GLuint program) { | |
299 if (cached_) { | |
300 return; | |
301 } | |
302 std::vector<int8> result; | |
303 gl->GetProgramInfoCHROMIUMHelper(program, &result); | |
304 if (result.empty()) { | |
305 // This should only happen on a lost context. | |
306 return; | |
307 } | |
308 GPU_DCHECK_GE(result.size(), sizeof(ProgramInfoHeader)); | |
309 const ProgramInfoHeader* header = LocalGetAs<const ProgramInfoHeader*>( | |
310 result, 0, sizeof(header)); | |
311 link_status_ = header->link_status != 0; | |
312 if (!link_status_) { | |
313 return; | |
314 } | |
315 attrib_infos_.clear(); | |
316 uniform_infos_.clear(); | |
317 max_attrib_name_length_ = 0; | |
318 max_uniform_name_length_ = 0; | |
319 const ProgramInput* inputs = LocalGetAs<const ProgramInput*>( | |
320 result, sizeof(*header), | |
321 sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms)); | |
322 const ProgramInput* input = inputs; | |
323 for (uint32 ii = 0; ii < header->num_attribs; ++ii) { | |
324 const int32* location = LocalGetAs<const int32*>( | |
325 result, input->location_offset, sizeof(int32)); | |
326 const char* name_buf = LocalGetAs<const char*>( | |
327 result, input->name_offset, input->name_length); | |
328 std::string name(name_buf, input->name_length); | |
329 attrib_infos_.push_back( | |
330 VertexAttribInfo(input->size, input->type, name, *location)); | |
331 max_attrib_name_length_ = std::max( | |
332 static_cast<GLsizei>(name.size() + 1), max_attrib_name_length_); | |
333 ++input; | |
334 } | |
335 for (uint32 ii = 0; ii < header->num_uniforms; ++ii) { | |
336 const int32* locations = LocalGetAs<const int32*>( | |
337 result, input->location_offset, sizeof(int32) * input->size); | |
338 const char* name_buf = LocalGetAs<const char*>( | |
339 result, input->name_offset, input->name_length); | |
340 std::string name(name_buf, input->name_length); | |
341 UniformInfo info(input->size, input->type, name); | |
342 max_uniform_name_length_ = std::max( | |
343 static_cast<GLsizei>(name.size() + 1), max_uniform_name_length_); | |
344 for (int32 jj = 0; jj < input->size; ++jj) { | |
345 info.element_locations.push_back(locations[jj]); | |
346 } | |
347 uniform_infos_.push_back(info); | |
348 ++input; | |
349 } | |
350 GPU_DCHECK_EQ(header->num_attribs + header->num_uniforms, | |
351 static_cast<uint32>(input - inputs)); | |
352 cached_ = true; | |
353 } | |
354 | |
355 CachedProgramInfoManager::CachedProgramInfoManager() { | |
356 } | |
357 | |
358 CachedProgramInfoManager::~CachedProgramInfoManager() { | |
359 | |
360 } | |
361 | |
362 CachedProgramInfoManager::ProgramInfo* | |
363 CachedProgramInfoManager::GetProgramInfo( | |
364 GLES2Implementation* gl, GLuint program) { | |
365 ProgramInfoMap::iterator it = program_infos_.find(program); | |
366 if (it == program_infos_.end()) { | |
367 return NULL; | |
368 } | |
369 ProgramInfo* info = &it->second; | |
370 info->Update(gl, program); | |
371 return info; | |
372 } | |
373 | |
374 void CachedProgramInfoManager::CreateInfo(GLuint program) { | |
375 DeleteInfo(program); | |
376 std::pair<ProgramInfoMap::iterator, bool> result = | |
377 program_infos_.insert(std::make_pair(program, ProgramInfo())); | |
378 | |
379 GPU_DCHECK(result.second); | |
380 } | |
381 | |
382 void CachedProgramInfoManager::DeleteInfo(GLuint program) { | |
383 program_infos_.erase(program); | |
384 } | |
385 | |
386 bool CachedProgramInfoManager::GetProgramiv( | |
387 GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) { | |
388 ProgramInfo* info = GetProgramInfo(gl, program); | |
389 if (!info) { | |
390 return false; | |
391 } | |
392 return info->GetProgramiv(pname, params); | |
393 } | |
394 | |
395 GLint CachedProgramInfoManager::GetAttribLocation( | |
396 GLES2Implementation* gl, GLuint program, const char* name) { | |
397 ProgramInfo* info = GetProgramInfo(gl, program); | |
398 if (info) { | |
399 return info->GetAttribLocation(name); | |
400 } | |
401 return gl->GetAttribLocationHelper(program, name); | |
402 } | |
403 | |
404 GLint CachedProgramInfoManager::GetUniformLocation( | |
405 GLES2Implementation* gl, GLuint program, const char* name) { | |
406 ProgramInfo* info = GetProgramInfo(gl, program); | |
407 if (info) { | |
408 return info->GetUniformLocation(name); | |
409 } | |
410 return gl->GetUniformLocationHelper(program, name); | |
411 } | |
412 | |
413 bool CachedProgramInfoManager::GetActiveAttrib( | |
414 GLES2Implementation* gl, | |
415 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, | |
416 GLint* size, GLenum* type, char* name) { | |
417 ProgramInfo* info = GetProgramInfo(gl, program); | |
418 if (info) { | |
419 const ProgramInfo::VertexAttribInfo* attrib_info = | |
420 info->GetAttribInfo(index); | |
421 if (attrib_info) { | |
422 if (size) { | |
423 *size = attrib_info->size; | |
424 } | |
425 if (type) { | |
426 *type = attrib_info->type; | |
427 } | |
428 if (length || name) { | |
429 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1, | |
430 std::max(static_cast<size_t>(0), | |
431 attrib_info->name.size())); | |
432 if (length) { | |
433 *length = max_size; | |
434 } | |
435 if (name && bufsize > 0) { | |
436 memcpy(name, attrib_info->name.c_str(), max_size); | |
437 name[max_size] = '\0'; | |
438 } | |
439 } | |
440 return true; | |
441 } | |
442 } | |
443 return gl->GetActiveAttribHelper( | |
444 program, index, bufsize, length, size, type, name); | |
445 } | |
446 | |
447 bool CachedProgramInfoManager::GetActiveUniform( | |
448 GLES2Implementation* gl, | |
449 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, | |
450 GLint* size, GLenum* type, char* name) { | |
451 ProgramInfo* info = GetProgramInfo(gl, program); | |
452 if (info) { | |
453 const ProgramInfo::UniformInfo* uniform_info = info->GetUniformInfo(index); | |
454 if (uniform_info) { | |
455 if (size) { | |
456 *size = uniform_info->size; | |
457 } | |
458 if (type) { | |
459 *type = uniform_info->type; | |
460 } | |
461 if (length || name) { | |
462 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1, | |
463 std::max(static_cast<size_t>(0), | |
464 uniform_info->name.size())); | |
465 if (length) { | |
466 *length = max_size; | |
467 } | |
468 if (name && bufsize > 0) { | |
469 memcpy(name, uniform_info->name.c_str(), max_size); | |
470 name[max_size] = '\0'; | |
471 } | |
472 } | |
473 return true; | |
474 } | |
475 } | |
476 return gl->GetActiveUniformHelper( | |
477 program, index, bufsize, length, size, type, name); | |
478 } | |
479 | |
480 ProgramInfoManager::ProgramInfoManager() { | |
481 } | |
482 | |
483 ProgramInfoManager::~ProgramInfoManager() { | |
484 } | |
485 | |
486 ProgramInfoManager* ProgramInfoManager::Create(bool shared_resources) { | |
487 if (shared_resources) { | |
488 return new NonCachedProgramInfoManager(); | |
489 } else { | |
490 return new CachedProgramInfoManager(); | |
491 } | |
492 } | |
493 | |
494 } // namespace gles2 | |
495 } // namespace gpu | |
496 | |
OLD | NEW |