1 #include "precompiled.h" 2 // 3 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 // 7 8 // Program.cpp: Implements the gl::Program class. Implements GL program objects 9 // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. 10 11 #include "libGLESv2/Program.h" 12 #include "libGLESv2/ProgramBinary.h" 13 #include "libGLESv2/ResourceManager.h" 14 15 namespace gl 16 { 17 const char * const g_fakepath = "C:\\fakepath"; 18 19 AttributeBindings::AttributeBindings() 20 { 21 } 22 23 AttributeBindings::~AttributeBindings() 24 { 25 } 26 27 InfoLog::InfoLog() : mInfoLog(NULL) 28 { 29 } 30 31 InfoLog::~InfoLog() 32 { 33 delete[] mInfoLog; 34 } 35 36 37 int InfoLog::getLength() const 38 { 39 if (!mInfoLog) 40 { 41 return 0; 42 } 43 else 44 { 45 return strlen(mInfoLog) + 1; 46 } 47 } 48 49 void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) 50 { 51 int index = 0; 52 53 if (bufSize > 0) 54 { 55 if (mInfoLog) 56 { 57 index = std::min(bufSize - 1, (int)strlen(mInfoLog)); 58 memcpy(infoLog, mInfoLog, index); 59 } 60 61 infoLog[index] = '\0'; 62 } 63 64 if (length) 65 { 66 *length = index; 67 } 68 } 69 70 // append a santized message to the program info log. 71 // The D3D compiler includes a fake file path in some of the warning or error 72 // messages, so lets remove all occurrences of this fake file path from the log. 73 void InfoLog::appendSanitized(const char *message) 74 { 75 std::string msg(message); 76 77 size_t found; 78 do 79 { 80 found = msg.find(g_fakepath); 81 if (found != std::string::npos) 82 { 83 msg.erase(found, strlen(g_fakepath)); 84 } 85 } 86 while (found != std::string::npos); 87 88 append("%s", msg.c_str()); 89 } 90 91 void InfoLog::append(const char *format, ...) 92 { 93 if (!format) 94 { 95 return; 96 } 97 98 char info[1024]; 99 100 va_list vararg; 101 va_start(vararg, format); 102 vsnprintf(info, sizeof(info), format, vararg); 103 va_end(vararg); 104 105 size_t infoLength = strlen(info); 106 107 if (!mInfoLog) 108 { 109 mInfoLog = new char[infoLength + 2]; 110 strcpy(mInfoLog, info); 111 strcpy(mInfoLog + infoLength, "\n"); 112 } 113 else 114 { 115 size_t logLength = strlen(mInfoLog); 116 char *newLog = new char[logLength + infoLength + 2]; 117 strcpy(newLog, mInfoLog); 118 strcpy(newLog + logLength, info); 119 strcpy(newLog + logLength + infoLength, "\n"); 120 121 delete[] mInfoLog; 122 mInfoLog = newLog; 123 } 124 } 125 126 void InfoLog::reset() 127 { 128 if (mInfoLog) 129 { 130 delete [] mInfoLog; 131 mInfoLog = NULL; 132 } 133 } 134 135 Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle) 136 { 137 mFragmentShader = NULL; 138 mVertexShader = NULL; 139 mProgramBinary.set(NULL); 140 mDeleteStatus = false; 141 mLinked = false; 142 mRefCount = 0; 143 mRenderer = renderer; 144 } 145 146 Program::~Program() 147 { 148 unlink(true); 149 150 if (mVertexShader != NULL) 151 { 152 mVertexShader->release(); 153 } 154 155 if (mFragmentShader != NULL) 156 { 157 mFragmentShader->release(); 158 } 159 } 160 161 bool Program::attachShader(Shader *shader) 162 { 163 if (shader->getType() == GL_VERTEX_SHADER) 164 { 165 if (mVertexShader) 166 { 167 return false; 168 } 169 170 mVertexShader = (VertexShader*)shader; 171 mVertexShader->addRef(); 172 } 173 else if (shader->getType() == GL_FRAGMENT_SHADER) 174 { 175 if (mFragmentShader) 176 { 177 return false; 178 } 179 180 mFragmentShader = (FragmentShader*)shader; 181 mFragmentShader->addRef(); 182 } 183 else UNREACHABLE(); 184 185 return true; 186 } 187 188 bool Program::detachShader(Shader *shader) 189 { 190 if (shader->getType() == GL_VERTEX_SHADER) 191 { 192 if (mVertexShader != shader) 193 { 194 return false; 195 } 196 197 mVertexShader->release(); 198 mVertexShader = NULL; 199 } 200 else if (shader->getType() == GL_FRAGMENT_SHADER) 201 { 202 if (mFragmentShader != shader) 203 { 204 return false; 205 } 206 207 mFragmentShader->release(); 208 mFragmentShader = NULL; 209 } 210 else UNREACHABLE(); 211 212 return true; 213 } 214 215 int Program::getAttachedShadersCount() const 216 { 217 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0); 218 } 219 220 void AttributeBindings::bindAttributeLocation(GLuint index, const char *name) 221 { 222 if (index < MAX_VERTEX_ATTRIBS) 223 { 224 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) 225 { 226 mAttributeBinding[i].erase(name); 227 } 228 229 mAttributeBinding[index].insert(name); 230 } 231 } 232 233 void Program::bindAttributeLocation(GLuint index, const char *name) 234 { 235 mAttributeBindings.bindAttributeLocation(index, name); 236 } 237 238 // Links the HLSL code of the vertex and pixel shader by matching up their varyings, 239 // compiling them into binaries, determining the attribute mappings, and collecting 240 // a list of uniforms 241 bool Program::link() 242 { 243 unlink(false); 244 245 mInfoLog.reset(); 246 247 mProgramBinary.set(new ProgramBinary(mRenderer)); 248 mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader); 249 250 return mLinked; 251 } 252 253 int AttributeBindings::getAttributeBinding(const std::string &name) const 254 { 255 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++) 256 { 257 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end()) 258 { 259 return location; 260 } 261 } 262 263 return -1; 264 } 265 266 // Returns the program object to an unlinked state, before re-linking, or at destruction 267 void Program::unlink(bool destroy) 268 { 269 if (destroy) // Object being destructed 270 { 271 if (mFragmentShader) 272 { 273 mFragmentShader->release(); 274 mFragmentShader = NULL; 275 } 276 277 if (mVertexShader) 278 { 279 mVertexShader->release(); 280 mVertexShader = NULL; 281 } 282 } 283 284 mProgramBinary.set(NULL); 285 mLinked = false; 286 } 287 288 bool Program::isLinked() 289 { 290 return mLinked; 291 } 292 293 ProgramBinary* Program::getProgramBinary() 294 { 295 return mProgramBinary.get(); 296 } 297 298 bool Program::setProgramBinary(const void *binary, GLsizei length) 299 { 300 unlink(false); 301 302 mInfoLog.reset(); 303 304 mProgramBinary.set(new ProgramBinary(mRenderer)); 305 mLinked = mProgramBinary->load(mInfoLog, binary, length); 306 if (!mLinked) 307 { 308 mProgramBinary.set(NULL); 309 } 310 311 return mLinked; 312 } 313 314 void Program::release() 315 { 316 mRefCount--; 317 318 if (mRefCount == 0 && mDeleteStatus) 319 { 320 mResourceManager->deleteProgram(mHandle); 321 } 322 } 323 324 void Program::addRef() 325 { 326 mRefCount++; 327 } 328 329 unsigned int Program::getRefCount() const 330 { 331 return mRefCount; 332 } 333 334 GLint Program::getProgramBinaryLength() const 335 { 336 ProgramBinary *programBinary = mProgramBinary.get(); 337 if (programBinary) 338 { 339 return programBinary->getLength(); 340 } 341 else 342 { 343 return 0; 344 } 345 } 346 347 int Program::getInfoLogLength() const 348 { 349 return mInfoLog.getLength(); 350 } 351 352 void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) 353 { 354 return mInfoLog.getLog(bufSize, length, infoLog); 355 } 356 357 void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) 358 { 359 int total = 0; 360 361 if (mVertexShader) 362 { 363 if (total < maxCount) 364 { 365 shaders[total] = mVertexShader->getHandle(); 366 } 367 368 total++; 369 } 370 371 if (mFragmentShader) 372 { 373 if (total < maxCount) 374 { 375 shaders[total] = mFragmentShader->getHandle(); 376 } 377 378 total++; 379 } 380 381 if (count) 382 { 383 *count = total; 384 } 385 } 386 387 void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) 388 { 389 ProgramBinary *programBinary = getProgramBinary(); 390 if (programBinary) 391 { 392 programBinary->getActiveAttribute(index, bufsize, length, size, type, name); 393 } 394 else 395 { 396 if (bufsize > 0) 397 { 398 name[0] = '\0'; 399 } 400 401 if (length) 402 { 403 *length = 0; 404 } 405 406 *type = GL_NONE; 407 *size = 1; 408 } 409 } 410 411 GLint Program::getActiveAttributeCount() 412 { 413 ProgramBinary *programBinary = getProgramBinary(); 414 if (programBinary) 415 { 416 return programBinary->getActiveAttributeCount(); 417 } 418 else 419 { 420 return 0; 421 } 422 } 423 424 GLint Program::getActiveAttributeMaxLength() 425 { 426 ProgramBinary *programBinary = getProgramBinary(); 427 if (programBinary) 428 { 429 return programBinary->getActiveAttributeMaxLength(); 430 } 431 else 432 { 433 return 0; 434 } 435 } 436 437 void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) 438 { 439 ProgramBinary *programBinary = getProgramBinary(); 440 if (programBinary) 441 { 442 return programBinary->getActiveUniform(index, bufsize, length, size, type, name); 443 } 444 else 445 { 446 if (bufsize > 0) 447 { 448 name[0] = '\0'; 449 } 450 451 if (length) 452 { 453 *length = 0; 454 } 455 456 *size = 0; 457 *type = GL_NONE; 458 } 459 } 460 461 GLint Program::getActiveUniformCount() 462 { 463 ProgramBinary *programBinary = getProgramBinary(); 464 if (programBinary) 465 { 466 return programBinary->getActiveUniformCount(); 467 } 468 else 469 { 470 return 0; 471 } 472 } 473 474 GLint Program::getActiveUniformMaxLength() 475 { 476 ProgramBinary *programBinary = getProgramBinary(); 477 if (programBinary) 478 { 479 return programBinary->getActiveUniformMaxLength(); 480 } 481 else 482 { 483 return 0; 484 } 485 } 486 487 void Program::flagForDeletion() 488 { 489 mDeleteStatus = true; 490 } 491 492 bool Program::isFlaggedForDeletion() const 493 { 494 return mDeleteStatus; 495 } 496 497 void Program::validate() 498 { 499 mInfoLog.reset(); 500 501 ProgramBinary *programBinary = getProgramBinary(); 502 if (isLinked() && programBinary) 503 { 504 programBinary->validate(mInfoLog); 505 } 506 else 507 { 508 mInfoLog.append("Program has not been successfully linked."); 509 } 510 } 511 512 bool Program::isValidated() const 513 { 514 ProgramBinary *programBinary = mProgramBinary.get(); 515 if (programBinary) 516 { 517 return programBinary->isValidated(); 518 } 519 else 520 { 521 return false; 522 } 523 } 524 525 } 526