blob: 8b1eedea35e0f3e5ecca7a1eb7503b7357400190 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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.
4
5#include "gpu/command_buffer/service/program_manager.h"
6
7#include <algorithm>
8#include <set>
9#include <utility>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/command_line.h"
14#include "base/logging.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/metrics/histogram.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010017#include "base/strings/string_number_conversions.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010018#include "base/time/time.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000019#include "gpu/command_buffer/common/gles2_cmd_format.h"
20#include "gpu/command_buffer/common/gles2_cmd_utils.h"
21#include "gpu/command_buffer/service/feature_info.h"
22#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
23#include "gpu/command_buffer/service/gpu_switches.h"
24#include "gpu/command_buffer/service/program_cache.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000025#include "gpu/command_buffer/service/shader_manager.h"
26#include "gpu/command_buffer/service/shader_translator.h"
27#include "third_party/re2/re2/re2.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000028
29using base::TimeDelta;
30using base::TimeTicks;
31
32namespace gpu {
33namespace gles2 {
34
35namespace {
36
37int ShaderTypeToIndex(GLenum shader_type) {
38 switch (shader_type) {
39 case GL_VERTEX_SHADER:
40 return 0;
41 case GL_FRAGMENT_SHADER:
42 return 1;
43 default:
44 NOTREACHED();
45 return 0;
46 }
47}
48
49ShaderTranslator* ShaderIndexToTranslator(
50 int index,
51 ShaderTranslator* vertex_translator,
52 ShaderTranslator* fragment_translator) {
53 switch (index) {
54 case 0:
55 return vertex_translator;
56 case 1:
57 return fragment_translator;
58 default:
59 NOTREACHED();
60 return NULL;
61 }
62}
63
64// Given a name like "foo.bar[123].moo[456]" sets new_name to "foo.bar[123].moo"
65// and sets element_index to 456. returns false if element expression was not a
66// whole decimal number. For example: "foo[1b2]"
67bool GetUniformNameSansElement(
68 const std::string& name, int* element_index, std::string* new_name) {
69 DCHECK(element_index);
70 DCHECK(new_name);
71 if (name.size() < 3 || name[name.size() - 1] != ']') {
72 *element_index = 0;
73 *new_name = name;
74 return true;
75 }
76
77 // Look for an array specification.
78 size_t open_pos = name.find_last_of('[');
79 if (open_pos == std::string::npos ||
80 open_pos >= name.size() - 2) {
81 return false;
82 }
83
84 GLint index = 0;
85 size_t last = name.size() - 1;
86 for (size_t pos = open_pos + 1; pos < last; ++pos) {
87 int8 digit = name[pos] - '0';
88 if (digit < 0 || digit > 9) {
89 return false;
90 }
91 index = index * 10 + digit;
92 }
93
94 *element_index = index;
95 *new_name = name.substr(0, open_pos);
96 return true;
97}
98
99} // anonymous namespace.
100
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000101Program::UniformInfo::UniformInfo()
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000102 : size(0),
103 type(GL_NONE),
104 fake_location_base(0),
105 is_array(false) {
106}
107
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000108Program::UniformInfo::UniformInfo(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000109 GLsizei _size,
110 GLenum _type,
111 int _fake_location_base,
112 const std::string& _name)
113 : size(_size),
114 type(_type),
115 fake_location_base(_fake_location_base),
116 is_array(false),
117 name(_name) {
118}
119
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000120Program::UniformInfo::~UniformInfo() {}
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000121
122bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) {
123 static const char kInvalidPrefix[] = { 'g', 'l', '_' };
124 return (length >= sizeof(kInvalidPrefix) &&
125 memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0);
126}
127
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000128Program::Program(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000129 ProgramManager* manager, GLuint service_id)
130 : manager_(manager),
131 use_count_(0),
132 max_attrib_name_length_(0),
133 max_uniform_name_length_(0),
134 service_id_(service_id),
135 deleted_(false),
136 valid_(false),
137 link_status_(false),
138 uniforms_cleared_(false),
139 num_uniforms_(0) {
140 manager_->StartTracking(this);
141}
142
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000143void Program::Reset() {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000144 valid_ = false;
145 link_status_ = false;
146 num_uniforms_ = 0;
147 max_uniform_name_length_ = 0;
148 max_attrib_name_length_ = 0;
149 attrib_infos_.clear();
150 uniform_infos_.clear();
151 sampler_indices_.clear();
152 attrib_location_to_index_map_.clear();
153}
154
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000155std::string Program::ProcessLogInfo(
156 const std::string& log) {
157 std::string output;
158 re2::StringPiece input(log);
159 std::string prior_log;
160 std::string hashed_name;
161 while (RE2::Consume(&input,
162 "(.*)(webgl_[0123456789abcdefABCDEF]+)",
163 &prior_log,
164 &hashed_name)) {
165 output += prior_log;
166
167 const std::string* original_name =
168 GetOriginalNameFromHashedName(hashed_name);
169 if (original_name)
170 output += *original_name;
171 else
172 output += hashed_name;
173 }
174
175 return output + input.as_string();
176}
177
178void Program::UpdateLogInfo() {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000179 GLint max_len = 0;
180 glGetProgramiv(service_id_, GL_INFO_LOG_LENGTH, &max_len);
181 if (max_len == 0) {
182 set_log_info(NULL);
183 return;
184 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100185 scoped_ptr<char[]> temp(new char[max_len]);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000186 GLint len = 0;
187 glGetProgramInfoLog(service_id_, max_len, &len, temp.get());
188 DCHECK(max_len == 0 || len < max_len);
189 DCHECK(len == 0 || temp[len] == '\0');
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000190 std::string log(temp.get(), len);
191 set_log_info(ProcessLogInfo(log).c_str());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000192}
193
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000194void Program::ClearUniforms(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000195 std::vector<uint8>* zero_buffer) {
196 DCHECK(zero_buffer);
197 if (uniforms_cleared_) {
198 return;
199 }
200 uniforms_cleared_ = true;
201 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
202 const UniformInfo& uniform_info = uniform_infos_[ii];
203 if (!uniform_info.IsValid()) {
204 continue;
205 }
206 GLint location = uniform_info.element_locations[0];
207 GLsizei size = uniform_info.size;
208 uint32 unit_size = GLES2Util::GetGLDataTypeSizeForUniforms(
209 uniform_info.type);
210 uint32 size_needed = size * unit_size;
211 if (size_needed > zero_buffer->size()) {
212 zero_buffer->resize(size_needed, 0u);
213 }
214 const void* zero = &(*zero_buffer)[0];
215 switch (uniform_info.type) {
216 case GL_FLOAT:
217 glUniform1fv(location, size, reinterpret_cast<const GLfloat*>(zero));
218 break;
219 case GL_FLOAT_VEC2:
220 glUniform2fv(location, size, reinterpret_cast<const GLfloat*>(zero));
221 break;
222 case GL_FLOAT_VEC3:
223 glUniform3fv(location, size, reinterpret_cast<const GLfloat*>(zero));
224 break;
225 case GL_FLOAT_VEC4:
226 glUniform4fv(location, size, reinterpret_cast<const GLfloat*>(zero));
227 break;
228 case GL_INT:
229 case GL_BOOL:
230 case GL_SAMPLER_2D:
231 case GL_SAMPLER_CUBE:
232 case GL_SAMPLER_EXTERNAL_OES:
233 case GL_SAMPLER_3D_OES:
234 case GL_SAMPLER_2D_RECT_ARB:
235 glUniform1iv(location, size, reinterpret_cast<const GLint*>(zero));
236 break;
237 case GL_INT_VEC2:
238 case GL_BOOL_VEC2:
239 glUniform2iv(location, size, reinterpret_cast<const GLint*>(zero));
240 break;
241 case GL_INT_VEC3:
242 case GL_BOOL_VEC3:
243 glUniform3iv(location, size, reinterpret_cast<const GLint*>(zero));
244 break;
245 case GL_INT_VEC4:
246 case GL_BOOL_VEC4:
247 glUniform4iv(location, size, reinterpret_cast<const GLint*>(zero));
248 break;
249 case GL_FLOAT_MAT2:
250 glUniformMatrix2fv(
251 location, size, false, reinterpret_cast<const GLfloat*>(zero));
252 break;
253 case GL_FLOAT_MAT3:
254 glUniformMatrix3fv(
255 location, size, false, reinterpret_cast<const GLfloat*>(zero));
256 break;
257 case GL_FLOAT_MAT4:
258 glUniformMatrix4fv(
259 location, size, false, reinterpret_cast<const GLfloat*>(zero));
260 break;
261 default:
262 NOTREACHED();
263 break;
264 }
265 }
266}
267
268namespace {
269
270struct UniformData {
271 UniformData() : size(-1), type(GL_NONE), location(0), added(false) {
272 }
273 std::string queried_name;
274 std::string corrected_name;
275 std::string original_name;
276 GLsizei size;
277 GLenum type;
278 GLint location;
279 bool added;
280};
281
282struct UniformDataComparer {
283 bool operator()(const UniformData& lhs, const UniformData& rhs) const {
284 return lhs.queried_name < rhs.queried_name;
285 }
286};
287
288} // anonymous namespace
289
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000290void Program::Update() {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000291 Reset();
292 UpdateLogInfo();
293 link_status_ = true;
294 uniforms_cleared_ = false;
295 GLint num_attribs = 0;
296 GLint max_len = 0;
297 GLint max_location = -1;
298 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs);
299 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
300 // TODO(gman): Should we check for error?
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100301 scoped_ptr<char[]> name_buffer(new char[max_len]);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000302 for (GLint ii = 0; ii < num_attribs; ++ii) {
303 GLsizei length = 0;
304 GLsizei size = 0;
305 GLenum type = 0;
306 glGetActiveAttrib(
307 service_id_, ii, max_len, &length, &size, &type, name_buffer.get());
308 DCHECK(max_len == 0 || length < max_len);
309 DCHECK(length == 0 || name_buffer[length] == '\0');
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000310 if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000311 std::string name;
312 std::string original_name;
313 GetCorrectedVariableInfo(
314 false, name_buffer.get(), &name, &original_name, &size, &type);
315 // TODO(gman): Should we check for error?
316 GLint location = glGetAttribLocation(service_id_, name_buffer.get());
317 if (location > max_location) {
318 max_location = location;
319 }
320 attrib_infos_.push_back(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000321 VertexAttrib(size, type, original_name, location));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000322 max_attrib_name_length_ = std::max(
323 max_attrib_name_length_, static_cast<GLsizei>(original_name.size()));
324 }
325 }
326
327 // Create attrib location to index map.
328 attrib_location_to_index_map_.resize(max_location + 1);
329 for (GLint ii = 0; ii <= max_location; ++ii) {
330 attrib_location_to_index_map_[ii] = -1;
331 }
332 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000333 const VertexAttrib& info = attrib_infos_[ii];
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000334 attrib_location_to_index_map_[info.location] = ii;
335 }
336
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000337#if !defined(NDEBUG)
338 if (CommandLine::ForCurrentProcess()->HasSwitch(
339 switches::kEnableGPUServiceLoggingGPU)) {
340 DLOG(INFO) << "----: attribs for service_id: " << service_id();
341 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
342 const VertexAttrib& info = attrib_infos_[ii];
343 DLOG(INFO) << ii << ": loc = " << info.location
344 << ", size = " << info.size
345 << ", type = " << GLES2Util::GetStringEnum(info.type)
346 << ", name = " << info.name;
347 }
348 }
349#endif
350
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000351 max_len = 0;
352 GLint num_uniforms = 0;
353 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
354 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
355 name_buffer.reset(new char[max_len]);
356
357 // Reads all the names.
358 std::vector<UniformData> uniform_data_;
359 for (GLint ii = 0; ii < num_uniforms; ++ii) {
360 GLsizei length = 0;
361 UniformData data;
362 glGetActiveUniform(
363 service_id_, ii, max_len, &length,
364 &data.size, &data.type, name_buffer.get());
365 DCHECK(max_len == 0 || length < max_len);
366 DCHECK(length == 0 || name_buffer[length] == '\0');
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000367 if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000368 data.queried_name = std::string(name_buffer.get());
369 GetCorrectedVariableInfo(
370 true, name_buffer.get(), &data.corrected_name, &data.original_name,
371 &data.size, &data.type);
372 uniform_data_.push_back(data);
373 }
374 }
375
376 // NOTE: We don't care if 2 uniforms are bound to the same location.
377 // One of them will take preference. The spec allows this, same as
378 // BindAttribLocation.
379 //
380 // The reason we don't check is if we were to fail we'd have to
381 // restore the previous program but since we've already linked successfully
382 // at this point the previous program is gone.
383
384 // Assigns the uniforms with bindings.
385 size_t next_available_index = 0;
386 for (size_t ii = 0; ii < uniform_data_.size(); ++ii) {
387 UniformData& data = uniform_data_[ii];
388 data.location = glGetUniformLocation(
389 service_id_, data.queried_name.c_str());
390 // remove "[0]"
391 std::string short_name;
392 int element_index = 0;
393 bool good ALLOW_UNUSED = GetUniformNameSansElement(
394 data.queried_name, &element_index, &short_name);\
395 DCHECK(good);
396 LocationMap::const_iterator it = bind_uniform_location_map_.find(
397 short_name);
398 if (it != bind_uniform_location_map_.end()) {
399 data.added = AddUniformInfo(
400 data.size, data.type, data.location, it->second, data.corrected_name,
401 data.original_name, &next_available_index);
402 }
403 }
404
405 // Assigns the uniforms that were not bound.
406 for (size_t ii = 0; ii < uniform_data_.size(); ++ii) {
407 const UniformData& data = uniform_data_[ii];
408 if (!data.added) {
409 AddUniformInfo(
410 data.size, data.type, data.location, -1, data.corrected_name,
411 data.original_name, &next_available_index);
412 }
413 }
414
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000415#if !defined(NDEBUG)
416 if (CommandLine::ForCurrentProcess()->HasSwitch(
417 switches::kEnableGPUServiceLoggingGPU)) {
418 DLOG(INFO) << "----: uniforms for service_id: " << service_id();
419 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
420 const UniformInfo& info = uniform_infos_[ii];
421 if (info.IsValid()) {
422 DLOG(INFO) << ii << ": loc = " << info.element_locations[0]
423 << ", size = " << info.size
424 << ", type = " << GLES2Util::GetStringEnum(info.type)
425 << ", name = " << info.name;
426 }
427 }
428 }
429#endif
430
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000431 valid_ = true;
432}
433
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000434void Program::ExecuteBindAttribLocationCalls() {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000435 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
436 it != bind_attrib_location_map_.end(); ++it) {
437 const std::string* mapped_name = GetAttribMappedName(it->first);
438 if (mapped_name && *mapped_name != it->first)
439 glBindAttribLocation(service_id_, it->second, mapped_name->c_str());
440 }
441}
442
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000443void ProgramManager::DoCompileShader(Shader* shader,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000444 ShaderTranslator* translator,
445 FeatureInfo* feature_info) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000446 // Translate GL ES 2.0 shader to Desktop GL shader and pass that to
447 // glShaderSource and then glCompileShader.
Ben Murdochbb1529c2013-08-08 10:24:53 +0100448 const std::string* source = shader->source();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000449 const char* shader_src = source ? source->c_str() : "";
450 if (translator) {
451 if (!translator->Translate(shader_src)) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000452 shader->SetStatus(false, translator->info_log(), NULL);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000453 return;
454 }
455 shader_src = translator->translated_shader();
456 if (!feature_info->feature_flags().angle_translated_shader_source)
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000457 shader->UpdateTranslatedSource(shader_src);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000458 }
459
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000460 glShaderSource(shader->service_id(), 1, &shader_src, NULL);
461 glCompileShader(shader->service_id());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000462 if (feature_info->feature_flags().angle_translated_shader_source) {
463 GLint max_len = 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000464 glGetShaderiv(shader->service_id(),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000465 GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE,
466 &max_len);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100467 scoped_ptr<char[]> temp(new char[max_len]);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000468 GLint len = 0;
469 glGetTranslatedShaderSourceANGLE(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000470 shader->service_id(), max_len, &len, temp.get());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000471 DCHECK(max_len == 0 || len < max_len);
472 DCHECK(len == 0 || temp[len] == '\0');
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000473 shader->UpdateTranslatedSource(max_len ? temp.get() : NULL);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000474 }
475
476 GLint status = GL_FALSE;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000477 glGetShaderiv(shader->service_id(), GL_COMPILE_STATUS, &status);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000478 if (status) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000479 shader->SetStatus(true, "", translator);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000480 } else {
481 // We cannot reach here if we are using the shader translator.
482 // All invalid shaders must be rejected by the translator.
483 // All translated shaders must compile.
484 GLint max_len = 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000485 glGetShaderiv(shader->service_id(), GL_INFO_LOG_LENGTH, &max_len);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100486 scoped_ptr<char[]> temp(new char[max_len]);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000487 GLint len = 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000488 glGetShaderInfoLog(shader->service_id(), max_len, &len, temp.get());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000489 DCHECK(max_len == 0 || len < max_len);
490 DCHECK(len == 0 || temp[len] == '\0');
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000491 shader->SetStatus(false, std::string(temp.get(), len).c_str(), NULL);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000492 LOG_IF(ERROR, translator)
493 << "Shader translator allowed/produced an invalid shader "
494 << "unless the driver is buggy:"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100495 << "\n--original-shader--\n" << (source ? *source : std::string())
496 << "\n--translated-shader--\n" << shader_src << "\n--info-log--\n"
497 << *shader->log_info();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000498 }
499}
500
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000501bool Program::Link(ShaderManager* manager,
502 ShaderTranslator* vertex_translator,
503 ShaderTranslator* fragment_translator,
504 FeatureInfo* feature_info,
505 const ShaderCacheCallback& shader_callback) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000506 ClearLinkStatus();
507 if (!CanLink()) {
508 set_log_info("missing shaders");
509 return false;
510 }
511 if (DetectAttribLocationBindingConflicts()) {
512 set_log_info("glBindAttribLocation() conflicts");
513 return false;
514 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000515
516 TimeTicks before_time = TimeTicks::HighResNow();
517 bool link = true;
518 ProgramCache* cache = manager_->program_cache_;
519 if (cache) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100520 DCHECK(attached_shaders_[0]->signature_source() &&
521 attached_shaders_[1]->signature_source());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000522 ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100523 *attached_shaders_[0]->signature_source(),
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100524 vertex_translator,
Ben Murdochbb1529c2013-08-08 10:24:53 +0100525 *attached_shaders_[1]->signature_source(),
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100526 fragment_translator,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000527 &bind_attrib_location_map_);
528
529 if (status == ProgramCache::LINK_SUCCEEDED) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100530 ProgramCache::ProgramLoadResult success =
531 cache->LoadLinkedProgram(service_id(),
532 attached_shaders_[0].get(),
533 vertex_translator,
534 attached_shaders_[1].get(),
535 fragment_translator,
536 &bind_attrib_location_map_,
537 shader_callback);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000538 link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
539 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link);
540 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000541 }
542
543 if (link) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100544 ExecuteBindAttribLocationCalls();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000545 before_time = TimeTicks::HighResNow();
546 if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
547 glProgramParameteri(service_id(),
548 PROGRAM_BINARY_RETRIEVABLE_HINT,
549 GL_TRUE);
550 }
551 glLinkProgram(service_id());
552 }
553
554 GLint success = 0;
555 glGetProgramiv(service_id(), GL_LINK_STATUS, &success);
556 if (success == GL_TRUE) {
557 Update();
558 if (link) {
559 if (cache) {
560 cache->SaveLinkedProgram(service_id(),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100561 attached_shaders_[0].get(),
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100562 vertex_translator,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100563 attached_shaders_[1].get(),
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100564 fragment_translator,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000565 &bind_attrib_location_map_,
566 shader_callback);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000567 }
568 UMA_HISTOGRAM_CUSTOM_COUNTS(
569 "GPU.ProgramCache.BinaryCacheMissTime",
570 (TimeTicks::HighResNow() - before_time).InMicroseconds(),
571 0,
572 TimeDelta::FromSeconds(10).InMicroseconds(),
573 50);
574 } else {
575 UMA_HISTOGRAM_CUSTOM_COUNTS(
576 "GPU.ProgramCache.BinaryCacheHitTime",
577 (TimeTicks::HighResNow() - before_time).InMicroseconds(),
578 0,
579 TimeDelta::FromSeconds(1).InMicroseconds(),
580 50);
581 }
582 } else {
583 UpdateLogInfo();
584 }
585 return success == GL_TRUE;
586}
587
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000588void Program::Validate() {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000589 if (!IsValid()) {
590 set_log_info("program not linked");
591 return;
592 }
593 glValidateProgram(service_id());
594 UpdateLogInfo();
595}
596
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000597GLint Program::GetUniformFakeLocation(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000598 const std::string& name) const {
599 bool getting_array_location = false;
600 size_t open_pos = std::string::npos;
601 int index = 0;
602 if (!GLES2Util::ParseUniformName(
603 name, &open_pos, &index, &getting_array_location)) {
604 return -1;
605 }
606 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
607 const UniformInfo& info = uniform_infos_[ii];
608 if (!info.IsValid()) {
609 continue;
610 }
611 if (info.name == name ||
612 (info.is_array &&
613 info.name.compare(0, info.name.size() - 3, name) == 0)) {
614 return info.fake_location_base;
615 } else if (getting_array_location && info.is_array) {
616 // Look for an array specification.
617 size_t open_pos_2 = info.name.find_last_of('[');
618 if (open_pos_2 == open_pos &&
619 name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
620 if (index >= 0 && index < info.size) {
621 return ProgramManager::MakeFakeLocation(
622 info.fake_location_base, index);
623 }
624 }
625 }
626 }
627 return -1;
628}
629
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000630GLint Program::GetAttribLocation(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000631 const std::string& name) const {
632 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000633 const VertexAttrib& info = attrib_infos_[ii];
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000634 if (info.name == name) {
635 return info.location;
636 }
637 }
638 return -1;
639}
640
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000641const Program::UniformInfo*
642 Program::GetUniformInfoByFakeLocation(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000643 GLint fake_location, GLint* real_location, GLint* array_index) const {
644 DCHECK(real_location);
645 DCHECK(array_index);
646 if (fake_location < 0) {
647 return NULL;
648 }
649
650 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
651 if (uniform_index >= 0 &&
652 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
653 const UniformInfo& uniform_info = uniform_infos_[uniform_index];
654 if (!uniform_info.IsValid()) {
655 return NULL;
656 }
657 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
658 if (element_index < uniform_info.size) {
659 *real_location = uniform_info.element_locations[element_index];
660 *array_index = element_index;
661 return &uniform_info;
662 }
663 }
664 return NULL;
665}
666
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000667const std::string* Program::GetAttribMappedName(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000668 const std::string& original_name) const {
669 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000670 Shader* shader = attached_shaders_[ii].get();
671 if (shader) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000672 const std::string* mapped_name =
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000673 shader->GetAttribMappedName(original_name);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000674 if (mapped_name)
675 return mapped_name;
676 }
677 }
678 return NULL;
679}
680
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000681const std::string* Program::GetOriginalNameFromHashedName(
682 const std::string& hashed_name) const {
683 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
684 Shader* shader = attached_shaders_[ii].get();
685 if (shader) {
686 const std::string* original_name =
687 shader->GetOriginalNameFromHashedName(hashed_name);
688 if (original_name)
689 return original_name;
690 }
691 }
692 return NULL;
693}
694
695bool Program::SetUniformLocationBinding(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000696 const std::string& name, GLint location) {
697 std::string short_name;
698 int element_index = 0;
699 if (!GetUniformNameSansElement(name, &element_index, &short_name) ||
700 element_index != 0) {
701 return false;
702 }
703
704 bind_uniform_location_map_[short_name] = location;
705 return true;
706}
707
708// Note: This is only valid to call right after a program has been linked
709// successfully.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000710void Program::GetCorrectedVariableInfo(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000711 bool use_uniforms,
712 const std::string& name, std::string* corrected_name,
713 std::string* original_name,
714 GLsizei* size, GLenum* type) const {
715 DCHECK(corrected_name);
716 DCHECK(original_name);
717 DCHECK(size);
718 DCHECK(type);
719 const char* kArraySpec = "[0]";
720 for (int jj = 0; jj < 2; ++jj) {
721 std::string test_name(name + ((jj == 1) ? kArraySpec : ""));
722 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000723 Shader* shader = attached_shaders_[ii].get();
724 if (shader) {
725 const Shader::VariableInfo* variable_info =
726 use_uniforms ? shader->GetUniformInfo(test_name) :
727 shader->GetAttribInfo(test_name);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000728 // Note: There is an assuption here that if an attrib is defined in more
729 // than 1 attached shader their types and sizes match. Should we check
730 // for that case?
731 if (variable_info) {
732 *corrected_name = test_name;
733 *original_name = variable_info->name;
734 *type = variable_info->type;
735 *size = variable_info->size;
736 return;
737 }
738 }
739 }
740 }
741 *corrected_name = name;
742 *original_name = name;
743}
744
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000745bool Program::AddUniformInfo(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000746 GLsizei size, GLenum type, GLint location, GLint fake_base_location,
747 const std::string& name, const std::string& original_name,
748 size_t* next_available_index) {
749 DCHECK(next_available_index);
750 const char* kArraySpec = "[0]";
751 size_t uniform_index =
752 fake_base_location >= 0 ? fake_base_location : *next_available_index;
753 if (uniform_infos_.size() < uniform_index + 1) {
754 uniform_infos_.resize(uniform_index + 1);
755 }
756
757 // return if this location is already in use.
758 if (uniform_infos_[uniform_index].IsValid()) {
759 DCHECK_GE(fake_base_location, 0);
760 return false;
761 }
762
763 uniform_infos_[uniform_index] = UniformInfo(
764 size, type, uniform_index, original_name);
765 ++num_uniforms_;
766
767 UniformInfo& info = uniform_infos_[uniform_index];
768 info.element_locations.resize(size);
769 info.element_locations[0] = location;
770 DCHECK_GE(size, 0);
771 size_t num_texture_units = info.IsSampler() ? static_cast<size_t>(size) : 0u;
772 info.texture_units.clear();
773 info.texture_units.resize(num_texture_units, 0);
774
775 if (size > 1) {
776 // Go through the array element locations looking for a match.
777 // We can skip the first element because it's the same as the
778 // the location without the array operators.
779 size_t array_pos = name.rfind(kArraySpec);
780 std::string base_name = name;
781 if (name.size() > 3) {
782 if (array_pos != name.size() - 3) {
783 info.name = name + kArraySpec;
784 } else {
785 base_name = name.substr(0, name.size() - 3);
786 }
787 }
788 for (GLsizei ii = 1; ii < info.size; ++ii) {
789 std::string element_name(base_name + "[" + base::IntToString(ii) + "]");
790 info.element_locations[ii] =
791 glGetUniformLocation(service_id_, element_name.c_str());
792 }
793 }
794
795 info.is_array =
796 (size > 1 ||
797 (info.name.size() > 3 &&
798 info.name.rfind(kArraySpec) == info.name.size() - 3));
799
800 if (info.IsSampler()) {
801 sampler_indices_.push_back(info.fake_location_base);
802 }
803 max_uniform_name_length_ =
804 std::max(max_uniform_name_length_,
805 static_cast<GLsizei>(info.name.size()));
806
807 while (*next_available_index < uniform_infos_.size() &&
808 uniform_infos_[*next_available_index].IsValid()) {
809 *next_available_index = *next_available_index + 1;
810 }
811
812 return true;
813}
814
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000815const Program::UniformInfo*
816 Program::GetUniformInfo(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000817 GLint index) const {
818 if (static_cast<size_t>(index) >= uniform_infos_.size()) {
819 return NULL;
820 }
821
822 const UniformInfo& info = uniform_infos_[index];
823 return info.IsValid() ? &info : NULL;
824}
825
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000826bool Program::SetSamplers(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000827 GLint num_texture_units, GLint fake_location,
828 GLsizei count, const GLint* value) {
829 if (fake_location < 0) {
830 return true;
831 }
832 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
833 if (uniform_index >= 0 &&
834 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
835 UniformInfo& info = uniform_infos_[uniform_index];
836 if (!info.IsValid()) {
837 return false;
838 }
839 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
840 if (element_index < info.size) {
841 count = std::min(info.size - element_index, count);
842 if (info.IsSampler() && count > 0) {
843 for (GLsizei ii = 0; ii < count; ++ii) {
844 if (value[ii] < 0 || value[ii] >= num_texture_units) {
845 return false;
846 }
847 }
848 std::copy(value, value + count,
849 info.texture_units.begin() + element_index);
850 return true;
851 }
852 }
853 }
854 return true;
855}
856
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000857void Program::GetProgramiv(GLenum pname, GLint* params) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000858 switch (pname) {
859 case GL_ACTIVE_ATTRIBUTES:
860 *params = attrib_infos_.size();
861 break;
862 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
863 // Notice +1 to accomodate NULL terminator.
864 *params = max_attrib_name_length_ + 1;
865 break;
866 case GL_ACTIVE_UNIFORMS:
867 *params = num_uniforms_;
868 break;
869 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
870 // Notice +1 to accomodate NULL terminator.
871 *params = max_uniform_name_length_ + 1;
872 break;
873 case GL_LINK_STATUS:
874 *params = link_status_;
875 break;
876 case GL_INFO_LOG_LENGTH:
877 // Notice +1 to accomodate NULL terminator.
878 *params = log_info_.get() ? (log_info_->size() + 1) : 0;
879 break;
880 case GL_DELETE_STATUS:
881 *params = deleted_;
882 break;
883 case GL_VALIDATE_STATUS:
884 if (!IsValid()) {
885 *params = GL_FALSE;
886 } else {
887 glGetProgramiv(service_id_, pname, params);
888 }
889 break;
890 default:
891 glGetProgramiv(service_id_, pname, params);
892 break;
893 }
894}
895
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000896bool Program::AttachShader(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000897 ShaderManager* shader_manager,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000898 Shader* shader) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000899 DCHECK(shader_manager);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000900 DCHECK(shader);
901 int index = ShaderTypeToIndex(shader->shader_type());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100902 if (attached_shaders_[index].get() != NULL) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000903 return false;
904 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000905 attached_shaders_[index] = scoped_refptr<Shader>(shader);
906 shader_manager->UseShader(shader);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000907 return true;
908}
909
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000910bool Program::DetachShader(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000911 ShaderManager* shader_manager,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000912 Shader* shader) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000913 DCHECK(shader_manager);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000914 DCHECK(shader);
915 if (attached_shaders_[ShaderTypeToIndex(shader->shader_type())].get() !=
916 shader) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000917 return false;
918 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000919 attached_shaders_[ShaderTypeToIndex(shader->shader_type())] = NULL;
920 shader_manager->UnuseShader(shader);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000921 return true;
922}
923
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000924void Program::DetachShaders(ShaderManager* shader_manager) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000925 DCHECK(shader_manager);
926 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100927 if (attached_shaders_[ii].get()) {
928 DetachShader(shader_manager, attached_shaders_[ii].get());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000929 }
930 }
931}
932
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000933bool Program::CanLink() const {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000934 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100935 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->IsValid()) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000936 return false;
937 }
938 }
939 return true;
940}
941
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000942bool Program::DetectAttribLocationBindingConflicts() const {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000943 std::set<GLint> location_binding_used;
944 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
945 it != bind_attrib_location_map_.end(); ++it) {
946 // Find out if an attribute is declared in this program's shaders.
947 bool active = false;
948 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100949 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->IsValid())
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000950 continue;
951 if (attached_shaders_[ii]->GetAttribInfo(it->first)) {
952 active = true;
953 break;
954 }
955 }
956 if (active) {
957 std::pair<std::set<GLint>::iterator, bool> result =
958 location_binding_used.insert(it->second);
959 if (!result.second)
960 return true;
961 }
962 }
963 return false;
964}
965
966static uint32 ComputeOffset(const void* start, const void* position) {
967 return static_cast<const uint8*>(position) -
968 static_cast<const uint8*>(start);
969}
970
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000971void Program::GetProgramInfo(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000972 ProgramManager* manager, CommonDecoder::Bucket* bucket) const {
973 // NOTE: It seems to me the math in here does not need check for overflow
974 // because the data being calucated from has various small limits. The max
975 // number of attribs + uniforms is somewhere well under 1024. The maximum size
976 // of an identifier is 256 characters.
977 uint32 num_locations = 0;
978 uint32 total_string_size = 0;
979
980 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000981 const VertexAttrib& info = attrib_infos_[ii];
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000982 num_locations += 1;
983 total_string_size += info.name.size();
984 }
985
986 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
987 const UniformInfo& info = uniform_infos_[ii];
988 if (info.IsValid()) {
989 num_locations += info.element_locations.size();
990 total_string_size += info.name.size();
991 }
992 }
993
994 uint32 num_inputs = attrib_infos_.size() + num_uniforms_;
995 uint32 input_size = num_inputs * sizeof(ProgramInput);
996 uint32 location_size = num_locations * sizeof(int32);
997 uint32 size = sizeof(ProgramInfoHeader) +
998 input_size + location_size + total_string_size;
999
1000 bucket->SetSize(size);
1001 ProgramInfoHeader* header = bucket->GetDataAs<ProgramInfoHeader*>(0, size);
1002 ProgramInput* inputs = bucket->GetDataAs<ProgramInput*>(
1003 sizeof(ProgramInfoHeader), input_size);
1004 int32* locations = bucket->GetDataAs<int32*>(
1005 sizeof(ProgramInfoHeader) + input_size, location_size);
1006 char* strings = bucket->GetDataAs<char*>(
1007 sizeof(ProgramInfoHeader) + input_size + location_size,
1008 total_string_size);
1009 DCHECK(header);
1010 DCHECK(inputs);
1011 DCHECK(locations);
1012 DCHECK(strings);
1013
1014 header->link_status = link_status_;
1015 header->num_attribs = attrib_infos_.size();
1016 header->num_uniforms = num_uniforms_;
1017
1018 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001019 const VertexAttrib& info = attrib_infos_[ii];
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001020 inputs->size = info.size;
1021 inputs->type = info.type;
1022 inputs->location_offset = ComputeOffset(header, locations);
1023 inputs->name_offset = ComputeOffset(header, strings);
1024 inputs->name_length = info.name.size();
1025 *locations++ = info.location;
1026 memcpy(strings, info.name.c_str(), info.name.size());
1027 strings += info.name.size();
1028 ++inputs;
1029 }
1030
1031 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1032 const UniformInfo& info = uniform_infos_[ii];
1033 if (info.IsValid()) {
1034 inputs->size = info.size;
1035 inputs->type = info.type;
1036 inputs->location_offset = ComputeOffset(header, locations);
1037 inputs->name_offset = ComputeOffset(header, strings);
1038 inputs->name_length = info.name.size();
1039 DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
1040 for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
1041 *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
1042 }
1043 memcpy(strings, info.name.c_str(), info.name.size());
1044 strings += info.name.size();
1045 ++inputs;
1046 }
1047 }
1048
1049 DCHECK_EQ(ComputeOffset(header, strings), size);
1050}
1051
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001052Program::~Program() {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001053 if (manager_) {
1054 if (manager_->have_context_) {
1055 glDeleteProgram(service_id());
1056 }
1057 manager_->StopTracking(this);
1058 manager_ = NULL;
1059 }
1060}
1061
1062
1063ProgramManager::ProgramManager(ProgramCache* program_cache)
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001064 : program_count_(0),
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001065 have_context_(true),
1066 disable_workarounds_(
1067 CommandLine::ForCurrentProcess()->HasSwitch(
1068 switches::kDisableGpuDriverBugWorkarounds)),
1069 program_cache_(program_cache) { }
1070
1071ProgramManager::~ProgramManager() {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001072 DCHECK(programs_.empty());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001073}
1074
1075void ProgramManager::Destroy(bool have_context) {
1076 have_context_ = have_context;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001077 programs_.clear();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001078}
1079
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001080void ProgramManager::StartTracking(Program* /* program */) {
1081 ++program_count_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001082}
1083
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001084void ProgramManager::StopTracking(Program* /* program */) {
1085 --program_count_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001086}
1087
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001088Program* ProgramManager::CreateProgram(
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001089 GLuint client_id, GLuint service_id) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001090 std::pair<ProgramMap::iterator, bool> result =
1091 programs_.insert(
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001092 std::make_pair(client_id,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001093 scoped_refptr<Program>(
1094 new Program(this, service_id))));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001095 DCHECK(result.second);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001096 return result.first->second.get();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001097}
1098
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001099Program* ProgramManager::GetProgram(GLuint client_id) {
1100 ProgramMap::iterator it = programs_.find(client_id);
Ben Murdocheb525c52013-07-10 11:40:50 +01001101 return it != programs_.end() ? it->second.get() : NULL;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001102}
1103
1104bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
1105 // This doesn't need to be fast. It's only used during slow queries.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001106 for (ProgramMap::const_iterator it = programs_.begin();
1107 it != programs_.end(); ++it) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001108 if (it->second->service_id() == service_id) {
1109 *client_id = it->first;
1110 return true;
1111 }
1112 }
1113 return false;
1114}
1115
1116ProgramCache* ProgramManager::program_cache() const {
1117 return program_cache_;
1118}
1119
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001120bool ProgramManager::IsOwned(Program* program) {
1121 for (ProgramMap::iterator it = programs_.begin();
1122 it != programs_.end(); ++it) {
1123 if (it->second.get() == program) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001124 return true;
1125 }
1126 }
1127 return false;
1128}
1129
1130void ProgramManager::RemoveProgramInfoIfUnused(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001131 ShaderManager* shader_manager, Program* program) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001132 DCHECK(shader_manager);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001133 DCHECK(program);
1134 DCHECK(IsOwned(program));
1135 if (program->IsDeleted() && !program->InUse()) {
1136 program->DetachShaders(shader_manager);
1137 for (ProgramMap::iterator it = programs_.begin();
1138 it != programs_.end(); ++it) {
1139 if (it->second.get() == program) {
1140 programs_.erase(it);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001141 return;
1142 }
1143 }
1144 NOTREACHED();
1145 }
1146}
1147
1148void ProgramManager::MarkAsDeleted(
1149 ShaderManager* shader_manager,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001150 Program* program) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001151 DCHECK(shader_manager);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001152 DCHECK(program);
1153 DCHECK(IsOwned(program));
1154 program->MarkAsDeleted();
1155 RemoveProgramInfoIfUnused(shader_manager, program);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001156}
1157
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001158void ProgramManager::UseProgram(Program* program) {
1159 DCHECK(program);
1160 DCHECK(IsOwned(program));
1161 program->IncUseCount();
1162 ClearUniforms(program);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001163}
1164
1165void ProgramManager::UnuseProgram(
1166 ShaderManager* shader_manager,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001167 Program* program) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001168 DCHECK(shader_manager);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001169 DCHECK(program);
1170 DCHECK(IsOwned(program));
1171 program->DecUseCount();
1172 RemoveProgramInfoIfUnused(shader_manager, program);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001173}
1174
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001175void ProgramManager::ClearUniforms(Program* program) {
1176 DCHECK(program);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001177 if (!disable_workarounds_) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001178 program->ClearUniforms(&zero_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001179 }
1180}
1181
1182int32 ProgramManager::MakeFakeLocation(int32 index, int32 element) {
1183 return index + element * 0x10000;
1184}
1185
1186} // namespace gles2
1187} // namespace gpu