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 <map> 6 7 #include "base/compiler_specific.h" 8 #include "gpu/command_buffer/client/atomicops.h" 9 #include "gpu/command_buffer/client/gles2_implementation.h" 10 #include "gpu/command_buffer/client/program_info_manager.h" 11 #include "gpu/command_buffer/common/gles2_cmd_utils.h" 12 13 namespace gpu { 14 namespace gles2 { 15 16 class NonCachedProgramInfoManager : public ProgramInfoManager { 17 public: 18 NonCachedProgramInfoManager(); 19 virtual ~NonCachedProgramInfoManager(); 20 21 virtual void CreateInfo(GLuint program) OVERRIDE; 22 23 virtual void DeleteInfo(GLuint program) OVERRIDE; 24 25 virtual bool GetProgramiv(GLES2Implementation* gl, 26 GLuint program, 27 GLenum pname, 28 GLint* params) OVERRIDE; 29 30 virtual GLint GetAttribLocation(GLES2Implementation* gl, 31 GLuint program, 32 const char* name) OVERRIDE; 33 34 virtual GLint GetUniformLocation(GLES2Implementation* gl, 35 GLuint program, 36 const char* name) OVERRIDE; 37 38 virtual bool GetActiveAttrib(GLES2Implementation* gl, 39 GLuint program, 40 GLuint index, 41 GLsizei bufsize, 42 GLsizei* length, 43 GLint* size, 44 GLenum* type, 45 char* name) OVERRIDE; 46 47 virtual bool GetActiveUniform(GLES2Implementation* gl, 48 GLuint program, 49 GLuint index, 50 GLsizei bufsize, 51 GLsizei* length, 52 GLint* size, 53 GLenum* type, 54 char* name) OVERRIDE; 55 56 }; 57 58 NonCachedProgramInfoManager::NonCachedProgramInfoManager() { 59 } 60 61 NonCachedProgramInfoManager::~NonCachedProgramInfoManager() { 62 } 63 64 void NonCachedProgramInfoManager::CreateInfo(GLuint /* program */) { 65 } 66 67 void NonCachedProgramInfoManager::DeleteInfo(GLuint /* program */) { 68 } 69 70 bool NonCachedProgramInfoManager::GetProgramiv( 71 GLES2Implementation* /* gl */, 72 GLuint /* program */, 73 GLenum /* pname */, 74 GLint* /* params */) { 75 return false; 76 } 77 78 GLint NonCachedProgramInfoManager::GetAttribLocation( 79 GLES2Implementation* gl, GLuint program, const char* name) { 80 return gl->GetAttribLocationHelper(program, name); 81 } 82 83 GLint NonCachedProgramInfoManager::GetUniformLocation( 84 GLES2Implementation* gl, GLuint program, const char* name) { 85 return gl->GetUniformLocationHelper(program, name); 86 } 87 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); 94 } 95 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); 102 } 103 104 class CachedProgramInfoManager : public ProgramInfoManager { 105 public: 106 CachedProgramInfoManager(); 107 virtual ~CachedProgramInfoManager(); 108 109 virtual void CreateInfo(GLuint program) OVERRIDE; 110 111 virtual void DeleteInfo(GLuint program) OVERRIDE; 112 113 virtual bool GetProgramiv(GLES2Implementation* gl, 114 GLuint program, 115 GLenum pname, 116 GLint* params) OVERRIDE; 117 118 virtual GLint GetAttribLocation(GLES2Implementation* gl, 119 GLuint program, 120 const char* name) OVERRIDE; 121 122 virtual GLint GetUniformLocation(GLES2Implementation* gl, 123 GLuint program, 124 const char* name) OVERRIDE; 125 126 virtual 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; 134 135 virtual 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; 143 144 private: 145 class Program { 146 public: 147 struct UniformInfo { 148 UniformInfo(GLsizei _size, GLenum _type, const std::string& _name); 149 150 GLsizei size; 151 GLenum type; 152 bool is_array; 153 std::string name; 154 std::vector<GLint> element_locations; 155 }; 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) { 163 } 164 GLsizei size; 165 GLenum type; 166 GLint location; 167 std::string name; 168 }; 169 170 typedef std::vector<UniformInfo> UniformInfoVector; 171 typedef std::vector<VertexAttrib> AttribInfoVector; 172 173 Program(); 174 175 const AttribInfoVector& GetAttribInfos() const { 176 return attrib_infos_; 177 } 178 179 const VertexAttrib* GetAttribInfo(GLint index) const { 180 return (static_cast<size_t>(index) < attrib_infos_.size()) ? 181 &attrib_infos_[index] : NULL; 182 } 183 184 GLint GetAttribLocation(const std::string& name) const; 185 186 const UniformInfo* GetUniformInfo(GLint index) const { 187 return (static_cast<size_t>(index) < uniform_infos_.size()) ? 188 &uniform_infos_[index] : NULL; 189 } 190 191 // Gets the location of a uniform by name. 192 GLint GetUniformLocation(const std::string& name) const; 193 194 bool GetProgramiv(GLenum pname, GLint* params); 195 196 // Updates the program info after a successful link. 197 void Update(GLES2Implementation* gl, GLuint program); 198 199 private: 200 bool cached_; 201 202 GLsizei max_attrib_name_length_; 203 204 // Attrib by index. 205 AttribInfoVector attrib_infos_; 206 207 GLsizei max_uniform_name_length_; 208 209 // Uniform info by index. 210 UniformInfoVector uniform_infos_; 211 212 // This is true if glLinkProgram was successful last time it was called. 213 bool link_status_; 214 }; 215 216 Program* GetProgramInfo(GLES2Implementation* gl, GLuint program); 217 218 // TODO(gman): Switch to a faster container. 219 typedef std::map<GLuint, Program> ProgramInfoMap; 220 221 ProgramInfoMap program_infos_; 222 223 mutable Lock lock_; 224 }; 225 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 GPU_DCHECK(!(size > 1 && !is_array)); 233 } 234 235 CachedProgramInfoManager::Program::Program() 236 : cached_(false), 237 max_attrib_name_length_(0), 238 max_uniform_name_length_(0), 239 link_status_(false) { 240 } 241 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; 249 } 250 } 251 return -1; 252 } 253 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; 262 } 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]; 276 } 277 } 278 } 279 } 280 return -1; 281 } 282 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; 303 } 304 return false; 305 } 306 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 GPU_NOTREACHED(); 312 return NULL; 313 } 314 return static_cast<T>(static_cast<const void*>(p)); 315 } 316 317 void CachedProgramInfoManager::Program::Update( 318 GLES2Implementation* gl, GLuint program) { 319 if (cached_) { 320 return; 321 } 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; 327 } 328 GPU_DCHECK_GE(result.size(), sizeof(ProgramInfoHeader)); 329 const ProgramInfoHeader* header = LocalGetAs<const ProgramInfoHeader*>( 330 result, 0, sizeof(header)); 331 link_status_ = header->link_status != 0; 332 if (!link_status_) { 333 return; 334 } 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; 354 } 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]); 366 } 367 uniform_infos_.push_back(info); 368 ++input; 369 } 370 GPU_DCHECK_EQ(header->num_attribs + header->num_uniforms, 371 static_cast<uint32>(input - inputs)); 372 cached_ = true; 373 } 374 375 CachedProgramInfoManager::CachedProgramInfoManager() { 376 } 377 378 CachedProgramInfoManager::~CachedProgramInfoManager() { 379 380 } 381 382 CachedProgramInfoManager::Program* 383 CachedProgramInfoManager::GetProgramInfo( 384 GLES2Implementation* gl, GLuint program) { 385 ProgramInfoMap::iterator it = program_infos_.find(program); 386 if (it == program_infos_.end()) { 387 return NULL; 388 } 389 Program* info = &it->second; 390 info->Update(gl, program); 391 return info; 392 } 393 394 void CachedProgramInfoManager::CreateInfo(GLuint program) { 395 AutoLock auto_lock(lock_); 396 DeleteInfo(program); 397 std::pair<ProgramInfoMap::iterator, bool> result = 398 program_infos_.insert(std::make_pair(program, Program())); 399 400 GPU_DCHECK(result.second); 401 } 402 403 void CachedProgramInfoManager::DeleteInfo(GLuint program) { 404 program_infos_.erase(program); 405 } 406 407 bool CachedProgramInfoManager::GetProgramiv( 408 GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) { 409 AutoLock auto_lock(lock_); 410 Program* info = GetProgramInfo(gl, program); 411 if (!info) { 412 return false; 413 } 414 return info->GetProgramiv(pname, params); 415 } 416 417 GLint CachedProgramInfoManager::GetAttribLocation( 418 GLES2Implementation* gl, GLuint program, const char* name) { 419 AutoLock auto_lock(lock_); 420 Program* info = GetProgramInfo(gl, program); 421 if (info) { 422 return info->GetAttribLocation(name); 423 } 424 return gl->GetAttribLocationHelper(program, name); 425 } 426 427 GLint CachedProgramInfoManager::GetUniformLocation( 428 GLES2Implementation* gl, GLuint program, const char* name) { 429 AutoLock auto_lock(lock_); 430 Program* info = GetProgramInfo(gl, program); 431 if (info) { 432 return info->GetUniformLocation(name); 433 } 434 return gl->GetUniformLocationHelper(program, name); 435 } 436 437 bool CachedProgramInfoManager::GetActiveAttrib( 438 GLES2Implementation* gl, 439 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, 440 GLint* size, GLenum* type, char* name) { 441 AutoLock auto_lock(lock_); 442 Program* info = GetProgramInfo(gl, program); 443 if (info) { 444 const Program::VertexAttrib* attrib_info = 445 info->GetAttribInfo(index); 446 if (attrib_info) { 447 if (size) { 448 *size = attrib_info->size; 449 } 450 if (type) { 451 *type = attrib_info->type; 452 } 453 if (length || name) { 454 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1, 455 std::max(static_cast<size_t>(0), 456 attrib_info->name.size())); 457 if (length) { 458 *length = max_size; 459 } 460 if (name && bufsize > 0) { 461 memcpy(name, attrib_info->name.c_str(), max_size); 462 name[max_size] = '\0'; 463 } 464 } 465 return true; 466 } 467 } 468 return gl->GetActiveAttribHelper( 469 program, index, bufsize, length, size, type, name); 470 } 471 472 bool CachedProgramInfoManager::GetActiveUniform( 473 GLES2Implementation* gl, 474 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, 475 GLint* size, GLenum* type, char* name) { 476 AutoLock auto_lock(lock_); 477 Program* info = GetProgramInfo(gl, program); 478 if (info) { 479 const Program::UniformInfo* uniform_info = info->GetUniformInfo(index); 480 if (uniform_info) { 481 if (size) { 482 *size = uniform_info->size; 483 } 484 if (type) { 485 *type = uniform_info->type; 486 } 487 if (length || name) { 488 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1, 489 std::max(static_cast<size_t>(0), 490 uniform_info->name.size())); 491 if (length) { 492 *length = max_size; 493 } 494 if (name && bufsize > 0) { 495 memcpy(name, uniform_info->name.c_str(), max_size); 496 name[max_size] = '\0'; 497 } 498 } 499 return true; 500 } 501 } 502 return gl->GetActiveUniformHelper( 503 program, index, bufsize, length, size, type, name); 504 } 505 506 ProgramInfoManager::ProgramInfoManager() { 507 } 508 509 ProgramInfoManager::~ProgramInfoManager() { 510 } 511 512 ProgramInfoManager* ProgramInfoManager::Create( 513 bool shared_resources_across_processes) { 514 if (shared_resources_across_processes) { 515 return new NonCachedProgramInfoManager(); 516 } else { 517 return new CachedProgramInfoManager(); 518 } 519 } 520 521 } // namespace gles2 522 } // namespace gpu 523 524