|  | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | // Shader.cpp: Implements the Shader class and its  derived classes | 
|  | // VertexShader and FragmentShader. Implements GL shader objects and related | 
|  | // functionality. | 
|  |  | 
|  | #include "Shader.h" | 
|  |  | 
|  | #include "main.h" | 
|  | #include "utilities.h" | 
|  |  | 
|  | #include <string> | 
|  |  | 
|  | namespace gl | 
|  | { | 
|  | bool Shader::compilerInitialized = false; | 
|  |  | 
|  | Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager) | 
|  | { | 
|  | mSource = nullptr; | 
|  |  | 
|  | clear(); | 
|  |  | 
|  | mRefCount = 0; | 
|  | mDeleteStatus = false; | 
|  | } | 
|  |  | 
|  | Shader::~Shader() | 
|  | { | 
|  | delete[] mSource; | 
|  | } | 
|  |  | 
|  | GLuint Shader::getName() const | 
|  | { | 
|  | return mHandle; | 
|  | } | 
|  |  | 
|  | void Shader::setSource(GLsizei count, const char *const *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(infoLog.empty()) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | return infoLog.size() + 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLogOut) | 
|  | { | 
|  | int index = 0; | 
|  |  | 
|  | if(bufSize > 0) | 
|  | { | 
|  | if(!infoLog.empty()) | 
|  | { | 
|  | index = std::min(bufSize - 1, (GLsizei)infoLog.size()); | 
|  | memcpy(infoLogOut, infoLog.c_str(), index); | 
|  | } | 
|  |  | 
|  | infoLogOut[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(bufSize > 0) | 
|  | { | 
|  | if(mSource) | 
|  | { | 
|  | index = std::min(bufSize - 1, (int)strlen(mSource)); | 
|  | memcpy(source, mSource, index); | 
|  | } | 
|  |  | 
|  | source[index] = '\0'; | 
|  | } | 
|  |  | 
|  | if(length) | 
|  | { | 
|  | *length = index; | 
|  | } | 
|  | } | 
|  |  | 
|  | TranslatorASM *Shader::createCompiler(GLenum shaderType) | 
|  | { | 
|  | if(!compilerInitialized) | 
|  | { | 
|  | InitCompilerGlobals(); | 
|  | compilerInitialized = true; | 
|  | } | 
|  |  | 
|  | TranslatorASM *assembler = new TranslatorASM(this, shaderType); | 
|  |  | 
|  | ShBuiltInResources 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; | 
|  | resources.OES_standard_derivatives = 1; | 
|  | resources.OES_fragment_precision_high = 1; | 
|  | resources.MaxCallStackDepth = 16; | 
|  | assembler->Init(resources); | 
|  |  | 
|  | return assembler; | 
|  | } | 
|  |  | 
|  | void Shader::clear() | 
|  | { | 
|  | infoLog.clear(); | 
|  |  | 
|  | varyings.clear(); | 
|  | activeUniforms.clear(); | 
|  | activeAttributes.clear(); | 
|  | } | 
|  |  | 
|  | void Shader::compile() | 
|  | { | 
|  | clear(); | 
|  |  | 
|  | createShader(); | 
|  | TranslatorASM *compiler = createCompiler(getType()); | 
|  |  | 
|  | // Ensure we don't pass a nullptr source to the compiler | 
|  | const char *source = "\0"; | 
|  | if(mSource) | 
|  | { | 
|  | source = mSource; | 
|  | } | 
|  |  | 
|  | bool success = compiler->compile(&source, 1, SH_OBJECT_CODE); | 
|  |  | 
|  | if(false) | 
|  | { | 
|  | static int serial = 1; | 
|  | char buffer[256]; | 
|  | sprintf(buffer, "shader-input-%d-%d.txt", getName(), serial); | 
|  | FILE *file = fopen(buffer, "wt"); | 
|  | fprintf(file, "%s", mSource); | 
|  | fclose(file); | 
|  | getShader()->print("shader-output-%d-%d.txt", getName(), serial); | 
|  | serial++; | 
|  | } | 
|  |  | 
|  | if(!success) | 
|  | { | 
|  | deleteShader(); | 
|  |  | 
|  | infoLog = compiler->getInfoSink().info.c_str(); | 
|  | TRACE("\n%s", infoLog.c_str()); | 
|  | } | 
|  |  | 
|  | delete compiler; | 
|  | } | 
|  |  | 
|  | bool Shader::isCompiled() | 
|  | { | 
|  | return getShader() != 0; | 
|  | } | 
|  |  | 
|  | void Shader::addRef() | 
|  | { | 
|  | mRefCount++; | 
|  | } | 
|  |  | 
|  | void Shader::release() | 
|  | { | 
|  | mRefCount--; | 
|  |  | 
|  | if(mRefCount == 0 && mDeleteStatus) | 
|  | { | 
|  | mResourceManager->deleteShader(mHandle); | 
|  | } | 
|  | } | 
|  |  | 
|  | unsigned int Shader::getRefCount() const | 
|  | { | 
|  | return mRefCount; | 
|  | } | 
|  |  | 
|  | bool Shader::isFlaggedForDeletion() const | 
|  | { | 
|  | return mDeleteStatus; | 
|  | } | 
|  |  | 
|  | void Shader::flagForDeletion() | 
|  | { | 
|  | mDeleteStatus = true; | 
|  | } | 
|  |  | 
|  | void Shader::releaseCompiler() | 
|  | { | 
|  | FreeCompilerGlobals(); | 
|  | compilerInitialized = false; | 
|  | } | 
|  |  | 
|  | // true if varying x has a higher priority in packing than y | 
|  | bool Shader::compareVarying(const glsl::Varying &x, const glsl::Varying &y) | 
|  | { | 
|  | if(x.type == y.type) | 
|  | { | 
|  | return x.size() > y.size(); | 
|  | } | 
|  |  | 
|  | switch(x.type) | 
|  | { | 
|  | case GL_FLOAT_MAT4: return true; | 
|  | case GL_FLOAT_MAT2: | 
|  | switch(y.type) | 
|  | { | 
|  | case GL_FLOAT_MAT4: return false; | 
|  | case GL_FLOAT_MAT2: return true; | 
|  | case GL_FLOAT_VEC4: return true; | 
|  | case GL_FLOAT_MAT3: return true; | 
|  | case GL_FLOAT_VEC3: return true; | 
|  | case GL_FLOAT_VEC2: return true; | 
|  | case GL_FLOAT:      return true; | 
|  | default: UNREACHABLE(y.type); | 
|  | } | 
|  | break; | 
|  | case GL_FLOAT_VEC4: | 
|  | switch(y.type) | 
|  | { | 
|  | case GL_FLOAT_MAT4: return false; | 
|  | case GL_FLOAT_MAT2: return false; | 
|  | case GL_FLOAT_VEC4: return true; | 
|  | case GL_FLOAT_MAT3: return true; | 
|  | case GL_FLOAT_VEC3: return true; | 
|  | case GL_FLOAT_VEC2: return true; | 
|  | case GL_FLOAT:      return true; | 
|  | default: UNREACHABLE(y.type); | 
|  | } | 
|  | break; | 
|  | case GL_FLOAT_MAT3: | 
|  | switch(y.type) | 
|  | { | 
|  | case GL_FLOAT_MAT4: return false; | 
|  | case GL_FLOAT_MAT2: return false; | 
|  | case GL_FLOAT_VEC4: return false; | 
|  | case GL_FLOAT_MAT3: return true; | 
|  | case GL_FLOAT_VEC3: return true; | 
|  | case GL_FLOAT_VEC2: return true; | 
|  | case GL_FLOAT:      return true; | 
|  | default: UNREACHABLE(y.type); | 
|  | } | 
|  | break; | 
|  | case GL_FLOAT_VEC3: | 
|  | switch(y.type) | 
|  | { | 
|  | case GL_FLOAT_MAT4: return false; | 
|  | case GL_FLOAT_MAT2: return false; | 
|  | case GL_FLOAT_VEC4: return false; | 
|  | case GL_FLOAT_MAT3: return false; | 
|  | case GL_FLOAT_VEC3: return true; | 
|  | case GL_FLOAT_VEC2: return true; | 
|  | case GL_FLOAT:      return true; | 
|  | default: UNREACHABLE(y.type); | 
|  | } | 
|  | break; | 
|  | case GL_FLOAT_VEC2: | 
|  | switch(y.type) | 
|  | { | 
|  | case GL_FLOAT_MAT4: return false; | 
|  | case GL_FLOAT_MAT2: return false; | 
|  | case GL_FLOAT_VEC4: return false; | 
|  | case GL_FLOAT_MAT3: return false; | 
|  | case GL_FLOAT_VEC3: return false; | 
|  | case GL_FLOAT_VEC2: return true; | 
|  | case GL_FLOAT:      return true; | 
|  | default: UNREACHABLE(y.type); | 
|  | } | 
|  | break; | 
|  | case GL_FLOAT: return false; | 
|  | default: UNREACHABLE(x.type); | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) | 
|  | { | 
|  | vertexShader = 0; | 
|  | } | 
|  |  | 
|  | VertexShader::~VertexShader() | 
|  | { | 
|  | delete vertexShader; | 
|  | } | 
|  |  | 
|  | GLenum VertexShader::getType() | 
|  | { | 
|  | return GL_VERTEX_SHADER; | 
|  | } | 
|  |  | 
|  | int VertexShader::getSemanticIndex(const std::string &attributeName) | 
|  | { | 
|  | if(!attributeName.empty()) | 
|  | { | 
|  | for(glsl::ActiveAttributes::iterator attribute = activeAttributes.begin(); attribute != activeAttributes.end(); attribute++) | 
|  | { | 
|  | if(attribute->name == attributeName) | 
|  | { | 
|  | return attribute->registerIndex; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | sw::Shader *VertexShader::getShader() const | 
|  | { | 
|  | return vertexShader; | 
|  | } | 
|  |  | 
|  | sw::VertexShader *VertexShader::getVertexShader() const | 
|  | { | 
|  | return vertexShader; | 
|  | } | 
|  |  | 
|  | void VertexShader::createShader() | 
|  | { | 
|  | delete vertexShader; | 
|  | vertexShader = new sw::VertexShader(); | 
|  | } | 
|  |  | 
|  | void VertexShader::deleteShader() | 
|  | { | 
|  | delete vertexShader; | 
|  | vertexShader = nullptr; | 
|  | } | 
|  |  | 
|  | FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) | 
|  | { | 
|  | pixelShader = 0; | 
|  | } | 
|  |  | 
|  | FragmentShader::~FragmentShader() | 
|  | { | 
|  | delete pixelShader; | 
|  | } | 
|  |  | 
|  | GLenum FragmentShader::getType() | 
|  | { | 
|  | return GL_FRAGMENT_SHADER; | 
|  | } | 
|  |  | 
|  | sw::Shader *FragmentShader::getShader() const | 
|  | { | 
|  | return pixelShader; | 
|  | } | 
|  |  | 
|  | sw::PixelShader *FragmentShader::getPixelShader() const | 
|  | { | 
|  | return pixelShader; | 
|  | } | 
|  |  | 
|  | void FragmentShader::createShader() | 
|  | { | 
|  | delete pixelShader; | 
|  | pixelShader = new sw::PixelShader(); | 
|  | } | 
|  |  | 
|  | void FragmentShader::deleteShader() | 
|  | { | 
|  | delete pixelShader; | 
|  | pixelShader = nullptr; | 
|  | } | 
|  |  | 
|  | } |