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 15namespace gl 16{ 17const char * const g_fakepath = "C:\\fakepath"; 18 19AttributeBindings::AttributeBindings() 20{ 21} 22 23AttributeBindings::~AttributeBindings() 24{ 25} 26 27InfoLog::InfoLog() : mInfoLog(NULL) 28{ 29} 30 31InfoLog::~InfoLog() 32{ 33 delete[] mInfoLog; 34} 35 36 37int InfoLog::getLength() const 38{ 39 if (!mInfoLog) 40 { 41 return 0; 42 } 43 else 44 { 45 return strlen(mInfoLog) + 1; 46 } 47} 48 49void 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. 73void 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 91void 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 126void InfoLog::reset() 127{ 128 if (mInfoLog) 129 { 130 delete [] mInfoLog; 131 mInfoLog = NULL; 132 } 133} 134 135Program::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 146Program::~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 161bool 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 188bool 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 215int Program::getAttachedShadersCount() const 216{ 217 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0); 218} 219 220void 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 233void 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 241bool 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 253int 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 267void 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 288bool Program::isLinked() 289{ 290 return mLinked; 291} 292 293ProgramBinary* Program::getProgramBinary() 294{ 295 return mProgramBinary.get(); 296} 297 298bool 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 314void Program::release() 315{ 316 mRefCount--; 317 318 if (mRefCount == 0 && mDeleteStatus) 319 { 320 mResourceManager->deleteProgram(mHandle); 321 } 322} 323 324void Program::addRef() 325{ 326 mRefCount++; 327} 328 329unsigned int Program::getRefCount() const 330{ 331 return mRefCount; 332} 333 334GLint 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 347int Program::getInfoLogLength() const 348{ 349 return mInfoLog.getLength(); 350} 351 352void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) 353{ 354 return mInfoLog.getLog(bufSize, length, infoLog); 355} 356 357void 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 387void 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 411GLint 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 424GLint 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 437void 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 461GLint 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 474GLint 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 487void Program::flagForDeletion() 488{ 489 mDeleteStatus = true; 490} 491 492bool Program::isFlaggedForDeletion() const 493{ 494 return mDeleteStatus; 495} 496 497void 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 512bool 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