| // 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. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84. |
| |
| #include "Shader.h" |
| |
| #include "main.h" |
| #include "utilities.h" |
| |
| #include <string> |
| #include <algorithm> |
| |
| namespace es2 |
| { |
| 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'; |
| } |
| |
| size_t 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; |
| } |
| } |
| |
| size_t 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.MaxVertexOutputVectors = MAX_VERTEX_OUTPUT_VECTORS; |
| resources.MaxFragmentInputVectors = MAX_FRAGMENT_INPUT_VECTORS; |
| resources.MinProgramTexelOffset = MIN_PROGRAM_TEXEL_OFFSET; |
| resources.MaxProgramTexelOffset = MAX_PROGRAM_TEXEL_OFFSET; |
| resources.OES_standard_derivatives = 1; |
| resources.OES_fragment_precision_high = 1; |
| resources.OES_EGL_image_external = 1; |
| resources.EXT_draw_buffers = 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++; |
| } |
| |
| int shaderVersion = compiler->getShaderVersion(); |
| int clientVersion = es2::getContext()->getClientVersion(); |
| |
| if(shaderVersion >= 300 && clientVersion < 3) |
| { |
| infoLog = "GLSL ES 3.00 is not supported by OpenGL ES 2.0 contexts"; |
| success = false; |
| } |
| |
| 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() const |
| { |
| 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() const |
| { |
| 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; |
| } |
| |
| } |