1 // 2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Shader.cpp: Implements the gl::Shader class and its derived classes 8 // VertexShader and FragmentShader. Implements GL shader objects and related 9 // functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84. 10 11 #include "libGLESv2/Shader.h" 12 13 #include <string> 14 15 #include "GLSLANG/Shaderlang.h" 16 #include "libGLESv2/main.h" 17 #include "libGLESv2/utilities.h" 18 19 namespace gl 20 { 21 void *Shader::mFragmentCompiler = NULL; 22 void *Shader::mVertexCompiler = NULL; 23 24 Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager) 25 { 26 mSource = NULL; 27 mHlsl = NULL; 28 mInfoLog = NULL; 29 30 // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler) 31 if (!mFragmentCompiler) 32 { 33 int result = ShInitialize(); 34 35 if (result) 36 { 37 ShBuiltInResources resources; 38 ShInitBuiltInResources(&resources); 39 Context *context = getContext(); 40 41 resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS; 42 resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS; 43 resources.MaxVaryingVectors = context->getMaximumVaryingVectors(); 44 resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS; 45 resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS; 46 resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; 47 resources.MaxFragmentUniformVectors = context->getMaximumFragmentUniformVectors(); 48 resources.MaxDrawBuffers = MAX_DRAW_BUFFERS; 49 resources.OES_standard_derivatives = 1; 50 51 mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources); 52 mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources); 53 } 54 } 55 56 mRefCount = 0; 57 mDeleteStatus = false; 58 } 59 60 Shader::~Shader() 61 { 62 delete[] mSource; 63 delete[] mHlsl; 64 delete[] mInfoLog; 65 } 66 67 GLuint Shader::getHandle() const 68 { 69 return mHandle; 70 } 71 72 void Shader::setSource(GLsizei count, const char **string, const GLint *length) 73 { 74 delete[] mSource; 75 int totalLength = 0; 76 77 for (int i = 0; i < count; i++) 78 { 79 if (length && length[i] >= 0) 80 { 81 totalLength += length[i]; 82 } 83 else 84 { 85 totalLength += (int)strlen(string[i]); 86 } 87 } 88 89 mSource = new char[totalLength + 1]; 90 char *code = mSource; 91 92 for (int i = 0; i < count; i++) 93 { 94 int stringLength; 95 96 if (length && length[i] >= 0) 97 { 98 stringLength = length[i]; 99 } 100 else 101 { 102 stringLength = (int)strlen(string[i]); 103 } 104 105 strncpy(code, string[i], stringLength); 106 code += stringLength; 107 } 108 109 mSource[totalLength] = '\0'; 110 } 111 112 int Shader::getInfoLogLength() const 113 { 114 if (!mInfoLog) 115 { 116 return 0; 117 } 118 else 119 { 120 return strlen(mInfoLog) + 1; 121 } 122 } 123 124 void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) 125 { 126 int index = 0; 127 128 if (mInfoLog) 129 { 130 while (index < bufSize - 1 && index < (int)strlen(mInfoLog)) 131 { 132 infoLog[index] = mInfoLog[index]; 133 index++; 134 } 135 } 136 137 if (bufSize) 138 { 139 infoLog[index] = '\0'; 140 } 141 142 if (length) 143 { 144 *length = index; 145 } 146 } 147 148 int Shader::getSourceLength() const 149 { 150 if (!mSource) 151 { 152 return 0; 153 } 154 else 155 { 156 return strlen(mSource) + 1; 157 } 158 } 159 160 void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source) 161 { 162 int index = 0; 163 164 if (mSource) 165 { 166 while (index < bufSize - 1 && index < (int)strlen(mSource)) 167 { 168 source[index] = mSource[index]; 169 index++; 170 } 171 } 172 173 if (bufSize) 174 { 175 source[index] = '\0'; 176 } 177 178 if (length) 179 { 180 *length = index; 181 } 182 } 183 184 bool Shader::isCompiled() 185 { 186 return mHlsl != NULL; 187 } 188 189 const char *Shader::getHLSL() 190 { 191 return mHlsl; 192 } 193 194 void Shader::addRef() 195 { 196 mRefCount++; 197 } 198 199 void Shader::release() 200 { 201 mRefCount--; 202 203 if (mRefCount == 0 && mDeleteStatus) 204 { 205 mResourceManager->deleteShader(mHandle); 206 } 207 } 208 209 unsigned int Shader::getRefCount() const 210 { 211 return mRefCount; 212 } 213 214 bool Shader::isFlaggedForDeletion() const 215 { 216 return mDeleteStatus; 217 } 218 219 void Shader::flagForDeletion() 220 { 221 mDeleteStatus = true; 222 } 223 224 void Shader::releaseCompiler() 225 { 226 ShDestruct(mFragmentCompiler); 227 ShDestruct(mVertexCompiler); 228 229 mFragmentCompiler = NULL; 230 mVertexCompiler = NULL; 231 232 ShFinalize(); 233 } 234 235 void Shader::parseVaryings() 236 { 237 if (mHlsl) 238 { 239 const char *input = strstr(mHlsl, "// Varyings") + 12; 240 241 while(true) 242 { 243 char varyingType[256]; 244 char varyingName[256]; 245 246 int matches = sscanf(input, "static %255s %255s", varyingType, varyingName); 247 248 if (matches != 2) 249 { 250 break; 251 } 252 253 char *array = strstr(varyingName, "["); 254 int size = 1; 255 256 if (array) 257 { 258 size = atoi(array + 1); 259 *array = '\0'; 260 } 261 262 varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL)); 263 264 input = strstr(input, ";") + 2; 265 } 266 267 mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL; 268 mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL; 269 mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL; 270 mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL; 271 } 272 } 273 274 void Shader::compileToHLSL(void *compiler) 275 { 276 if (isCompiled() || !mSource) 277 { 278 return; 279 } 280 281 TRACE("\n%s", mSource); 282 283 delete[] mInfoLog; 284 mInfoLog = NULL; 285 286 int result = ShCompile(compiler, &mSource, 1, SH_OBJECT_CODE); 287 288 if (result) 289 { 290 int objCodeLen = 0; 291 ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen); 292 mHlsl = new char[objCodeLen]; 293 ShGetObjectCode(compiler, mHlsl); 294 295 TRACE("\n%s", mHlsl); 296 } 297 else 298 { 299 int infoLogLen = 0; 300 ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen); 301 mInfoLog = new char[infoLogLen]; 302 ShGetInfoLog(compiler, mInfoLog); 303 304 TRACE("\n%s", mInfoLog); 305 } 306 } 307 308 GLenum Shader::parseType(const std::string &type) 309 { 310 if (type == "float") 311 { 312 return GL_FLOAT; 313 } 314 else if (type == "float2") 315 { 316 return GL_FLOAT_VEC2; 317 } 318 else if (type == "float3") 319 { 320 return GL_FLOAT_VEC3; 321 } 322 else if (type == "float4") 323 { 324 return GL_FLOAT_VEC4; 325 } 326 else if (type == "float2x2") 327 { 328 return GL_FLOAT_MAT2; 329 } 330 else if (type == "float3x3") 331 { 332 return GL_FLOAT_MAT3; 333 } 334 else if (type == "float4x4") 335 { 336 return GL_FLOAT_MAT4; 337 } 338 else UNREACHABLE(); 339 340 return GL_NONE; 341 } 342 343 // true if varying x has a higher priority in packing than y 344 bool Shader::compareVarying(const Varying &x, const Varying &y) 345 { 346 if(x.type == y.type) 347 { 348 return x.size > y.size; 349 } 350 351 switch (x.type) 352 { 353 case GL_FLOAT_MAT4: return true; 354 case GL_FLOAT_MAT2: 355 switch(y.type) 356 { 357 case GL_FLOAT_MAT4: return false; 358 case GL_FLOAT_MAT2: return true; 359 case GL_FLOAT_VEC4: return true; 360 case GL_FLOAT_MAT3: return true; 361 case GL_FLOAT_VEC3: return true; 362 case GL_FLOAT_VEC2: return true; 363 case GL_FLOAT: return true; 364 default: UNREACHABLE(); 365 } 366 break; 367 case GL_FLOAT_VEC4: 368 switch(y.type) 369 { 370 case GL_FLOAT_MAT4: return false; 371 case GL_FLOAT_MAT2: return false; 372 case GL_FLOAT_VEC4: return true; 373 case GL_FLOAT_MAT3: return true; 374 case GL_FLOAT_VEC3: return true; 375 case GL_FLOAT_VEC2: return true; 376 case GL_FLOAT: return true; 377 default: UNREACHABLE(); 378 } 379 break; 380 case GL_FLOAT_MAT3: 381 switch(y.type) 382 { 383 case GL_FLOAT_MAT4: return false; 384 case GL_FLOAT_MAT2: return false; 385 case GL_FLOAT_VEC4: return false; 386 case GL_FLOAT_MAT3: return true; 387 case GL_FLOAT_VEC3: return true; 388 case GL_FLOAT_VEC2: return true; 389 case GL_FLOAT: return true; 390 default: UNREACHABLE(); 391 } 392 break; 393 case GL_FLOAT_VEC3: 394 switch(y.type) 395 { 396 case GL_FLOAT_MAT4: return false; 397 case GL_FLOAT_MAT2: return false; 398 case GL_FLOAT_VEC4: return false; 399 case GL_FLOAT_MAT3: return false; 400 case GL_FLOAT_VEC3: return true; 401 case GL_FLOAT_VEC2: return true; 402 case GL_FLOAT: return true; 403 default: UNREACHABLE(); 404 } 405 break; 406 case GL_FLOAT_VEC2: 407 switch(y.type) 408 { 409 case GL_FLOAT_MAT4: return false; 410 case GL_FLOAT_MAT2: return false; 411 case GL_FLOAT_VEC4: return false; 412 case GL_FLOAT_MAT3: return false; 413 case GL_FLOAT_VEC3: return false; 414 case GL_FLOAT_VEC2: return true; 415 case GL_FLOAT: return true; 416 default: UNREACHABLE(); 417 } 418 break; 419 case GL_FLOAT: return false; 420 default: UNREACHABLE(); 421 } 422 423 return false; 424 } 425 426 VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) 427 { 428 } 429 430 VertexShader::~VertexShader() 431 { 432 } 433 434 GLenum VertexShader::getType() 435 { 436 return GL_VERTEX_SHADER; 437 } 438 439 void VertexShader::compile() 440 { 441 compileToHLSL(mVertexCompiler); 442 parseAttributes(); 443 parseVaryings(); 444 } 445 446 int VertexShader::getSemanticIndex(const std::string &attributeName) 447 { 448 if (!attributeName.empty()) 449 { 450 int semanticIndex = 0; 451 for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++) 452 { 453 if (attribute->name == attributeName) 454 { 455 return semanticIndex; 456 } 457 458 semanticIndex += VariableRowCount(attribute->type); 459 } 460 } 461 462 return -1; 463 } 464 465 void VertexShader::parseAttributes() 466 { 467 if (mHlsl) 468 { 469 const char *input = strstr(mHlsl, "// Attributes") + 14; 470 471 while(true) 472 { 473 char attributeType[256]; 474 char attributeName[256]; 475 476 int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName); 477 478 if (matches != 2) 479 { 480 break; 481 } 482 483 mAttributes.push_back(Attribute(parseType(attributeType), attributeName)); 484 485 input = strstr(input, ";") + 2; 486 } 487 } 488 } 489 490 FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) 491 { 492 } 493 494 FragmentShader::~FragmentShader() 495 { 496 } 497 498 GLenum FragmentShader::getType() 499 { 500 return GL_FRAGMENT_SHADER; 501 } 502 503 void FragmentShader::compile() 504 { 505 compileToHLSL(mFragmentCompiler); 506 parseVaryings(); 507 varyings.sort(compareVarying); 508 } 509 } 510