| // |
| // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // Shader.cpp: Implements the gl::Shader class and its derived classes |
| // VertexShader and FragmentShader. Implements GL shader objects and related |
| // functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84. |
| |
| #include "Shader.h" |
| |
| #include "main.h" |
| #include "GLSLANG/Shaderlang.h" |
| #include "compiler/OutputHLSL.h" |
| #include "common/debug.h" |
| |
| namespace gl |
| { |
| void *Shader::mFragmentCompiler = NULL; |
| void *Shader::mVertexCompiler = NULL; |
| |
| Shader::Shader() |
| { |
| mSource = NULL; |
| mHlsl = NULL; |
| mInfoLog = NULL; |
| |
| // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler) |
| if (!mFragmentCompiler) |
| { |
| int result = ShInitialize(); |
| |
| if (result) |
| { |
| mFragmentCompiler = ShConstructCompiler(EShLangFragment, EDebugOpObjectCode); |
| mVertexCompiler = ShConstructCompiler(EShLangVertex, EDebugOpObjectCode); |
| } |
| } |
| |
| mAttachCount = 0; |
| mDeleteStatus = false; |
| } |
| |
| Shader::~Shader() |
| { |
| delete[] mSource; |
| delete[] mHlsl; |
| delete[] mInfoLog; |
| } |
| |
| void Shader::setSource(GLsizei count, const char **string, const GLint *length) |
| { |
| delete[] mSource; |
| int totalLength = 0; |
| |
| for (int i = 0; i < count; i++) |
| { |
| if (length && length[i] >= 0) |
| { |
| totalLength += length[i]; |
| } |
| else |
| { |
| totalLength += (int)strlen(string[i]); |
| } |
| } |
| |
| mSource = new char[totalLength + 1]; |
| char *code = mSource; |
| |
| for (int i = 0; i < count; i++) |
| { |
| int stringLength; |
| |
| if (length && length[i] >= 0) |
| { |
| stringLength = length[i]; |
| } |
| else |
| { |
| stringLength = (int)strlen(string[i]); |
| } |
| |
| strncpy(code, string[i], stringLength); |
| code += stringLength; |
| } |
| |
| mSource[totalLength] = '\0'; |
| } |
| |
| int Shader::getInfoLogLength() const |
| { |
| if (!mInfoLog) |
| { |
| return 0; |
| } |
| else |
| { |
| return strlen(mInfoLog) + 1; |
| } |
| } |
| |
| void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) |
| { |
| int index = 0; |
| |
| if (mInfoLog) |
| { |
| while (index < bufSize - 1 && index < (int)strlen(mInfoLog)) |
| { |
| infoLog[index] = mInfoLog[index]; |
| index++; |
| } |
| } |
| |
| if (bufSize) |
| { |
| infoLog[index] = '\0'; |
| } |
| |
| if (length) |
| { |
| *length = index; |
| } |
| } |
| |
| int Shader::getSourceLength() const |
| { |
| if (!mSource) |
| { |
| return 0; |
| } |
| else |
| { |
| return strlen(mSource) + 1; |
| } |
| } |
| |
| void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source) |
| { |
| int index = 0; |
| |
| if (mSource) |
| { |
| while (index < bufSize - 1 && index < (int)strlen(mInfoLog)) |
| { |
| source[index] = mSource[index]; |
| index++; |
| } |
| } |
| |
| if (bufSize) |
| { |
| source[index] = '\0'; |
| } |
| |
| if (length) |
| { |
| *length = index; |
| } |
| } |
| |
| bool Shader::isCompiled() |
| { |
| return mHlsl != NULL; |
| } |
| |
| const char *Shader::linkHLSL() |
| { |
| return mHlsl; |
| } |
| |
| void Shader::attach() |
| { |
| mAttachCount++; |
| } |
| |
| void Shader::detach() |
| { |
| mAttachCount--; |
| } |
| |
| bool Shader::isAttached() const |
| { |
| return mAttachCount > 0; |
| } |
| |
| bool Shader::isDeletable() const |
| { |
| return mDeleteStatus == true && mAttachCount == 0; |
| } |
| |
| bool Shader::isFlaggedForDeletion() const |
| { |
| return mDeleteStatus; |
| } |
| |
| void Shader::flagForDeletion() |
| { |
| mDeleteStatus = true; |
| } |
| |
| void Shader::releaseCompiler() |
| { |
| ShDestruct(mFragmentCompiler); |
| ShDestruct(mVertexCompiler); |
| |
| mFragmentCompiler = NULL; |
| mVertexCompiler = NULL; |
| } |
| |
| void Shader::compileToHLSL(void *compiler) |
| { |
| if (isCompiled() || !mSource) |
| { |
| return; |
| } |
| |
| TRACE("\n%s", mSource); |
| |
| delete[] mInfoLog; |
| mInfoLog = NULL; |
| |
| TBuiltInResource resources; |
| |
| resources.maxVertexAttribs = MAX_VERTEX_ATTRIBS; |
| resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS; |
| resources.maxVaryingVectors = MAX_VARYING_VECTORS; |
| resources.maxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS; |
| resources.maxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS; |
| resources.maxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; |
| resources.maxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS; |
| resources.maxDrawBuffers = MAX_DRAW_BUFFERS; |
| |
| int result = ShCompile(compiler, &mSource, 1, EShOptNone, &resources, EDebugOpObjectCode); |
| const char *obj = ShGetObjectCode(compiler); |
| const char *info = ShGetInfoLog(compiler); |
| |
| if (result) |
| { |
| mHlsl = new char[strlen(obj) + 1]; |
| strcpy(mHlsl, obj); |
| |
| TRACE("\n%s", mHlsl); |
| } |
| else |
| { |
| mInfoLog = new char[strlen(info) + 1]; |
| strcpy(mInfoLog, info); |
| |
| TRACE("\n%s", mInfoLog); |
| } |
| } |
| |
| InputMapping::InputMapping() |
| { |
| mAttribute = NULL; |
| mSemanticIndex = -1; |
| } |
| |
| InputMapping::InputMapping(const char *attribute, int semanticIndex) |
| { |
| mAttribute = new char[strlen(attribute) + 1]; |
| strcpy(mAttribute, attribute); |
| mSemanticIndex = semanticIndex; |
| } |
| |
| InputMapping &InputMapping::operator=(const InputMapping &inputMapping) |
| { |
| delete[] mAttribute; |
| |
| mAttribute = new char[strlen(inputMapping.mAttribute) + 1]; |
| strcpy(mAttribute, inputMapping.mAttribute); |
| mSemanticIndex = inputMapping.mSemanticIndex; |
| |
| return *this; |
| } |
| |
| InputMapping::~InputMapping() |
| { |
| delete[] mAttribute; |
| } |
| |
| VertexShader::VertexShader() |
| { |
| } |
| |
| VertexShader::~VertexShader() |
| { |
| } |
| |
| GLenum VertexShader::getType() |
| { |
| return GL_VERTEX_SHADER; |
| } |
| |
| void VertexShader::compile() |
| { |
| compileToHLSL(mVertexCompiler); |
| parseAttributes(); |
| } |
| |
| const char *VertexShader::linkHLSL(const char *pixelHLSL) |
| { |
| if (mHlsl && pixelHLSL) |
| { |
| const char *input = strstr(pixelHLSL, "struct PS_INPUT"); |
| char *output = strstr(mHlsl, "struct VS_OUTPUT"); |
| |
| while (*input != '}' && output) |
| { |
| char varyingName[100]; |
| unsigned int semanticIndex; |
| int matches = sscanf(input, "%s : TEXCOORD%d;", varyingName, &semanticIndex); |
| |
| if (matches == 2 && semanticIndex != sh::HLSL_FRAG_COORD_SEMANTIC) |
| { |
| ASSERT(semanticIndex < MAX_VARYING_VECTORS); |
| char *varying = strstr(output, varyingName); |
| |
| if (varying) |
| { |
| ASSERT(semanticIndex <= 9); // Single character |
| varying = strstr(varying, " : TEXCOORD0;"); |
| varying[11] = '0' + semanticIndex; |
| } |
| else |
| { |
| return NULL; |
| } |
| |
| input = strstr(input, ";"); |
| } |
| |
| input++; |
| } |
| } |
| |
| return mHlsl; |
| } |
| |
| const char *VertexShader::getAttributeName(unsigned int attributeIndex) |
| { |
| if (attributeIndex < MAX_VERTEX_ATTRIBS) |
| { |
| return mInputMapping[attributeIndex].mAttribute; |
| } |
| |
| return 0; |
| } |
| |
| bool VertexShader::isActiveAttribute(const char *attributeName) |
| { |
| return getInputMapping(attributeName) != -1; |
| } |
| |
| int VertexShader::getInputMapping(const char *attributeName) |
| { |
| if (attributeName) |
| { |
| for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) |
| { |
| if (mInputMapping[index].mAttribute && strcmp(mInputMapping[index].mAttribute, attributeName) == 0) |
| { |
| return mInputMapping[index].mSemanticIndex; |
| } |
| } |
| } |
| |
| return -1; |
| } |
| |
| void VertexShader::parseAttributes() |
| { |
| if (mHlsl) |
| { |
| const char *input = strstr(mHlsl, "struct VS_INPUT"); |
| |
| for (int attributeIndex = 0; *input != '}'; input++) |
| { |
| char attributeName[100]; |
| int semanticIndex; |
| |
| int matches = sscanf(input, "%s : TEXCOORD%d;", attributeName, &semanticIndex); |
| |
| if (matches == 2) |
| { |
| ASSERT(attributeIndex < MAX_VERTEX_ATTRIBS); |
| mInputMapping[attributeIndex] = InputMapping(attributeName, semanticIndex); |
| attributeIndex++; |
| |
| input = strstr(input, ";"); |
| } |
| } |
| } |
| } |
| |
| FragmentShader::FragmentShader() |
| { |
| } |
| |
| FragmentShader::~FragmentShader() |
| { |
| } |
| |
| GLenum FragmentShader::getType() |
| { |
| return GL_FRAGMENT_SHADER; |
| } |
| |
| void FragmentShader::compile() |
| { |
| compileToHLSL(mFragmentCompiler); |
| } |
| } |