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