diff options
Diffstat (limited to 'gfx/angle/src/libANGLE/Shader.cpp')
-rwxr-xr-x | gfx/angle/src/libANGLE/Shader.cpp | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/Shader.cpp b/gfx/angle/src/libANGLE/Shader.cpp new file mode 100755 index 000000000..a4c68950b --- /dev/null +++ b/gfx/angle/src/libANGLE/Shader.cpp @@ -0,0 +1,432 @@ +// +// Copyright (c) 2002-2014 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 "libANGLE/Shader.h" + +#include <sstream> + +#include "common/utilities.h" +#include "GLSLANG/ShaderLang.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Compiler.h" +#include "libANGLE/Constants.h" +#include "libANGLE/renderer/GLImplFactory.h" +#include "libANGLE/renderer/ShaderImpl.h" +#include "libANGLE/ResourceManager.h" +#include "libANGLE/Context.h" + +namespace gl +{ + +namespace +{ +template <typename VarT> +std::vector<VarT> GetActiveShaderVariables(const std::vector<VarT> *variableList) +{ + ASSERT(variableList); + std::vector<VarT> result; + for (size_t varIndex = 0; varIndex < variableList->size(); varIndex++) + { + const VarT &var = variableList->at(varIndex); + if (var.staticUse) + { + result.push_back(var); + } + } + return result; +} + +template <typename VarT> +const std::vector<VarT> &GetShaderVariables(const std::vector<VarT> *variableList) +{ + ASSERT(variableList); + return *variableList; +} + +} // anonymous namespace + +// true if varying x has a higher priority in packing than y +bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y) +{ + if (x.type == y.type) + { + return x.arraySize > y.arraySize; + } + + // Special case for handling structs: we sort these to the end of the list + if (x.type == GL_STRUCT_ANGLEX) + { + return false; + } + + if (y.type == GL_STRUCT_ANGLEX) + { + return true; + } + + return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type); +} + +ShaderState::ShaderState(GLenum shaderType) : mLabel(), mShaderType(shaderType), mShaderVersion(100) +{ + mLocalSize.fill(-1); +} + +ShaderState::~ShaderState() +{ +} + +Shader::Shader(ResourceManager *manager, + rx::GLImplFactory *implFactory, + const gl::Limitations &rendererLimitations, + GLenum type, + GLuint handle) + : mState(type), + mImplementation(implFactory->createShader(mState)), + mRendererLimitations(rendererLimitations), + mHandle(handle), + mType(type), + mRefCount(0), + mDeleteStatus(false), + mCompiled(false), + mResourceManager(manager) +{ + ASSERT(mImplementation); +} + +Shader::~Shader() +{ + SafeDelete(mImplementation); +} + +void Shader::setLabel(const std::string &label) +{ + mState.mLabel = label; +} + +const std::string &Shader::getLabel() const +{ + return mState.mLabel; +} + +GLuint Shader::getHandle() const +{ + return mHandle; +} + +void Shader::setSource(GLsizei count, const char *const *string, const GLint *length) +{ + std::ostringstream stream; + + for (int i = 0; i < count; i++) + { + if (length == nullptr || length[i] < 0) + { + stream.write(string[i], strlen(string[i])); + } + else + { + stream.write(string[i], length[i]); + } + } + + mState.mSource = stream.str(); +} + +int Shader::getInfoLogLength() const +{ + if (mInfoLog.empty()) + { + return 0; + } + + return (static_cast<int>(mInfoLog.length()) + 1); +} + +void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const +{ + int index = 0; + + if (bufSize > 0) + { + index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length())); + memcpy(infoLog, mInfoLog.c_str(), index); + + infoLog[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +int Shader::getSourceLength() const +{ + return mState.mSource.empty() ? 0 : (static_cast<int>(mState.mSource.length()) + 1); +} + +int Shader::getTranslatedSourceLength() const +{ + if (mState.mTranslatedSource.empty()) + { + return 0; + } + + return (static_cast<int>(mState.mTranslatedSource.length()) + 1); +} + +int Shader::getTranslatedSourceWithDebugInfoLength() const +{ + const std::string &debugInfo = mImplementation->getDebugInfo(); + if (debugInfo.empty()) + { + return 0; + } + + return (static_cast<int>(debugInfo.length()) + 1); +} + +void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer) +{ + int index = 0; + + if (bufSize > 0) + { + index = std::min(bufSize - 1, static_cast<GLsizei>(source.length())); + memcpy(buffer, source.c_str(), index); + + buffer[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const +{ + getSourceImpl(mState.mSource, bufSize, length, buffer); +} + +void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const +{ + getSourceImpl(mState.mTranslatedSource, bufSize, length, buffer); +} + +void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const +{ + const std::string &debugInfo = mImplementation->getDebugInfo(); + getSourceImpl(debugInfo, bufSize, length, buffer); +} + +void Shader::compile(const Context *context) +{ + mState.mTranslatedSource.clear(); + mInfoLog.clear(); + mState.mShaderVersion = 100; + mState.mVaryings.clear(); + mState.mUniforms.clear(); + mState.mInterfaceBlocks.clear(); + mState.mActiveAttributes.clear(); + mState.mActiveOutputVariables.clear(); + + Compiler *compiler = context->getCompiler(); + ShHandle compilerHandle = compiler->getCompilerHandle(mState.mShaderType); + + std::stringstream sourceStream; + + std::string sourcePath; + ShCompileOptions additionalOptions = + mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath); + ShCompileOptions compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions); + + // Add default options to WebGL shaders to prevent unexpected behavior during compilation. + if (context->getExtensions().webglCompatibility) + { + compileOptions |= SH_LIMIT_CALL_STACK_DEPTH; + compileOptions |= SH_LIMIT_EXPRESSION_COMPLEXITY; + compileOptions |= SH_ENFORCE_PACKING_RESTRICTIONS; + } + + // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes + // in fragment shaders. Shader compilation will fail. To provide a better error message we can + // instruct the compiler to pre-validate. + if (mRendererLimitations.shadersRequireIndexedLoopValidation) + { + compileOptions |= SH_VALIDATE_LOOP_INDEXING; + } + + std::string sourceString = sourceStream.str(); + std::vector<const char *> sourceCStrings; + + if (!sourcePath.empty()) + { + sourceCStrings.push_back(sourcePath.c_str()); + } + + sourceCStrings.push_back(sourceString.c_str()); + + bool result = + sh::Compile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions); + + if (!result) + { + mInfoLog = sh::GetInfoLog(compilerHandle); + TRACE("\n%s", mInfoLog.c_str()); + mCompiled = false; + return; + } + + mState.mTranslatedSource = sh::GetObjectCode(compilerHandle); + +#ifndef NDEBUG + // Prefix translated shader with commented out un-translated shader. + // Useful in diagnostics tools which capture the shader source. + std::ostringstream shaderStream; + shaderStream << "// GLSL\n"; + shaderStream << "//\n"; + + size_t curPos = 0; + while (curPos != std::string::npos) + { + size_t nextLine = mState.mSource.find("\n", curPos); + size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1); + + shaderStream << "// " << mState.mSource.substr(curPos, len); + + curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1); + } + shaderStream << "\n\n"; + shaderStream << mState.mTranslatedSource; + mState.mTranslatedSource = shaderStream.str(); +#endif + + // Gather the shader information + mState.mShaderVersion = sh::GetShaderVersion(compilerHandle); + + mState.mVaryings = GetShaderVariables(sh::GetVaryings(compilerHandle)); + mState.mUniforms = GetShaderVariables(sh::GetUniforms(compilerHandle)); + mState.mInterfaceBlocks = GetShaderVariables(sh::GetInterfaceBlocks(compilerHandle)); + + switch (mState.mShaderType) + { + case GL_COMPUTE_SHADER: + { + mState.mLocalSize = sh::GetComputeShaderLocalGroupSize(compilerHandle); + break; + } + case GL_VERTEX_SHADER: + { + mState.mActiveAttributes = GetActiveShaderVariables(sh::GetAttributes(compilerHandle)); + break; + } + case GL_FRAGMENT_SHADER: + { + // TODO(jmadill): Figure out why we only sort in the FS, and if we need to. + std::sort(mState.mVaryings.begin(), mState.mVaryings.end(), CompareShaderVar); + mState.mActiveOutputVariables = + GetActiveShaderVariables(sh::GetOutputVariables(compilerHandle)); + break; + } + default: + UNREACHABLE(); + } + + ASSERT(!mState.mTranslatedSource.empty()); + + mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog); +} + +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; +} + +int Shader::getShaderVersion() const +{ + return mState.mShaderVersion; +} + +const std::vector<sh::Varying> &Shader::getVaryings() const +{ + return mState.getVaryings(); +} + +const std::vector<sh::Uniform> &Shader::getUniforms() const +{ + return mState.getUniforms(); +} + +const std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks() const +{ + return mState.getInterfaceBlocks(); +} + +const std::vector<sh::Attribute> &Shader::getActiveAttributes() const +{ + return mState.getActiveAttributes(); +} + +const std::vector<sh::OutputVariable> &Shader::getActiveOutputVariables() const +{ + return mState.getActiveOutputVariables(); +} + +int Shader::getSemanticIndex(const std::string &attributeName) const +{ + if (!attributeName.empty()) + { + const auto &activeAttributes = mState.getActiveAttributes(); + + int semanticIndex = 0; + for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++) + { + const sh::ShaderVariable &attribute = activeAttributes[attributeIndex]; + + if (attribute.name == attributeName) + { + return semanticIndex; + } + + semanticIndex += gl::VariableRegisterCount(attribute.type); + } + } + + return -1; +} + +} |