summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libGLESv2/Shader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/Shader.cpp')
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Shader.cpp584
1 files changed, 584 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.cpp b/src/3rdparty/angle/src/libGLESv2/Shader.cpp
new file mode 100644
index 0000000000..1087f11b4a
--- /dev/null
+++ b/src/3rdparty/angle/src/libGLESv2/Shader.cpp
@@ -0,0 +1,584 @@
+//
+// Copyright (c) 2002-2012 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 "libGLESv2/Shader.h"
+
+#include <string>
+
+#include "GLSLANG/ShaderLang.h"
+#include "libGLESv2/main.h"
+#include "libGLESv2/utilities.h"
+
+namespace gl
+{
+void *Shader::mFragmentCompiler = NULL;
+void *Shader::mVertexCompiler = NULL;
+
+Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager)
+{
+ mSource = NULL;
+ mHlsl = NULL;
+ mInfoLog = NULL;
+
+ uncompile();
+ initializeCompiler();
+
+ mRefCount = 0;
+ mDeleteStatus = false;
+}
+
+Shader::~Shader()
+{
+ delete[] mSource;
+ delete[] mHlsl;
+ delete[] mInfoLog;
+}
+
+GLuint Shader::getHandle() const
+{
+ return mHandle;
+}
+
+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 (bufSize > 0)
+ {
+ if (mInfoLog)
+ {
+ index = std::min(bufSize - 1, (int)strlen(mInfoLog));
+ memcpy(infoLog, mInfoLog, index);
+ }
+
+ infoLog[index] = '\0';
+ }
+
+ if (length)
+ {
+ *length = index;
+ }
+}
+
+int Shader::getSourceLength() const
+{
+ if (!mSource)
+ {
+ return 0;
+ }
+ else
+ {
+ return strlen(mSource) + 1;
+ }
+}
+
+int Shader::getTranslatedSourceLength() const
+{
+ if (!mHlsl)
+ {
+ return 0;
+ }
+ else
+ {
+ return strlen(mHlsl) + 1;
+ }
+}
+
+void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer)
+{
+ int index = 0;
+
+ if (bufSize > 0)
+ {
+ if (source)
+ {
+ index = std::min(bufSize - 1, (int)strlen(source));
+ memcpy(buffer, source, index);
+ }
+
+ buffer[index] = '\0';
+ }
+
+ if (length)
+ {
+ *length = index;
+ }
+}
+
+void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer)
+{
+ getSourceImpl(mSource, bufSize, length, buffer);
+}
+
+void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer)
+{
+ getSourceImpl(mHlsl, bufSize, length, buffer);
+}
+
+bool Shader::isCompiled()
+{
+ return mHlsl != NULL;
+}
+
+const char *Shader::getHLSL()
+{
+ return mHlsl;
+}
+
+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;
+}
+
+// Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
+void Shader::initializeCompiler()
+{
+ if (!mFragmentCompiler)
+ {
+ int result = ShInitialize();
+
+ if (result)
+ {
+ ShBuiltInResources resources;
+ ShInitBuiltInResources(&resources);
+ Context *context = getContext();
+
+ resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
+ resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
+ resources.MaxVaryingVectors = context->getMaximumVaryingVectors();
+ resources.MaxVertexTextureImageUnits = context->getMaximumVertexTextureImageUnits();
+ resources.MaxCombinedTextureImageUnits = context->getMaximumCombinedTextureImageUnits();
+ resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+ resources.MaxFragmentUniformVectors = context->getMaximumFragmentUniformVectors();
+ resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
+ resources.OES_standard_derivatives = 1;
+ // resources.OES_EGL_image_external = getDisplay()->isD3d9ExDevice() ? 1 : 0; // TODO: commented out until the extension is actually supported.
+
+ mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
+ mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
+ }
+ }
+}
+
+void Shader::releaseCompiler()
+{
+ ShDestruct(mFragmentCompiler);
+ ShDestruct(mVertexCompiler);
+
+ mFragmentCompiler = NULL;
+ mVertexCompiler = NULL;
+
+ ShFinalize();
+}
+
+void Shader::parseVaryings()
+{
+ if (mHlsl)
+ {
+ const char *input = strstr(mHlsl, "// Varyings") + 12;
+
+ while(true)
+ {
+ char varyingType[256];
+ char varyingName[256];
+
+ int matches = sscanf(input, "static %255s %255s", varyingType, varyingName);
+
+ if (matches != 2)
+ {
+ break;
+ }
+
+ char *array = strstr(varyingName, "[");
+ int size = 1;
+
+ if (array)
+ {
+ size = atoi(array + 1);
+ *array = '\0';
+ }
+
+ mVaryings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
+
+ input = strstr(input, ";") + 2;
+ }
+
+ mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
+ mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
+ mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
+ mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
+ }
+}
+
+// initialize/clean up previous state
+void Shader::uncompile()
+{
+ // set by compileToHLSL
+ delete[] mHlsl;
+ mHlsl = NULL;
+ delete[] mInfoLog;
+ mInfoLog = NULL;
+
+ // set by parseVaryings
+ mVaryings.clear();
+
+ mUsesFragCoord = false;
+ mUsesFrontFacing = false;
+ mUsesPointSize = false;
+ mUsesPointCoord = false;
+}
+
+void Shader::compileToHLSL(void *compiler)
+{
+ // ensure we don't pass a NULL source to the compiler
+ char *source = "\0";
+ if (mSource)
+ {
+ source = mSource;
+ }
+
+ // ensure the compiler is loaded
+ initializeCompiler();
+
+ int compileOptions = SH_OBJECT_CODE;
+ std::string sourcePath;
+ if (perfActive())
+ {
+ sourcePath = getTempPath();
+ writeFile(sourcePath.c_str(), source, strlen(source));
+ compileOptions |= SH_LINE_DIRECTIVES;
+ }
+
+ int result;
+ if (sourcePath.empty())
+ {
+ result = ShCompile(compiler, &source, 1, compileOptions);
+ }
+ else
+ {
+ const char* sourceStrings[2] =
+ {
+ sourcePath.c_str(),
+ source
+ };
+
+ result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH);
+ }
+
+ if (result)
+ {
+ int objCodeLen = 0;
+ ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
+ mHlsl = new char[objCodeLen];
+ ShGetObjectCode(compiler, mHlsl);
+ }
+ else
+ {
+ int infoLogLen = 0;
+ ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
+ mInfoLog = new char[infoLogLen];
+ ShGetInfoLog(compiler, mInfoLog);
+
+ TRACE("\n%s", mInfoLog);
+ }
+}
+
+GLenum Shader::parseType(const std::string &type)
+{
+ if (type == "float")
+ {
+ return GL_FLOAT;
+ }
+ else if (type == "float2")
+ {
+ return GL_FLOAT_VEC2;
+ }
+ else if (type == "float3")
+ {
+ return GL_FLOAT_VEC3;
+ }
+ else if (type == "float4")
+ {
+ return GL_FLOAT_VEC4;
+ }
+ else if (type == "float2x2")
+ {
+ return GL_FLOAT_MAT2;
+ }
+ else if (type == "float3x3")
+ {
+ return GL_FLOAT_MAT3;
+ }
+ else if (type == "float4x4")
+ {
+ return GL_FLOAT_MAT4;
+ }
+ else UNREACHABLE();
+
+ return GL_NONE;
+}
+
+// true if varying x has a higher priority in packing than y
+bool Shader::compareVarying(const Varying &x, const 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();
+ }
+ 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();
+ }
+ 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();
+ }
+ 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();
+ }
+ 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();
+ }
+ break;
+ case GL_FLOAT: return false;
+ default: UNREACHABLE();
+ }
+
+ return false;
+}
+
+VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
+{
+}
+
+VertexShader::~VertexShader()
+{
+}
+
+GLenum VertexShader::getType()
+{
+ return GL_VERTEX_SHADER;
+}
+
+void VertexShader::uncompile()
+{
+ Shader::uncompile();
+
+ // set by ParseAttributes
+ mAttributes.clear();
+};
+
+void VertexShader::compile()
+{
+ uncompile();
+
+ compileToHLSL(mVertexCompiler);
+ parseAttributes();
+ parseVaryings();
+}
+
+int VertexShader::getSemanticIndex(const std::string &attributeName)
+{
+ if (!attributeName.empty())
+ {
+ int semanticIndex = 0;
+ for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
+ {
+ if (attribute->name == attributeName)
+ {
+ return semanticIndex;
+ }
+
+ semanticIndex += VariableRowCount(attribute->type);
+ }
+ }
+
+ return -1;
+}
+
+void VertexShader::parseAttributes()
+{
+ const char *hlsl = getHLSL();
+ if (hlsl)
+ {
+ const char *input = strstr(hlsl, "// Attributes") + 14;
+
+ while(true)
+ {
+ char attributeType[256];
+ char attributeName[256];
+
+ int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
+
+ if (matches != 2)
+ {
+ break;
+ }
+
+ mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
+
+ input = strstr(input, ";") + 2;
+ }
+ }
+}
+
+FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
+{
+}
+
+FragmentShader::~FragmentShader()
+{
+}
+
+GLenum FragmentShader::getType()
+{
+ return GL_FRAGMENT_SHADER;
+}
+
+void FragmentShader::compile()
+{
+ uncompile();
+
+ compileToHLSL(mFragmentCompiler);
+ parseVaryings();
+ mVaryings.sort(compareVarying);
+}
+}