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 19namespace gl 20{ 21void *Shader::mFragmentCompiler = NULL; 22void *Shader::mVertexCompiler = NULL; 23 24Shader::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 60Shader::~Shader() 61{ 62 delete[] mSource; 63 delete[] mHlsl; 64 delete[] mInfoLog; 65} 66 67GLuint Shader::getHandle() const 68{ 69 return mHandle; 70} 71 72void 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 112int Shader::getInfoLogLength() const 113{ 114 if (!mInfoLog) 115 { 116 return 0; 117 } 118 else 119 { 120 return strlen(mInfoLog) + 1; 121 } 122} 123 124void 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 148int Shader::getSourceLength() const 149{ 150 if (!mSource) 151 { 152 return 0; 153 } 154 else 155 { 156 return strlen(mSource) + 1; 157 } 158} 159 160void 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 184bool Shader::isCompiled() 185{ 186 return mHlsl != NULL; 187} 188 189const char *Shader::getHLSL() 190{ 191 return mHlsl; 192} 193 194void Shader::addRef() 195{ 196 mRefCount++; 197} 198 199void Shader::release() 200{ 201 mRefCount--; 202 203 if (mRefCount == 0 && mDeleteStatus) 204 { 205 mResourceManager->deleteShader(mHandle); 206 } 207} 208 209unsigned int Shader::getRefCount() const 210{ 211 return mRefCount; 212} 213 214bool Shader::isFlaggedForDeletion() const 215{ 216 return mDeleteStatus; 217} 218 219void Shader::flagForDeletion() 220{ 221 mDeleteStatus = true; 222} 223 224void Shader::releaseCompiler() 225{ 226 ShDestruct(mFragmentCompiler); 227 ShDestruct(mVertexCompiler); 228 229 mFragmentCompiler = NULL; 230 mVertexCompiler = NULL; 231 232 ShFinalize(); 233} 234 235void 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 274void 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 308GLenum 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 344bool 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 426VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) 427{ 428} 429 430VertexShader::~VertexShader() 431{ 432} 433 434GLenum VertexShader::getType() 435{ 436 return GL_VERTEX_SHADER; 437} 438 439void VertexShader::compile() 440{ 441 compileToHLSL(mVertexCompiler); 442 parseAttributes(); 443 parseVaryings(); 444} 445 446int 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 465void 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 490FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) 491{ 492} 493 494FragmentShader::~FragmentShader() 495{ 496} 497 498GLenum FragmentShader::getType() 499{ 500 return GL_FRAGMENT_SHADER; 501} 502 503void FragmentShader::compile() 504{ 505 compileToHLSL(mFragmentCompiler); 506 parseVaryings(); 507 varyings.sort(compareVarying); 508} 509} 510