summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp')
-rw-r--r--src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp3206
1 files changed, 1722 insertions, 1484 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp
index 13c515a594..9fad5fbfc5 100644
--- a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp
@@ -1,6 +1,6 @@
#include "precompiled.h"
//
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// 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.
//
@@ -10,50 +10,182 @@
#include "libGLESv2/BinaryStream.h"
#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Renderbuffer.h"
#include "libGLESv2/renderer/ShaderExecutable.h"
#include "common/debug.h"
#include "common/version.h"
-#include "utilities.h"
+#include "common/utilities.h"
#include "libGLESv2/main.h"
#include "libGLESv2/Shader.h"
#include "libGLESv2/Program.h"
#include "libGLESv2/renderer/Renderer.h"
-#include "libGLESv2/renderer/VertexDataManager.h"
+#include "libGLESv2/renderer/d3d/VertexDataManager.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/DynamicHLSL.h"
+#include "common/blocklayout.h"
#undef near
#undef far
namespace gl
{
-std::string str(int i)
+
+namespace
+{
+
+TextureType GetTextureType(GLenum samplerType)
{
- char buffer[20];
- snprintf(buffer, sizeof(buffer), "%d", i);
- return buffer;
+ switch (samplerType)
+ {
+ case GL_SAMPLER_2D:
+ case GL_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_SAMPLER_2D_SHADOW:
+ return TEXTURE_2D;
+ case GL_SAMPLER_3D:
+ case GL_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ return TEXTURE_3D;
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_CUBE_SHADOW:
+ return TEXTURE_CUBE;
+ case GL_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ return TEXTURE_CUBE;
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ return TEXTURE_2D_ARRAY;
+ default: UNREACHABLE();
+ }
+
+ return TEXTURE_2D;
}
-static rx::D3DWorkaroundType DiscardWorkaround(bool usesDiscard)
+unsigned int ParseAndStripArrayIndex(std::string* name)
{
- return (usesDiscard ? rx::ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER : rx::ANGLE_D3D_WORKAROUND_NONE);
+ unsigned int subscript = GL_INVALID_INDEX;
+
+ // Strip any trailing array operator and retrieve the subscript
+ size_t open = name->find_last_of('[');
+ size_t close = name->find_last_of(']');
+ if (open != std::string::npos && close == name->length() - 1)
+ {
+ subscript = atoi(name->substr(open + 1).c_str());
+ name->erase(open);
+ }
+
+ return subscript;
}
-UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
+void GetInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
+{
+ size_t layoutIndex = 0;
+ for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
+ {
+ ASSERT(layoutIndex < MAX_VERTEX_ATTRIBS);
+
+ const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex];
+
+ if (shaderAttr.type != GL_NONE)
+ {
+ GLenum transposedType = TransposeMatrixType(shaderAttr.type);
+
+ for (size_t rowIndex = 0; static_cast<int>(rowIndex) < VariableRowCount(transposedType); rowIndex++, layoutIndex++)
+ {
+ VertexFormat *defaultFormat = &inputLayout[layoutIndex];
+
+ defaultFormat->mType = VariableComponentType(transposedType);
+ defaultFormat->mNormalized = false;
+ defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool
+ defaultFormat->mComponents = VariableColumnCount(transposedType);
+ }
+ }
+ }
+}
+
+}
+
+VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
: name(name), element(element), index(index)
{
}
-unsigned int ProgramBinary::mCurrentSerial = 1;
+ProgramBinary::VertexExecutable::VertexExecutable(const VertexFormat inputLayout[],
+ const GLenum signature[],
+ rx::ShaderExecutable *shaderExecutable)
+ : mShaderExecutable(shaderExecutable)
+{
+ for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ mInputs[attributeIndex] = inputLayout[attributeIndex];
+ mSignature[attributeIndex] = signature[attributeIndex];
+ }
+}
-ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
+ProgramBinary::VertexExecutable::~VertexExecutable()
{
- mPixelExecutable = NULL;
- mVertexExecutable = NULL;
- mGeometryExecutable = NULL;
+ SafeDelete(mShaderExecutable);
+}
- mValidated = false;
+bool ProgramBinary::VertexExecutable::matchesSignature(const GLenum signature[]) const
+{
+ for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ if (mSignature[attributeIndex] != signature[attributeIndex])
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+ProgramBinary::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, rx::ShaderExecutable *shaderExecutable)
+ : mOutputSignature(outputSignature),
+ mShaderExecutable(shaderExecutable)
+{
+}
+
+ProgramBinary::PixelExecutable::~PixelExecutable()
+{
+ SafeDelete(mShaderExecutable);
+}
+LinkedVarying::LinkedVarying()
+{
+}
+
+LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
+ unsigned int semanticIndex, unsigned int semanticIndexCount)
+ : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
+{
+}
+
+unsigned int ProgramBinary::mCurrentSerial = 1;
+
+ProgramBinary::ProgramBinary(rx::Renderer *renderer)
+ : RefCountObject(0),
+ mRenderer(renderer),
+ mDynamicHLSL(NULL),
+ mVertexWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
+ mPixelWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
+ mGeometryExecutable(NULL),
+ mUsedVertexSamplerRange(0),
+ mUsedPixelSamplerRange(0),
+ mUsesPointSize(false),
+ mShaderVersion(100),
+ mDirtySamplerMapping(true),
+ mVertexUniformStorage(NULL),
+ mFragmentUniformStorage(NULL),
+ mValidated(false),
+ mSerial(issueSerial())
+{
for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
{
mSemanticIndex[index] = -1;
@@ -69,27 +201,13 @@ ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefC
mSamplersVS[index].active = false;
}
- mUsedVertexSamplerRange = 0;
- mUsedPixelSamplerRange = 0;
- mUsesPointSize = false;
+ mDynamicHLSL = new DynamicHLSL(renderer);
}
ProgramBinary::~ProgramBinary()
{
- delete mPixelExecutable;
- mPixelExecutable = NULL;
-
- delete mVertexExecutable;
- mVertexExecutable = NULL;
-
- delete mGeometryExecutable;
- mGeometryExecutable = NULL;
-
- while (!mUniforms.empty())
- {
- delete mUniforms.back();
- mUniforms.pop_back();
- }
+ reset();
+ SafeDelete(mDynamicHLSL);
}
unsigned int ProgramBinary::getSerial() const
@@ -97,22 +215,108 @@ unsigned int ProgramBinary::getSerial() const
return mSerial;
}
+int ProgramBinary::getShaderVersion() const
+{
+ return mShaderVersion;
+}
+
unsigned int ProgramBinary::issueSerial()
{
return mCurrentSerial++;
}
-rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
+rx::ShaderExecutable *ProgramBinary::getPixelExecutableForFramebuffer(const Framebuffer *fbo)
{
- return mPixelExecutable;
+ std::vector<GLenum> outputs(IMPLEMENTATION_MAX_DRAW_BUFFERS);
+ for (size_t outputIndex = 0; outputIndex < IMPLEMENTATION_MAX_DRAW_BUFFERS; outputIndex++)
+ {
+ if (fbo->getColorbuffer(outputIndex) != NULL)
+ {
+ // Always output floats for now
+ outputs[outputIndex] = GL_FLOAT;
+ }
+ else
+ {
+ outputs[outputIndex] = GL_NONE;
+ }
+ }
+
+ return getPixelExecutableForOutputLayout(outputs);
}
-rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
+rx::ShaderExecutable *ProgramBinary::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature)
{
- return mVertexExecutable;
+ for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++)
+ {
+ if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature))
+ {
+ return mPixelExecutables[executableIndex]->shaderExecutable();
+ }
+ }
+
+ std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth,
+ outputSignature);
+
+ // Generate new pixel executable
+ InfoLog tempInfoLog;
+ rx::ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL.c_str(), rx::SHADER_PIXEL,
+ mTransformFeedbackLinkedVaryings,
+ (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+ mPixelWorkarounds);
+
+ if (!pixelExecutable)
+ {
+ std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3);
+ tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
+ ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]);
+ }
+ else
+ {
+ mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable));
+ }
+
+ return pixelExecutable;
}
-rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
+rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
+{
+ GLenum signature[MAX_VERTEX_ATTRIBS];
+ mDynamicHLSL->getInputLayoutSignature(inputLayout, signature);
+
+ for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
+ {
+ if (mVertexExecutables[executableIndex]->matchesSignature(signature))
+ {
+ return mVertexExecutables[executableIndex]->shaderExecutable();
+ }
+ }
+
+ // Generate new dynamic layout with attribute conversions
+ std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes);
+
+ // Generate new vertex executable
+ InfoLog tempInfoLog;
+ rx::ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL.c_str(),
+ rx::SHADER_VERTEX,
+ mTransformFeedbackLinkedVaryings,
+ (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+ mVertexWorkarounds);
+
+ if (!vertexExecutable)
+ {
+ std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3);
+ tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
+ ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]);
+ }
+ else
+ {
+ mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable));
+ }
+
+ return vertexExecutable;
+}
+
+rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() const
{
return mGeometryExecutable;
}
@@ -136,7 +340,7 @@ GLuint ProgramBinary::getAttributeLocation(const char *name)
int ProgramBinary::getSemanticIndex(int attributeIndex)
{
ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
-
+
return mSemanticIndex[attributeIndex];
}
@@ -179,7 +383,7 @@ GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerInd
switch (type)
{
case SAMPLER_PIXEL:
- ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
+ ASSERT(samplerIndex < ArraySize(mSamplersPS));
if (mSamplersPS[samplerIndex].active)
{
@@ -187,7 +391,7 @@ GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerInd
}
break;
case SAMPLER_VERTEX:
- ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
+ ASSERT(samplerIndex < ArraySize(mSamplersVS));
if (mSamplersVS[samplerIndex].active)
{
@@ -212,11 +416,11 @@ TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int
switch (type)
{
case SAMPLER_PIXEL:
- ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
+ ASSERT(samplerIndex < ArraySize(mSamplersPS));
ASSERT(mSamplersPS[samplerIndex].active);
return mSamplersPS[samplerIndex].textureType;
case SAMPLER_VERTEX:
- ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
+ ASSERT(samplerIndex < ArraySize(mSamplersVS));
ASSERT(mSamplersVS[samplerIndex].active);
return mSamplersVS[samplerIndex].textureType;
default: UNREACHABLE();
@@ -227,402 +431,352 @@ TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int
GLint ProgramBinary::getUniformLocation(std::string name)
{
- unsigned int subscript = 0;
-
- // Strip any trailing array operator and retrieve the subscript
- size_t open = name.find_last_of('[');
- size_t close = name.find_last_of(']');
- if (open != std::string::npos && close == name.length() - 1)
- {
- subscript = atoi(name.substr(open + 1).c_str());
- name.erase(open);
- }
+ unsigned int subscript = ParseAndStripArrayIndex(&name);
unsigned int numUniforms = mUniformIndex.size();
for (unsigned int location = 0; location < numUniforms; location++)
{
- if (mUniformIndex[location].name == name &&
- mUniformIndex[location].element == subscript)
+ if (mUniformIndex[location].name == name)
{
- return location;
+ const int index = mUniformIndex[location].index;
+ const bool isArray = mUniforms[index]->isArray();
+
+ if ((isArray && mUniformIndex[location].element == subscript) ||
+ (subscript == GL_INVALID_INDEX))
+ {
+ return location;
+ }
}
}
return -1;
}
-bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+GLuint ProgramBinary::getUniformIndex(std::string name)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
-
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
-
- int elementCount = targetUniform->elementCount();
-
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ unsigned int subscript = ParseAndStripArrayIndex(&name);
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
-
- if (targetUniform->type == GL_FLOAT)
+ // The app is not allowed to specify array indices other than 0 for arrays of basic types
+ if (subscript != 0 && subscript != GL_INVALID_INDEX)
{
- GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (int i = 0; i < count; i++)
- {
- target[0] = v[0];
- target[1] = 0;
- target[2] = 0;
- target[3] = 0;
- target += 4;
- v += 1;
- }
+ return GL_INVALID_INDEX;
}
- else if (targetUniform->type == GL_BOOL)
- {
- GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
- for (int i = 0; i < count; i++)
+ unsigned int numUniforms = mUniforms.size();
+ for (unsigned int index = 0; index < numUniforms; index++)
+ {
+ if (mUniforms[index]->name == name)
{
- boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
- boolParams[1] = GL_FALSE;
- boolParams[2] = GL_FALSE;
- boolParams[3] = GL_FALSE;
- boolParams += 4;
- v += 1;
+ if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
+ {
+ return index;
+ }
}
}
- else
- {
- return false;
- }
- return true;
+ return GL_INVALID_INDEX;
}
-bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
+GLuint ProgramBinary::getUniformBlockIndex(std::string name)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
+ unsigned int subscript = ParseAndStripArrayIndex(&name);
+
+ unsigned int numUniformBlocks = mUniformBlocks.size();
+ for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
{
- return false;
+ const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
+ if (uniformBlock.name == name)
+ {
+ const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
+ if (subscript == uniformBlock.elementIndex || arrayElementZero)
+ {
+ return blockIndex;
+ }
+ }
}
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
-
- int elementCount = targetUniform->elementCount();
+ return GL_INVALID_INDEX;
+}
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
+{
+ ASSERT(blockIndex < mUniformBlocks.size());
+ return mUniformBlocks[blockIndex];
+}
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+GLint ProgramBinary::getFragDataLocation(const char *name) const
+{
+ std::string baseName(name);
+ unsigned int arrayIndex;
+ arrayIndex = ParseAndStripArrayIndex(&baseName);
- if (targetUniform->type == GL_FLOAT_VEC2)
+ for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
{
- GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+ const VariableLocation &outputVariable = locationIt->second;
- for (int i = 0; i < count; i++)
+ if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
{
- target[0] = v[0];
- target[1] = v[1];
- target[2] = 0;
- target[3] = 0;
- target += 4;
- v += 2;
+ return static_cast<GLint>(locationIt->first);
}
}
- else if (targetUniform->type == GL_BOOL_VEC2)
- {
- GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
- for (int i = 0; i < count; i++)
- {
- boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
- boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
- boolParams[2] = GL_FALSE;
- boolParams[3] = GL_FALSE;
- boolParams += 4;
- v += 2;
- }
- }
- else
- {
- return false;
- }
+ return -1;
+}
- return true;
+size_t ProgramBinary::getTransformFeedbackVaryingCount() const
+{
+ return mTransformFeedbackLinkedVaryings.size();
}
-bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
+const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
+ return mTransformFeedbackLinkedVaryings[idx];
+}
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
+GLenum ProgramBinary::getTransformFeedbackBufferMode() const
+{
+ return mTransformFeedbackBufferMode;
+}
- int elementCount = targetUniform->elementCount();
+template <typename T>
+static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag)
+{
+ ASSERT(dest != NULL);
+ ASSERT(dirtyFlag != NULL);
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0);
+ *dest = source;
+}
+
+template <typename T>
+void ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
+{
+ const int components = VariableComponentCount(targetUniformType);
+ const GLenum targetBoolType = VariableBoolVectorType(targetUniformType);
+
+ LinkedUniform *targetUniform = getUniformByLocation(location);
+
+ int elementCount = targetUniform->elementCount();
count = std::min(elementCount - (int)mUniformIndex[location].element, count);
- if (targetUniform->type == GL_FLOAT_VEC3)
+ if (targetUniform->type == targetUniformType)
{
- GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+ T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
for (int i = 0; i < count; i++)
{
- target[0] = v[0];
- target[1] = v[1];
- target[2] = v[2];
- target[3] = 0;
+ for (int c = 0; c < components; c++)
+ {
+ SetIfDirty(target + c, v[c], &targetUniform->dirty);
+ }
+ for (int c = components; c < 4; c++)
+ {
+ SetIfDirty(target + c, T(0), &targetUniform->dirty);
+ }
target += 4;
- v += 3;
+ v += components;
}
}
- else if (targetUniform->type == GL_BOOL_VEC3)
+ else if (targetUniform->type == targetBoolType)
{
GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
for (int i = 0; i < count; i++)
{
- boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
- boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
- boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
- boolParams[3] = GL_FALSE;
+ for (int c = 0; c < components; c++)
+ {
+ SetIfDirty(boolParams + c, (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty);
+ }
+ for (int c = components; c < 4; c++)
+ {
+ SetIfDirty(boolParams + c, GL_FALSE, &targetUniform->dirty);
+ }
boolParams += 4;
- v += 3;
+ v += components;
}
}
- else
- {
- return false;
- }
-
- return true;
+ else UNREACHABLE();
}
-bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
+ setUniform(location, count, v, GL_FLOAT);
+}
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
+void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ setUniform(location, count, v, GL_FLOAT_VEC2);
+}
- int elementCount = targetUniform->elementCount();
+void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ setUniform(location, count, v, GL_FLOAT_VEC3);
+}
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ setUniform(location, count, v, GL_FLOAT_VEC4);
+}
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+template<typename T>
+bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
+{
+ bool dirty = false;
+ int copyWidth = std::min(targetHeight, srcWidth);
+ int copyHeight = std::min(targetWidth, srcHeight);
- if (targetUniform->type == GL_FLOAT_VEC4)
+ for (int x = 0; x < copyWidth; x++)
{
- GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (int i = 0; i < count; i++)
+ for (int y = 0; y < copyHeight; y++)
{
- target[0] = v[0];
- target[1] = v[1];
- target[2] = v[2];
- target[3] = v[3];
- target += 4;
- v += 4;
+ SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]), &dirty);
}
}
- else if (targetUniform->type == GL_BOOL_VEC4)
+ // clear unfilled right side
+ for (int y = 0; y < copyWidth; y++)
{
- GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (int i = 0; i < count; i++)
+ for (int x = copyHeight; x < targetWidth; x++)
{
- boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
- boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
- boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
- boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE;
- boolParams += 4;
- v += 4;
+ SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
}
}
- else
+ // clear unfilled bottom.
+ for (int y = copyWidth; y < targetHeight; y++)
{
- return false;
+ for (int x = 0; x < targetWidth; x++)
+ {
+ SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
+ }
}
- return true;
+ return dirty;
}
-template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
-void transposeMatrix(T *target, const GLfloat *value)
+template<typename T>
+bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
{
+ bool dirty = false;
int copyWidth = std::min(targetWidth, srcWidth);
int copyHeight = std::min(targetHeight, srcHeight);
- for (int x = 0; x < copyWidth; x++)
+ for (int y = 0; y < copyHeight; y++)
{
- for (int y = 0; y < copyHeight; y++)
+ for (int x = 0; x < copyWidth; x++)
{
- target[x * targetWidth + y] = (T)value[y * srcWidth + x];
+ SetIfDirty(target + (y * targetWidth + x), static_cast<T>(value[y * srcWidth + x]), &dirty);
}
}
// clear unfilled right side
for (int y = 0; y < copyHeight; y++)
{
- for (int x = srcWidth; x < targetWidth; x++)
+ for (int x = copyWidth; x < targetWidth; x++)
{
- target[y * targetWidth + x] = (T)0;
+ SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
}
}
// clear unfilled bottom.
- for (int y = srcHeight; y < targetHeight; y++)
+ for (int y = copyHeight; y < targetHeight; y++)
{
for (int x = 0; x < targetWidth; x++)
{
- target[y * targetWidth + x] = (T)0;
+ SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
}
}
+
+ return dirty;
}
-bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
+template <int cols, int rows>
+void ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
-
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
-
- if (targetUniform->type != GL_FLOAT_MAT2)
- {
- return false;
- }
+ LinkedUniform *targetUniform = getUniformByLocation(location);
int elementCount = targetUniform->elementCount();
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
count = std::min(elementCount - (int)mUniformIndex[location].element, count);
- GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
+ const unsigned int targetMatrixStride = (4 * rows);
+ GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
for (int i = 0; i < count; i++)
{
- transposeMatrix<GLfloat,4,2,2,2>(target, value);
- target += 8;
- value += 4;
+ // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
+ if (transpose == GL_FALSE)
+ {
+ targetUniform->dirty = transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols) || targetUniform->dirty;
+ }
+ else
+ {
+ targetUniform->dirty = expandMatrix<GLfloat>(target, value, 4, rows, cols, rows) || targetUniform->dirty;
+ }
+ target += targetMatrixStride;
+ value += cols * rows;
}
-
- return true;
}
-bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
+void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
-
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
-
- if (targetUniform->type != GL_FLOAT_MAT3)
- {
- return false;
- }
-
- int elementCount = targetUniform->elementCount();
-
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
- GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
-
- for (int i = 0; i < count; i++)
- {
- transposeMatrix<GLfloat,4,3,3,3>(target, value);
- target += 12;
- value += 9;
- }
-
- return true;
+ setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
}
-
-bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
+void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
-
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
+ setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
+}
- if (targetUniform->type != GL_FLOAT_MAT4)
- {
- return false;
- }
+void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
+}
- int elementCount = targetUniform->elementCount();
+void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
+}
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
+}
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
- GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
+void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
+}
- for (int i = 0; i < count; i++)
- {
- transposeMatrix<GLfloat,4,4,4,4>(target, value);
- target += 16;
- value += 16;
- }
+void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
+}
- return true;
+void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
}
-bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
+void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
+ setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
+}
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
+void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
+{
+ LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
int elementCount = targetUniform->elementCount();
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
count = std::min(elementCount - (int)mUniformIndex[location].element, count);
- if (targetUniform->type == GL_INT ||
- targetUniform->type == GL_SAMPLER_2D ||
- targetUniform->type == GL_SAMPLER_CUBE)
+ if (targetUniform->type == GL_INT || IsSampler(targetUniform->type))
{
GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
for (int i = 0; i < count; i++)
{
- target[0] = v[0];
- target[1] = 0;
- target[2] = 0;
- target[3] = 0;
+ SetIfDirty(target + 0, v[0], &targetUniform->dirty);
+ SetIfDirty(target + 1, 0, &targetUniform->dirty);
+ SetIfDirty(target + 2, 0, &targetUniform->dirty);
+ SetIfDirty(target + 3, 0, &targetUniform->dirty);
target += 4;
v += 1;
}
@@ -633,317 +787,157 @@ bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
for (int i = 0; i < count; i++)
{
- boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
- boolParams[1] = GL_FALSE;
- boolParams[2] = GL_FALSE;
- boolParams[3] = GL_FALSE;
+ SetIfDirty(boolParams + 0, (v[0] == 0) ? GL_FALSE : GL_TRUE, &targetUniform->dirty);
+ SetIfDirty(boolParams + 1, GL_FALSE, &targetUniform->dirty);
+ SetIfDirty(boolParams + 2, GL_FALSE, &targetUniform->dirty);
+ SetIfDirty(boolParams + 3, GL_FALSE, &targetUniform->dirty);
boolParams += 4;
v += 1;
}
}
- else
+ else UNREACHABLE();
+
+ // Set a special flag if we change a sampler uniform
+ if (IsSampler(targetUniform->type) &&
+ (memcmp(targetUniform->data, v, sizeof(GLint)) != 0))
{
- return false;
+ mDirtySamplerMapping = true;
}
-
- return true;
}
-bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
+void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
-
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
-
- int elementCount = targetUniform->elementCount();
-
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
-
- if (targetUniform->type == GL_INT_VEC2)
- {
- GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (int i = 0; i < count; i++)
- {
- target[0] = v[0];
- target[1] = v[1];
- target[2] = 0;
- target[3] = 0;
- target += 4;
- v += 2;
- }
- }
- else if (targetUniform->type == GL_BOOL_VEC2)
- {
- GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (int i = 0; i < count; i++)
- {
- boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
- boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
- boolParams[2] = GL_FALSE;
- boolParams[3] = GL_FALSE;
- boolParams += 4;
- v += 2;
- }
- }
- else
- {
- return false;
- }
-
- return true;
+ setUniform(location, count, v, GL_INT_VEC2);
}
-bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
+void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
-
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
-
- int elementCount = targetUniform->elementCount();
-
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
-
- if (targetUniform->type == GL_INT_VEC3)
- {
- GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (int i = 0; i < count; i++)
- {
- target[0] = v[0];
- target[1] = v[1];
- target[2] = v[2];
- target[3] = 0;
- target += 4;
- v += 3;
- }
- }
- else if (targetUniform->type == GL_BOOL_VEC3)
- {
- GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (int i = 0; i < count; i++)
- {
- boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
- boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
- boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
- boolParams[3] = GL_FALSE;
- boolParams += 4;
- v += 3;
- }
- }
- else
- {
- return false;
- }
-
- return true;
+ setUniform(location, count, v, GL_INT_VEC3);
}
-bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
+void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
-
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
- targetUniform->dirty = true;
-
- int elementCount = targetUniform->elementCount();
-
- if (elementCount == 1 && count > 1)
- return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
-
- if (targetUniform->type == GL_INT_VEC4)
- {
- GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+ setUniform(location, count, v, GL_INT_VEC4);
+}
- for (int i = 0; i < count; i++)
- {
- target[0] = v[0];
- target[1] = v[1];
- target[2] = v[2];
- target[3] = v[3];
- target += 4;
- v += 4;
- }
- }
- else if (targetUniform->type == GL_BOOL_VEC4)
- {
- GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
+{
+ setUniform(location, count, v, GL_UNSIGNED_INT);
+}
- for (int i = 0; i < count; i++)
- {
- boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
- boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
- boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
- boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE;
- boolParams += 4;
- v += 4;
- }
- }
- else
- {
- return false;
- }
+void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
+{
+ setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
+}
- return true;
+void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
+{
+ setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
}
-bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
+void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
+ setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
+}
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+template <typename T>
+bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
+{
+ LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
// sized queries -- ensure the provided buffer is large enough
if (bufSize)
{
- int requiredBytes = UniformExternalSize(targetUniform->type);
+ int requiredBytes = VariableExternalSize(targetUniform->type);
if (*bufSize < requiredBytes)
{
return false;
}
}
- switch (targetUniform->type)
+ if (IsMatrixType(targetUniform->type))
{
- case GL_FLOAT_MAT2:
- transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
- break;
- case GL_FLOAT_MAT3:
- transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
- break;
- case GL_FLOAT_MAT4:
- transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
- break;
- default:
+ const int rows = VariableRowCount(targetUniform->type);
+ const int cols = VariableColumnCount(targetUniform->type);
+ transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows);
+ }
+ else if (uniformType == VariableComponentType(targetUniform->type))
+ {
+ unsigned int size = VariableComponentCount(targetUniform->type);
+ memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
+ size * sizeof(T));
+ }
+ else
+ {
+ unsigned int size = VariableComponentCount(targetUniform->type);
+ switch (VariableComponentType(targetUniform->type))
{
- unsigned int size = UniformComponentCount(targetUniform->type);
-
- switch (UniformComponentType(targetUniform->type))
+ case GL_BOOL:
{
- case GL_BOOL:
- {
- GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
- }
- }
- break;
- case GL_FLOAT:
- memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat),
- size * sizeof(GLfloat));
- break;
- case GL_INT:
+ for (unsigned int i = 0; i < size; i++)
{
- GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = (float)intParams[i];
- }
+ params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
}
- break;
- default: UNREACHABLE();
}
- }
- }
-
- return true;
-}
+ break;
-bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
-{
- if (location < 0 || location >= (int)mUniformIndex.size())
- {
- return false;
- }
+ case GL_FLOAT:
+ {
+ GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
- Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ for (unsigned int i = 0; i < size; i++)
+ {
+ params[i] = static_cast<T>(floatParams[i]);
+ }
+ }
+ break;
- // sized queries -- ensure the provided buffer is large enough
- if (bufSize)
- {
- int requiredBytes = UniformExternalSize(targetUniform->type);
- if (*bufSize < requiredBytes)
- {
- return false;
- }
- }
+ case GL_INT:
+ {
+ GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
- switch (targetUniform->type)
- {
- case GL_FLOAT_MAT2:
- transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
- break;
- case GL_FLOAT_MAT3:
- transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
- break;
- case GL_FLOAT_MAT4:
- transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
- break;
- default:
- {
- unsigned int size = VariableColumnCount(targetUniform->type);
+ for (unsigned int i = 0; i < size; i++)
+ {
+ params[i] = static_cast<T>(intParams[i]);
+ }
+ }
+ break;
- switch (UniformComponentType(targetUniform->type))
+ case GL_UNSIGNED_INT:
{
- case GL_BOOL:
- {
- GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+ GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = boolParams[i];
- }
- }
- break;
- case GL_FLOAT:
+ for (unsigned int i = 0; i < size; i++)
{
- GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = (GLint)floatParams[i];
- }
+ params[i] = static_cast<T>(uintParams[i]);
}
- break;
- case GL_INT:
- memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint),
- size * sizeof(GLint));
- break;
- default: UNREACHABLE();
}
+ break;
+
+ default: UNREACHABLE();
}
}
return true;
}
+bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
+{
+ return getUniformv(location, bufSize, params, GL_FLOAT);
+}
+
+bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
+{
+ return getUniformv(location, bufSize, params, GL_INT);
+}
+
+bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
+{
+ return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
+}
+
void ProgramBinary::dirtyAllUniforms()
{
unsigned int numUniforms = mUniforms.size();
@@ -953,23 +947,28 @@ void ProgramBinary::dirtyAllUniforms()
}
}
-// Applies all the uniforms set for this program object to the renderer
-void ProgramBinary::applyUniforms()
+void ProgramBinary::updateSamplerMapping()
{
+ if (!mDirtySamplerMapping)
+ {
+ return;
+ }
+
+ mDirtySamplerMapping = false;
+
// Retrieve sampler uniform values
- for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
+ for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
{
- Uniform *targetUniform = *ub;
+ LinkedUniform *targetUniform = mUniforms[uniformIndex];
if (targetUniform->dirty)
{
- if (targetUniform->type == GL_SAMPLER_2D ||
- targetUniform->type == GL_SAMPLER_CUBE)
+ if (IsSampler(targetUniform->type))
{
int count = targetUniform->elementCount();
- GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
+ GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data);
- if (targetUniform->psRegisterIndex >= 0)
+ if (targetUniform->isReferencedByFragmentShader())
{
unsigned int firstIndex = targetUniform->psRegisterIndex;
@@ -985,7 +984,7 @@ void ProgramBinary::applyUniforms()
}
}
- if (targetUniform->vsRegisterIndex >= 0)
+ if (targetUniform->isReferencedByVertexShader())
{
unsigned int firstIndex = targetUniform->vsRegisterIndex;
@@ -1003,215 +1002,87 @@ void ProgramBinary::applyUniforms()
}
}
}
-
- mRenderer->applyUniforms(this, &mUniforms);
}
-// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
-// Returns the number of used varying registers, or -1 if unsuccesful
-int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
+// Applies all the uniforms set for this program object to the renderer
+void ProgramBinary::applyUniforms()
{
- const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
+ updateSamplerMapping();
- fragmentShader->resetVaryingsRegisterAssignment();
+ mRenderer->applyUniforms(*this);
- for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
+ for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
{
- int n = VariableRowCount(varying->type) * varying->size;
- int m = VariableColumnCount(varying->type);
- bool success = false;
-
- if (m == 2 || m == 3 || m == 4)
- {
- for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
- {
- bool available = true;
-
- for (int y = 0; y < n && available; y++)
- {
- for (int x = 0; x < m && available; x++)
- {
- if (packing[r + y][x])
- {
- available = false;
- }
- }
- }
+ mUniforms[uniformIndex]->dirty = false;
+ }
+}
- if (available)
- {
- varying->reg = r;
- varying->col = 0;
+bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
+{
+ const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
+ const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
- for (int y = 0; y < n; y++)
- {
- for (int x = 0; x < m; x++)
- {
- packing[r + y][x] = &*varying;
- }
- }
+ const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
+ const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
- success = true;
- }
- }
+ ASSERT(boundBuffers.size() == mUniformBlocks.size());
- if (!success && m == 2)
- {
- for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
- {
- bool available = true;
-
- for (int y = 0; y < n && available; y++)
- {
- for (int x = 2; x < 4 && available; x++)
- {
- if (packing[r + y][x])
- {
- available = false;
- }
- }
- }
-
- if (available)
- {
- varying->reg = r;
- varying->col = 2;
+ for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
+ {
+ UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
+ gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
- for (int y = 0; y < n; y++)
- {
- for (int x = 2; x < 4; x++)
- {
- packing[r + y][x] = &*varying;
- }
- }
+ ASSERT(uniformBlock && uniformBuffer);
- success = true;
- }
- }
- }
- }
- else if (m == 1)
+ if (uniformBuffer->getSize() < uniformBlock->dataSize)
{
- int space[4] = {0};
-
- for (int y = 0; y < maxVaryingVectors; y++)
- {
- for (int x = 0; x < 4; x++)
- {
- space[x] += packing[y][x] ? 0 : 1;
- }
- }
-
- int column = 0;
-
- for (int x = 0; x < 4; x++)
- {
- if (space[x] >= n && space[x] < space[column])
- {
- column = x;
- }
- }
-
- if (space[column] >= n)
- {
- for (int r = 0; r < maxVaryingVectors; r++)
- {
- if (!packing[r][column])
- {
- varying->reg = r;
-
- for (int y = r; y < r + n; y++)
- {
- packing[y][column] = &*varying;
- }
-
- break;
- }
- }
-
- varying->col = column;
-
- success = true;
- }
+ // undefined behaviour
+ return false;
}
- else UNREACHABLE();
- if (!success)
- {
- infoLog.append("Could not pack varying %s", varying->name.c_str());
+ ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
- return -1;
+ if (uniformBlock->isReferencedByVertexShader())
+ {
+ unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
+ ASSERT(vertexUniformBuffers[registerIndex] == NULL);
+ ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
+ vertexUniformBuffers[registerIndex] = uniformBuffer;
}
- }
-
- // Return the number of used registers
- int registers = 0;
- for (int r = 0; r < maxVaryingVectors; r++)
- {
- if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
+ if (uniformBlock->isReferencedByFragmentShader())
{
- registers++;
+ unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
+ ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
+ ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
+ fragmentUniformBuffers[registerIndex] = uniformBuffer;
}
}
- return registers;
+ return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
}
-bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
- std::string& pixelHLSL, std::string& vertexHLSL,
- FragmentShader *fragmentShader, VertexShader *vertexShader)
+bool ProgramBinary::linkVaryings(InfoLog &infoLog, FragmentShader *fragmentShader, VertexShader *vertexShader)
{
- if (pixelHLSL.empty() || vertexHLSL.empty())
- {
- return false;
- }
+ std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
+ std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
- bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
- bool usesFragColor = fragmentShader->mUsesFragColor;
- bool usesFragData = fragmentShader->mUsesFragData;
- if (usesFragColor && usesFragData)
- {
- infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
- return false;
- }
-
- // Write the HLSL input/output declarations
- const int shaderModel = mRenderer->getMajorShaderModel();
- const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
-
- const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
-
- // The output color is broadcast to all enabled draw buffers when writing to gl_FragColor
- const bool broadcast = fragmentShader->mUsesFragColor;
- const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
-
- if (registersNeeded > maxVaryingVectors)
- {
- infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
-
- return false;
- }
-
- vertexShader->resetVaryingsRegisterAssignment();
-
- for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
+ for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
{
+ PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
bool matched = false;
- for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
+ for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
{
+ PackedVarying *output = &vertexVaryings[vertVaryingIndex];
if (output->name == input->name)
{
- if (output->type != input->type || output->size != input->size)
+ if (!linkValidateVariables(infoLog, output->name, *input, *output))
{
- infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
-
return false;
}
- output->reg = input->reg;
- output->col = input->col;
+ output->registerIndex = input->registerIndex;
matched = true;
break;
@@ -1221,664 +1092,463 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying
if (!matched)
{
infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
-
return false;
}
}
- mUsesPointSize = vertexShader->mUsesPointSize;
- std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
- std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
- std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
- std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
+ return true;
+}
- // special varyings that use reserved registers
- int reservedRegisterIndex = registers;
- std::string fragCoordSemantic;
- std::string pointCoordSemantic;
+bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
+{
+#ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
+ return false;
+#else
+ reset();
- if (fragmentShader->mUsesFragCoord)
+ BinaryInputStream stream(binary, length);
+
+ int format = stream.readInt<int>();
+ if (format != GL_PROGRAM_BINARY_ANGLE)
{
- fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
+ infoLog.append("Invalid program binary format.");
+ return false;
}
- if (fragmentShader->mUsesPointCoord)
+ int majorVersion = stream.readInt<int>();
+ int minorVersion = stream.readInt<int>();
+ if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
{
- // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
- // In DX11 we compute this in the GS.
- if (shaderModel == 3)
- {
- pointCoordSemantic = "TEXCOORD0";
- }
- else if (shaderModel >= 4)
- {
- pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
- }
+ infoLog.append("Invalid program binary version.");
+ return false;
}
- vertexHLSL += "struct VS_INPUT\n"
- "{\n";
-
- int semanticIndex = 0;
- for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
+ unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
+ stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
+ if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
{
- switch (attribute->type)
- {
- case GL_FLOAT: vertexHLSL += " float "; break;
- case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
- case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
- case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
- case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
- case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
- case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
- default: UNREACHABLE();
- }
-
- vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
-
- semanticIndex += VariableRowCount(attribute->type);
+ infoLog.append("Invalid program binary version.");
+ return false;
}
- vertexHLSL += "};\n"
- "\n"
- "struct VS_OUTPUT\n"
- "{\n";
-
- if (shaderModel < 4)
+ int compileFlags = stream.readInt<int>();
+ if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
{
- vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
+ infoLog.append("Mismatched compilation flags.");
+ return false;
}
- for (int r = 0; r < registers; r++)
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
{
- int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
-
- vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
+ stream.readInt(&mLinkedAttribute[i].type);
+ stream.readString(&mLinkedAttribute[i].name);
+ stream.readInt(&mShaderAttributes[i].type);
+ stream.readString(&mShaderAttributes[i].name);
+ stream.readInt(&mSemanticIndex[i]);
}
- if (fragmentShader->mUsesFragCoord)
+ initAttributesByLayout();
+
+ for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
{
- vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
+ stream.readBool(&mSamplersPS[i].active);
+ stream.readInt(&mSamplersPS[i].logicalTextureUnit);
+ stream.readInt(&mSamplersPS[i].textureType);
}
- if (vertexShader->mUsesPointSize && shaderModel >= 3)
+ for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
{
- vertexHLSL += " float gl_PointSize : PSIZE;\n";
+ stream.readBool(&mSamplersVS[i].active);
+ stream.readInt(&mSamplersVS[i].logicalTextureUnit);
+ stream.readInt(&mSamplersVS[i].textureType);
}
- if (shaderModel >= 4)
+ stream.readInt(&mUsedVertexSamplerRange);
+ stream.readInt(&mUsedPixelSamplerRange);
+ stream.readBool(&mUsesPointSize);
+ stream.readInt(&mShaderVersion);
+
+ const unsigned int uniformCount = stream.readInt<unsigned int>();
+ if (stream.error())
{
- vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
+ infoLog.append("Invalid program binary.");
+ return false;
}
- vertexHLSL += "};\n"
- "\n"
- "VS_OUTPUT main(VS_INPUT input)\n"
- "{\n";
-
- for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
+ mUniforms.resize(uniformCount);
+ for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++)
{
- vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
+ GLenum type = stream.readInt<GLenum>();
+ GLenum precision = stream.readInt<GLenum>();
+ std::string name = stream.readString();
+ unsigned int arraySize = stream.readInt<unsigned int>();
+ int blockIndex = stream.readInt<int>();
- if (VariableRowCount(attribute->type) > 1) // Matrix
- {
- vertexHLSL += "transpose";
- }
+ int offset = stream.readInt<int>();
+ int arrayStride = stream.readInt<int>();
+ int matrixStride = stream.readInt<int>();
+ bool isRowMajorMatrix = stream.readBool();
- vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
- }
+ const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
- if (shaderModel >= 4)
- {
- vertexHLSL += "\n"
- " gl_main();\n"
- "\n"
- " VS_OUTPUT output;\n"
- " output.gl_Position.x = gl_Position.x;\n"
- " output.gl_Position.y = -gl_Position.y;\n"
- " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
- " output.gl_Position.w = gl_Position.w;\n";
- }
- else
- {
- vertexHLSL += "\n"
- " gl_main();\n"
- "\n"
- " VS_OUTPUT output;\n"
- " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
- " output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"
- " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
- " output.gl_Position.w = gl_Position.w;\n";
- }
+ LinkedUniform *uniform = new LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo);
- if (vertexShader->mUsesPointSize && shaderModel >= 3)
- {
- vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
+ stream.readInt(&uniform->psRegisterIndex);
+ stream.readInt(&uniform->vsRegisterIndex);
+ stream.readInt(&uniform->registerCount);
+ stream.readInt(&uniform->registerElement);
+
+ mUniforms[uniformIndex] = uniform;
}
- if (fragmentShader->mUsesFragCoord)
+ unsigned int uniformBlockCount = stream.readInt<unsigned int>();
+ if (stream.error())
{
- vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
+ infoLog.append("Invalid program binary.");
+ return false;
}
- for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
+ mUniformBlocks.resize(uniformBlockCount);
+ for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
{
- if (varying->reg >= 0)
- {
- for (int i = 0; i < varying->size; i++)
- {
- int rows = VariableRowCount(varying->type);
-
- for (int j = 0; j < rows; j++)
- {
- int r = varying->reg + i * rows + j;
- vertexHLSL += " output.v" + str(r);
-
- bool sharedRegister = false; // Register used by multiple varyings
-
- for (int x = 0; x < 4; x++)
- {
- if (packing[r][x] && packing[r][x] != packing[r][0])
- {
- sharedRegister = true;
- break;
- }
- }
+ std::string name = stream.readString();
+ unsigned int elementIndex = stream.readInt<unsigned int>();
+ unsigned int dataSize = stream.readInt<unsigned int>();
- if(sharedRegister)
- {
- vertexHLSL += ".";
-
- for (int x = 0; x < 4; x++)
- {
- if (packing[r][x] == &*varying)
- {
- switch(x)
- {
- case 0: vertexHLSL += "x"; break;
- case 1: vertexHLSL += "y"; break;
- case 2: vertexHLSL += "z"; break;
- case 3: vertexHLSL += "w"; break;
- }
- }
- }
- }
-
- vertexHLSL += " = " + varying->name;
-
- if (varying->array)
- {
- vertexHLSL += "[" + str(i) + "]";
- }
-
- if (rows > 1)
- {
- vertexHLSL += "[" + str(j) + "]";
- }
-
- vertexHLSL += ";\n";
- }
- }
- }
- }
+ UniformBlock *uniformBlock = new UniformBlock(name, elementIndex, dataSize);
- vertexHLSL += "\n"
- " return output;\n"
- "}\n";
+ stream.readInt(&uniformBlock->psRegisterIndex);
+ stream.readInt(&uniformBlock->vsRegisterIndex);
- pixelHLSL += "struct PS_INPUT\n"
- "{\n";
-
- for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
- {
- if (varying->reg >= 0)
+ unsigned int numMembers = stream.readInt<unsigned int>();
+ uniformBlock->memberUniformIndexes.resize(numMembers);
+ for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
{
- for (int i = 0; i < varying->size; i++)
- {
- int rows = VariableRowCount(varying->type);
- for (int j = 0; j < rows; j++)
- {
- std::string n = str(varying->reg + i * rows + j);
- pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
- }
- }
+ stream.readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]);
}
- else UNREACHABLE();
+
+ mUniformBlocks[uniformBlockIndex] = uniformBlock;
}
- if (fragmentShader->mUsesFragCoord)
+ const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
+ if (stream.error())
{
- pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
+ infoLog.append("Invalid program binary.");
+ return false;
}
-
- if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
+
+ mUniformIndex.resize(uniformIndexCount);
+ for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++)
{
- pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
+ stream.readString(&mUniformIndex[uniformIndexIndex].name);
+ stream.readInt(&mUniformIndex[uniformIndexIndex].element);
+ stream.readInt(&mUniformIndex[uniformIndexIndex].index);
}
- // Must consume the PSIZE element if the geometry shader is not active
- // We won't know if we use a GS until we draw
- if (vertexShader->mUsesPointSize && shaderModel >= 4)
+ stream.readInt(&mTransformFeedbackBufferMode);
+ const unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
+ mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount);
+ for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++)
{
- pixelHLSL += " float gl_PointSize : PSIZE;\n";
+ LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex];
+
+ stream.readString(&varying.name);
+ stream.readInt(&varying.type);
+ stream.readInt(&varying.size);
+ stream.readString(&varying.semanticName);
+ stream.readInt(&varying.semanticIndex);
+ stream.readInt(&varying.semanticIndexCount);
}
- if (fragmentShader->mUsesFragCoord)
+ stream.readString(&mVertexHLSL);
+
+ stream.readInt(&mVertexWorkarounds);
+
+ const unsigned int vertexShaderCount = stream.readInt<unsigned int>();
+ for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++)
{
- if (shaderModel >= 4)
+ VertexFormat inputLayout[MAX_VERTEX_ATTRIBS];
+
+ for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++)
{
- pixelHLSL += " float4 dx_VPos : SV_Position;\n";
+ VertexFormat *vertexInput = &inputLayout[inputIndex];
+ stream.readInt(&vertexInput->mType);
+ stream.readInt(&vertexInput->mNormalized);
+ stream.readInt(&vertexInput->mComponents);
+ stream.readBool(&vertexInput->mPureInteger);
}
- else if (shaderModel >= 3)
+
+ unsigned int vertexShaderSize = stream.readInt<unsigned int>();
+ const unsigned char *vertexShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset();
+ rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
+ vertexShaderSize, rx::SHADER_VERTEX,
+ mTransformFeedbackLinkedVaryings,
+ (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
+ if (!shaderExecutable)
{
- pixelHLSL += " float2 dx_VPos : VPOS;\n";
+ infoLog.append("Could not create vertex shader.");
+ return false;
}
- }
- pixelHLSL += "};\n"
- "\n"
- "struct PS_OUTPUT\n"
- "{\n";
+ // generated converted input layout
+ GLenum signature[MAX_VERTEX_ATTRIBS];
+ mDynamicHLSL->getInputLayoutSignature(inputLayout, signature);
- for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
- {
- pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
- }
+ // add new binary
+ mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable));
- if (fragmentShader->mUsesFragDepth)
- {
- pixelHLSL += " float gl_Depth : " + depthSemantic + ";\n";
+ stream.skip(vertexShaderSize);
}
- pixelHLSL += "};\n"
- "\n";
+ stream.readString(&mPixelHLSL);
+ stream.readInt(&mPixelWorkarounds);
+ stream.readBool(&mUsesFragDepth);
- if (fragmentShader->mUsesFrontFacing)
+ const size_t pixelShaderKeySize = stream.readInt<unsigned int>();
+ mPixelShaderKey.resize(pixelShaderKeySize);
+ for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; pixelShaderKeyIndex++)
{
- if (shaderModel >= 4)
- {
- pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
- "{\n";
- }
- else
- {
- pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
- "{\n";
- }
- }
- else
- {
- pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
- "{\n";
+ stream.readInt(&mPixelShaderKey[pixelShaderKeyIndex].type);
+ stream.readString(&mPixelShaderKey[pixelShaderKeyIndex].name);
+ stream.readString(&mPixelShaderKey[pixelShaderKeyIndex].source);
+ stream.readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex);
}
- if (fragmentShader->mUsesFragCoord)
+ const size_t pixelShaderCount = stream.readInt<unsigned int>();
+ for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++)
{
- pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
-
- if (shaderModel >= 4)
+ const size_t outputCount = stream.readInt<unsigned int>();
+ std::vector<GLenum> outputs(outputCount);
+ for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++)
{
- pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
- " gl_FragCoord.y = input.dx_VPos.y;\n";
+ stream.readInt(&outputs[outputIndex]);
}
- else if (shaderModel >= 3)
- {
- pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
- " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
- }
- else
+
+ const size_t pixelShaderSize = stream.readInt<unsigned int>();
+ const unsigned char *pixelShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset();
+ rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize,
+ rx::SHADER_PIXEL,
+ mTransformFeedbackLinkedVaryings,
+ (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
+ if (!shaderExecutable)
{
- // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
- pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
- " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
+ infoLog.append("Could not create pixel shader.");
+ return false;
}
-
- pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
- " gl_FragCoord.w = rhw;\n";
- }
- if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
- {
- pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
- pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
- }
+ // add new binary
+ mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable));
- if (fragmentShader->mUsesFrontFacing)
- {
- if (shaderModel <= 3)
- {
- pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
- }
- else
- {
- pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
- }
+ stream.skip(pixelShaderSize);
}
- for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
+ unsigned int geometryShaderSize = stream.readInt<unsigned int>();
+
+ if (geometryShaderSize > 0)
{
- if (varying->reg >= 0)
+ const char *geometryShaderFunction = (const char*) binary + stream.offset();
+ mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
+ geometryShaderSize, rx::SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings,
+ (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
+ if (!mGeometryExecutable)
{
- for (int i = 0; i < varying->size; i++)
- {
- int rows = VariableRowCount(varying->type);
- for (int j = 0; j < rows; j++)
- {
- std::string n = str(varying->reg + i * rows + j);
- pixelHLSL += " " + varying->name;
-
- if (varying->array)
- {
- pixelHLSL += "[" + str(i) + "]";
- }
-
- if (rows > 1)
- {
- pixelHLSL += "[" + str(j) + "]";
- }
-
- switch (VariableColumnCount(varying->type))
- {
- case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
- case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
- case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
- case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
- default: UNREACHABLE();
- }
- }
- }
+ infoLog.append("Could not create geometry shader.");
+ return false;
}
- else UNREACHABLE();
+ stream.skip(geometryShaderSize);
}
- pixelHLSL += "\n"
- " gl_main();\n"
- "\n"
- " PS_OUTPUT output;\n";
-
- for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
- {
- unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
+ const char *ptr = (const char*) binary + stream.offset();
- pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
- }
+ const GUID *binaryIdentifier = (const GUID *) ptr;
+ ptr += sizeof(GUID);
- if (fragmentShader->mUsesFragDepth)
+ GUID identifier = mRenderer->getAdapterIdentifier();
+ if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
{
- pixelHLSL += " output.gl_Depth = gl_Depth;\n";
+ infoLog.append("Invalid program binary.");
+ return false;
}
- pixelHLSL += "\n"
- " return output;\n"
- "}\n";
+ initializeUniformStorage();
return true;
+#endif // #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
}
-bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
+bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
{
- BinaryInputStream stream(binary, length);
-
- int format = 0;
- stream.read(&format);
- if (format != GL_PROGRAM_BINARY_ANGLE)
- {
- infoLog.append("Invalid program binary format.");
- return false;
- }
-
- int majorVersion = 0;
- int minorVersion = 0;
- stream.read(&majorVersion);
- stream.read(&minorVersion);
- if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
- {
- infoLog.append("Invalid program binary version.");
- return false;
- }
-
-#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY)
- unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
- stream.read(commitString, ANGLE_COMMIT_HASH_SIZE);
- if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
- {
- infoLog.append("Invalid program binary version.");
- return false;
- }
+ BinaryOutputStream stream;
- int compileFlags = 0;
- stream.read(&compileFlags);
- if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
- {
- infoLog.append("Mismatched compilation flags.");
- return false;
- }
-#endif
+ stream.writeInt(GL_PROGRAM_BINARY_ANGLE);
+ stream.writeInt(ANGLE_MAJOR_VERSION);
+ stream.writeInt(ANGLE_MINOR_VERSION);
+ stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
+ stream.writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
- for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
+ for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
{
- stream.read(&mLinkedAttribute[i].type);
- std::string name;
- stream.read(&name);
- mLinkedAttribute[i].name = name;
- stream.read(&mSemanticIndex[i]);
+ stream.writeInt(mLinkedAttribute[i].type);
+ stream.writeString(mLinkedAttribute[i].name);
+ stream.writeInt(mShaderAttributes[i].type);
+ stream.writeString(mShaderAttributes[i].name);
+ stream.writeInt(mSemanticIndex[i]);
}
- initAttributesByLayout();
-
for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
{
- stream.read(&mSamplersPS[i].active);
- stream.read(&mSamplersPS[i].logicalTextureUnit);
-
- int textureType;
- stream.read(&textureType);
- mSamplersPS[i].textureType = (TextureType) textureType;
+ stream.writeInt(mSamplersPS[i].active);
+ stream.writeInt(mSamplersPS[i].logicalTextureUnit);
+ stream.writeInt(mSamplersPS[i].textureType);
}
for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
{
- stream.read(&mSamplersVS[i].active);
- stream.read(&mSamplersVS[i].logicalTextureUnit);
-
- int textureType;
- stream.read(&textureType);
- mSamplersVS[i].textureType = (TextureType) textureType;
+ stream.writeInt(mSamplersVS[i].active);
+ stream.writeInt(mSamplersVS[i].logicalTextureUnit);
+ stream.writeInt(mSamplersVS[i].textureType);
}
- stream.read(&mUsedVertexSamplerRange);
- stream.read(&mUsedPixelSamplerRange);
- stream.read(&mUsesPointSize);
+ stream.writeInt(mUsedVertexSamplerRange);
+ stream.writeInt(mUsedPixelSamplerRange);
+ stream.writeInt(mUsesPointSize);
+ stream.writeInt(mShaderVersion);
- size_t size;
- stream.read(&size);
- if (stream.error())
+ stream.writeInt(mUniforms.size());
+ for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
{
- infoLog.append("Invalid program binary.");
- return false;
- }
-
- mUniforms.resize(size);
- for (unsigned int i = 0; i < size; ++i)
- {
- GLenum type;
- GLenum precision;
- std::string name;
- unsigned int arraySize;
+ const LinkedUniform &uniform = *mUniforms[uniformIndex];
- stream.read(&type);
- stream.read(&precision);
- stream.read(&name);
- stream.read(&arraySize);
+ stream.writeInt(uniform.type);
+ stream.writeInt(uniform.precision);
+ stream.writeString(uniform.name);
+ stream.writeInt(uniform.arraySize);
+ stream.writeInt(uniform.blockIndex);
- mUniforms[i] = new Uniform(type, precision, name, arraySize);
-
- stream.read(&mUniforms[i]->psRegisterIndex);
- stream.read(&mUniforms[i]->vsRegisterIndex);
- stream.read(&mUniforms[i]->registerCount);
- }
+ stream.writeInt(uniform.blockInfo.offset);
+ stream.writeInt(uniform.blockInfo.arrayStride);
+ stream.writeInt(uniform.blockInfo.matrixStride);
+ stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
- stream.read(&size);
- if (stream.error())
- {
- infoLog.append("Invalid program binary.");
- return false;
+ stream.writeInt(uniform.psRegisterIndex);
+ stream.writeInt(uniform.vsRegisterIndex);
+ stream.writeInt(uniform.registerCount);
+ stream.writeInt(uniform.registerElement);
}
- mUniformIndex.resize(size);
- for (unsigned int i = 0; i < size; ++i)
+ stream.writeInt(mUniformBlocks.size());
+ for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
{
- stream.read(&mUniformIndex[i].name);
- stream.read(&mUniformIndex[i].element);
- stream.read(&mUniformIndex[i].index);
- }
+ const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
- unsigned int pixelShaderSize;
- stream.read(&pixelShaderSize);
+ stream.writeString(uniformBlock.name);
+ stream.writeInt(uniformBlock.elementIndex);
+ stream.writeInt(uniformBlock.dataSize);
- unsigned int vertexShaderSize;
- stream.read(&vertexShaderSize);
-
- unsigned int geometryShaderSize;
- stream.read(&geometryShaderSize);
-
- const char *ptr = (const char*) binary + stream.offset();
-
-#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY)
- const GUID *binaryIdentifier = (const GUID *) ptr;
- ptr += sizeof(GUID);
+ stream.writeInt(uniformBlock.memberUniformIndexes.size());
+ for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
+ {
+ stream.writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]);
+ }
- GUID identifier = mRenderer->getAdapterIdentifier();
- if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
- {
- infoLog.append("Invalid program binary.");
- return false;
+ stream.writeInt(uniformBlock.psRegisterIndex);
+ stream.writeInt(uniformBlock.vsRegisterIndex);
}
-#endif
-
- const char *pixelShaderFunction = ptr;
- ptr += pixelShaderSize;
-
- const char *vertexShaderFunction = ptr;
- ptr += vertexShaderSize;
- const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
- ptr += geometryShaderSize;
-
- mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
- pixelShaderSize, rx::SHADER_PIXEL);
- if (!mPixelExecutable)
+ stream.writeInt(mUniformIndex.size());
+ for (size_t i = 0; i < mUniformIndex.size(); ++i)
{
- infoLog.append("Could not create pixel shader.");
- return false;
+ stream.writeString(mUniformIndex[i].name);
+ stream.writeInt(mUniformIndex[i].element);
+ stream.writeInt(mUniformIndex[i].index);
}
- mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
- vertexShaderSize, rx::SHADER_VERTEX);
- if (!mVertexExecutable)
+ stream.writeInt(mTransformFeedbackBufferMode);
+ stream.writeInt(mTransformFeedbackLinkedVaryings.size());
+ for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
{
- infoLog.append("Could not create vertex shader.");
- delete mPixelExecutable;
- mPixelExecutable = NULL;
- return false;
+ const LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
+
+ stream.writeString(varying.name);
+ stream.writeInt(varying.type);
+ stream.writeInt(varying.size);
+ stream.writeString(varying.semanticName);
+ stream.writeInt(varying.semanticIndex);
+ stream.writeInt(varying.semanticIndexCount);
}
- if (geometryShaderFunction != NULL && geometryShaderSize > 0)
+ stream.writeString(mVertexHLSL);
+ stream.writeInt(mVertexWorkarounds);
+
+ stream.writeInt(mVertexExecutables.size());
+ for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++)
{
- mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
- geometryShaderSize, rx::SHADER_GEOMETRY);
- if (!mGeometryExecutable)
+ VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex];
+
+ for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
{
- infoLog.append("Could not create geometry shader.");
- delete mPixelExecutable;
- mPixelExecutable = NULL;
- delete mVertexExecutable;
- mVertexExecutable = NULL;
- return false;
+ const VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex];
+ stream.writeInt(vertexInput.mType);
+ stream.writeInt(vertexInput.mNormalized);
+ stream.writeInt(vertexInput.mComponents);
+ stream.writeInt(vertexInput.mPureInteger);
}
- }
- else
- {
- mGeometryExecutable = NULL;
- }
- return true;
-}
-
-bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
-{
- BinaryOutputStream stream;
+ size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength();
+ stream.writeInt(vertexShaderSize);
- stream.write(GL_PROGRAM_BINARY_ANGLE);
- stream.write(ANGLE_MAJOR_VERSION);
- stream.write(ANGLE_MINOR_VERSION);
-#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY)
- stream.write(ANGLE_COMMIT_HASH, ANGLE_COMMIT_HASH_SIZE);
- stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
-#endif
- for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
- {
- stream.write(mLinkedAttribute[i].type);
- stream.write(mLinkedAttribute[i].name);
- stream.write(mSemanticIndex[i]);
+ const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction();
+ stream.writeBytes(vertexBlob, vertexShaderSize);
}
- for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
+ stream.writeString(mPixelHLSL);
+ stream.writeInt(mPixelWorkarounds);
+ stream.writeInt(mUsesFragDepth);
+
+ stream.writeInt(mPixelShaderKey.size());
+ for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < mPixelShaderKey.size(); pixelShaderKeyIndex++)
{
- stream.write(mSamplersPS[i].active);
- stream.write(mSamplersPS[i].logicalTextureUnit);
- stream.write((int) mSamplersPS[i].textureType);
+ const PixelShaderOuputVariable &variable = mPixelShaderKey[pixelShaderKeyIndex];
+ stream.writeInt(variable.type);
+ stream.writeString(variable.name);
+ stream.writeString(variable.source);
+ stream.writeInt(variable.outputIndex);
}
- for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
+ stream.writeInt(mPixelExecutables.size());
+ for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++)
{
- stream.write(mSamplersVS[i].active);
- stream.write(mSamplersVS[i].logicalTextureUnit);
- stream.write((int) mSamplersVS[i].textureType);
- }
+ PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex];
- stream.write(mUsedVertexSamplerRange);
- stream.write(mUsedPixelSamplerRange);
- stream.write(mUsesPointSize);
+ const std::vector<GLenum> outputs = pixelExecutable->outputSignature();
+ stream.writeInt(outputs.size());
+ for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++)
+ {
+ stream.writeInt(outputs[outputIndex]);
+ }
- stream.write(mUniforms.size());
- for (unsigned int i = 0; i < mUniforms.size(); ++i)
- {
- stream.write(mUniforms[i]->type);
- stream.write(mUniforms[i]->precision);
- stream.write(mUniforms[i]->name);
- stream.write(mUniforms[i]->arraySize);
+ size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength();
+ stream.writeInt(pixelShaderSize);
- stream.write(mUniforms[i]->psRegisterIndex);
- stream.write(mUniforms[i]->vsRegisterIndex);
- stream.write(mUniforms[i]->registerCount);
+ const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction();
+ stream.writeBytes(pixelBlob, pixelShaderSize);
}
- stream.write(mUniformIndex.size());
- for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
+ size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
+ stream.writeInt(geometryShaderSize);
+
+ if (mGeometryExecutable != NULL && geometryShaderSize > 0)
{
- stream.write(mUniformIndex[i].name);
- stream.write(mUniformIndex[i].element);
- stream.write(mUniformIndex[i].index);
+ const uint8_t *geometryBlob = mGeometryExecutable->getFunction();
+ stream.writeBytes(geometryBlob, geometryShaderSize);
}
- UINT pixelShaderSize = mPixelExecutable->getLength();
- stream.write(pixelShaderSize);
-
- UINT vertexShaderSize = mVertexExecutable->getLength();
- stream.write(vertexShaderSize);
-
- UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
- stream.write(geometryShaderSize);
-
-#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY)
GUID identifier = mRenderer->getAdapterIdentifier();
-#endif
GLsizei streamLength = stream.length();
const void *streamData = stream.data();
- GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
+ GLsizei totalLength = streamLength + sizeof(GUID);
if (totalLength > bufSize)
{
if (length)
@@ -1896,22 +1566,8 @@ bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
memcpy(ptr, streamData, streamLength);
ptr += streamLength;
-#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY)
memcpy(ptr, &identifier, sizeof(GUID));
ptr += sizeof(GUID);
-#endif
-
- memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
- ptr += pixelShaderSize;
-
- memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
- ptr += vertexShaderSize;
-
- if (mGeometryExecutable != NULL && geometryShaderSize > 0)
- {
- memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
- ptr += geometryShaderSize;
- }
ASSERT(ptr - totalLength == binary);
}
@@ -1937,7 +1593,8 @@ GLint ProgramBinary::getLength()
}
}
-bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
+bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader,
+ const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode)
{
if (!fragmentShader || !fragmentShader->isCompiled())
{
@@ -1949,19 +1606,37 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin
return false;
}
- std::string pixelHLSL = fragmentShader->getHLSL();
- std::string vertexHLSL = vertexShader->getHLSL();
+ reset();
+
+ mTransformFeedbackBufferMode = transformFeedbackBufferMode;
+
+ mShaderVersion = vertexShader->getShaderVersion();
+
+ mPixelHLSL = fragmentShader->getHLSL();
+ mPixelWorkarounds = fragmentShader->getD3DWorkarounds();
+
+ mVertexHLSL = vertexShader->getHLSL();
+ mVertexWorkarounds = vertexShader->getD3DWorkarounds();
// Map the varyings to the register file
- const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
- int registers = packVaryings(infoLog, packing, fragmentShader);
+ VaryingPacking packing = { NULL };
+ int registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShader, vertexShader, transformFeedbackVaryings);
if (registers < 0)
{
return false;
}
- if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
+ if (!linkVaryings(infoLog, fragmentShader, vertexShader))
+ {
+ return false;
+ }
+
+ mUsesPointSize = vertexShader->usesPointSize();
+ std::vector<LinkedVarying> linkedVaryings;
+ if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, registers, packing, mPixelHLSL, mVertexHLSL,
+ fragmentShader, vertexShader, transformFeedbackVaryings,
+ &linkedVaryings, &mOutputVariables, &mPixelShaderKey, &mUsesFragDepth))
{
return false;
}
@@ -1973,41 +1648,59 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin
success = false;
}
- if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
+ if (!linkUniforms(infoLog, *vertexShader, *fragmentShader))
{
success = false;
}
// special case for gl_DepthRange, the only built-in uniform (also a struct)
- if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
+ if (vertexShader->usesDepthRange() || fragmentShader->usesDepthRange())
{
- mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0));
- mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0));
- mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0));
+ const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo();
+
+ mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo));
+ mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo));
+ mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo));
+ }
+
+ if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader))
+ {
+ success = false;
+ }
+
+ if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings,
+ transformFeedbackBufferMode, &mTransformFeedbackLinkedVaryings))
+ {
+ success = false;
}
if (success)
{
- mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX, DiscardWorkaround(vertexShader->mUsesDiscardRewriting));
- mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL, DiscardWorkaround(fragmentShader->mUsesDiscardRewriting));
+ VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS];
+ GetInputLayoutFromShader(vertexShader->activeAttributes(), defaultInputLayout);
+ rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout);
+
+ std::vector<GLenum> defaultPixelOutput(IMPLEMENTATION_MAX_DRAW_BUFFERS);
+ for (size_t i = 0; i < defaultPixelOutput.size(); i++)
+ {
+ defaultPixelOutput[i] = (i == 0) ? GL_FLOAT : GL_NONE;
+ }
+ rx::ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput);
if (usesGeometryShader())
{
- std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
- mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY, rx::ANGLE_D3D_WORKAROUND_NONE);
+ std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShader, vertexShader);
+ mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY,
+ mTransformFeedbackLinkedVaryings,
+ (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+ rx::ANGLE_D3D_WORKAROUND_NONE);
}
- if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
+ if (!defaultVertexExecutable || !defaultPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
{
infoLog.append("Failed to create D3D shaders.");
success = false;
-
- delete mVertexExecutable;
- mVertexExecutable = NULL;
- delete mPixelExecutable;
- mPixelExecutable = NULL;
- delete mGeometryExecutable;
- mGeometryExecutable = NULL;
+ reset();
}
}
@@ -2018,62 +1711,75 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin
bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
{
unsigned int usedLocations = 0;
+ const std::vector<sh::Attribute> &activeAttributes = vertexShader->activeAttributes();
// Link attributes that have a binding location
- for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
+ for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
{
- int location = attributeBindings.getAttributeBinding(attribute->name);
-
- if (location != -1) // Set by glBindAttribLocation
- {
- if (!mLinkedAttribute[location].name.empty())
- {
- // Multiple active attributes bound to the same location; not an error
- }
+ const sh::Attribute &attribute = activeAttributes[attributeIndex];
+ const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
- mLinkedAttribute[location] = *attribute;
+ mShaderAttributes[attributeIndex] = attribute;
- int rows = VariableRowCount(attribute->type);
+ if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
+ {
+ const int rows = VariableRegisterCount(attribute.type);
if (rows + location > MAX_VERTEX_ATTRIBS)
{
- infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);
+ infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
return false;
}
- for (int i = 0; i < rows; i++)
+ for (int row = 0; row < rows; row++)
{
- usedLocations |= 1 << (location + i);
+ const int rowLocation = location + row;
+ sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
+
+ // In GLSL 3.00, attribute aliasing produces a link error
+ // In GLSL 1.00, attribute aliasing is allowed
+ if (mShaderVersion >= 300)
+ {
+ if (!linkedAttribute.name.empty())
+ {
+ infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
+ return false;
+ }
+ }
+
+ linkedAttribute = attribute;
+ usedLocations |= 1 << rowLocation;
}
}
}
// Link attributes that don't have a binding location
- for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
+ for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
{
- int location = attributeBindings.getAttributeBinding(attribute->name);
+ const sh::Attribute &attribute = activeAttributes[attributeIndex];
+ const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
- if (location == -1) // Not set by glBindAttribLocation
+ if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
{
- int rows = VariableRowCount(attribute->type);
+ int rows = VariableRegisterCount(attribute.type);
int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
{
- infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
+ infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
return false; // Fail to link
}
- mLinkedAttribute[availableIndex] = *attribute;
+ mLinkedAttribute[availableIndex] = attribute;
}
}
for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
{
int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
- int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
+ int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
for (int r = 0; r < rows; r++)
{
@@ -2086,19 +1792,51 @@ bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &at
return true;
}
-bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
+bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
+ const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
{
- for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
+ if (vertexVariable.type != fragmentVariable.type)
+ {
+ infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
+ return false;
+ }
+ if (vertexVariable.arraySize != fragmentVariable.arraySize)
{
- if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
+ infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
+ return false;
+ }
+ if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
+ {
+ infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+template <class ShaderVarType>
+bool ProgramBinary::linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar)
+{
+ if (vertexVar.fields.size() != fragmentVar.fields.size())
+ {
+ infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", varName.c_str());
+ return false;
+ }
+ const unsigned int numMembers = vertexVar.fields.size();
+ for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
+ {
+ const ShaderVarType &vertexMember = vertexVar.fields[memberIndex];
+ const ShaderVarType &fragmentMember = fragmentVar.fields[memberIndex];
+
+ if (vertexMember.name != fragmentMember.name)
{
+ infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
+ memberIndex, varName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
return false;
}
- }
- for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
- {
- if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
+ const std::string memberName = varName.substr(0, varName.length()-1) + "." + vertexVar.name + "'";
+ if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember))
{
return false;
}
@@ -2107,274 +1845,571 @@ bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &ver
return true;
}
-bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
+bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
{
- if (constant.type == GL_SAMPLER_2D ||
- constant.type == GL_SAMPLER_CUBE)
+ if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
{
- unsigned int samplerIndex = constant.registerIndex;
-
- do
- {
- if (shader == GL_VERTEX_SHADER)
- {
- if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
- {
- mSamplersVS[samplerIndex].active = true;
- mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
- mSamplersVS[samplerIndex].logicalTextureUnit = 0;
- mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
- }
- else
- {
- infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
- return false;
- }
- }
- else if (shader == GL_FRAGMENT_SHADER)
- {
- if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
- {
- mSamplersPS[samplerIndex].active = true;
- mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
- mSamplersPS[samplerIndex].logicalTextureUnit = 0;
- mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
- }
- else
- {
- infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
- return false;
- }
- }
- else UNREACHABLE();
+ return false;
+ }
- samplerIndex++;
- }
- while (samplerIndex < constant.registerIndex + constant.arraySize);
+ if (!linkValidateFields<sh::Uniform>(infoLog, uniformName, vertexUniform, fragmentUniform))
+ {
+ return false;
}
- Uniform *uniform = NULL;
- GLint location = getUniformLocation(constant.name);
+ return true;
+}
- if (location >= 0) // Previously defined, type and precision must match
+bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
+{
+ if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
{
- uniform = mUniforms[mUniformIndex[location].index];
+ return false;
+ }
- if (uniform->type != constant.type)
- {
- infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
- return false;
- }
+ if (vertexVarying.interpolation != fragmentVarying.interpolation)
+ {
+ infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
+ return false;
+ }
- if (uniform->precision != constant.precision)
- {
- infoLog.append("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
- return false;
- }
+ if (!linkValidateFields<sh::Varying>(infoLog, varyingName, vertexVarying, fragmentVarying))
+ {
+ return false;
}
- else
+
+ return true;
+}
+
+bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
+{
+ if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
{
- uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize);
+ return false;
}
- if (!uniform)
+ if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
{
+ infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
return false;
}
- if (shader == GL_FRAGMENT_SHADER)
+ if (!linkValidateFields<sh::InterfaceBlockField>(infoLog, uniformName, vertexUniform, fragmentUniform))
{
- uniform->psRegisterIndex = constant.registerIndex;
+ return false;
}
- else if (shader == GL_VERTEX_SHADER)
+
+ return true;
+}
+
+bool ProgramBinary::linkUniforms(InfoLog &infoLog, const VertexShader &vertexShader, const FragmentShader &fragmentShader)
+{
+ const std::vector<sh::Uniform> &vertexUniforms = vertexShader.getUniforms();
+ const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader.getUniforms();
+
+ // Check that uniforms defined in the vertex and fragment shaders are identical
+ typedef std::map<std::string, const sh::Uniform*> UniformMap;
+ UniformMap linkedUniforms;
+
+ for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
{
- uniform->vsRegisterIndex = constant.registerIndex;
+ const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
+ linkedUniforms[vertexUniform.name] = &vertexUniform;
+ }
+
+ for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
+ {
+ const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
+ UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
+ if (entry != linkedUniforms.end())
+ {
+ const sh::Uniform &vertexUniform = *entry->second;
+ const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
+ if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform))
+ {
+ return false;
+ }
+ }
}
- else UNREACHABLE();
- if (location >= 0)
+ for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
{
- return uniform->type == constant.type;
+ const sh::Uniform &uniform = vertexUniforms[uniformIndex];
+ defineUniformBase(GL_VERTEX_SHADER, uniform, vertexShader.getUniformRegister(uniform.name));
}
- mUniforms.push_back(uniform);
- unsigned int uniformIndex = mUniforms.size() - 1;
+ for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
+ {
+ const sh::Uniform &uniform = fragmentUniforms[uniformIndex];
+ defineUniformBase(GL_FRAGMENT_SHADER, uniform, fragmentShader.getUniformRegister(uniform.name));
+ }
- for (unsigned int i = 0; i < uniform->elementCount(); i++)
+ if (!indexUniforms(infoLog))
{
- mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
+ return false;
}
- if (shader == GL_VERTEX_SHADER)
+ initializeUniformStorage();
+
+ return true;
+}
+
+void ProgramBinary::defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister)
+{
+ ShShaderOutput outputType = Shader::getCompilerOutputType(shader);
+ sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType));
+ encoder.skipRegisters(uniformRegister);
+
+ defineUniform(shader, uniform, uniform.name, &encoder);
+}
+
+void ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &uniform,
+ const std::string &fullName, sh::HLSLBlockEncoder *encoder)
+{
+ if (uniform.isStruct())
+ {
+ for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
+ {
+ const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
+
+ encoder->enterAggregateType();
+
+ for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
+ {
+ const sh::Uniform &field = uniform.fields[fieldIndex];
+ const std::string &fieldFullName = (fullName + elementString + "." + field.name);
+
+ defineUniform(shader, field, fieldFullName, encoder);
+ }
+
+ encoder->exitAggregateType();
+ }
+ }
+ else // Not a struct
+ {
+ // Arrays are treated as aggregate types
+ if (uniform.isArray())
+ {
+ encoder->enterAggregateType();
+ }
+
+ LinkedUniform *linkedUniform = getUniformByName(fullName);
+
+ if (!linkedUniform)
+ {
+ linkedUniform = new LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
+ -1, sh::BlockMemberInfo::getDefaultBlockInfo());
+ ASSERT(linkedUniform);
+ linkedUniform->registerElement = encoder->getCurrentElement();
+ mUniforms.push_back(linkedUniform);
+ }
+
+ ASSERT(linkedUniform->registerElement == encoder->getCurrentElement());
+
+ if (shader == GL_FRAGMENT_SHADER)
+ {
+ linkedUniform->psRegisterIndex = encoder->getCurrentRegister();
+ }
+ else if (shader == GL_VERTEX_SHADER)
+ {
+ linkedUniform->vsRegisterIndex = encoder->getCurrentRegister();
+ }
+ else UNREACHABLE();
+
+ // Advance the uniform offset, to track registers allocation for structs
+ encoder->encodeType(uniform.type, uniform.arraySize, false);
+
+ // Arrays are treated as aggregate types
+ if (uniform.isArray())
+ {
+ encoder->exitAggregateType();
+ }
+ }
+}
+
+bool ProgramBinary::indexSamplerUniform(const LinkedUniform &uniform, InfoLog &infoLog)
+{
+ ASSERT(IsSampler(uniform.type));
+ ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX);
+
+ if (uniform.vsRegisterIndex != GL_INVALID_INDEX)
{
- if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
+ if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS,
+ &mUsedVertexSamplerRange, mRenderer->getMaxVertexTextureImageUnits()))
+ {
+ infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).",
+ mRenderer->getMaxVertexTextureImageUnits());
+ return false;
+ }
+
+ unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() +
+ mRenderer->getMaxVertexUniformVectors();
+ if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors)
{
- infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
+ infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)",
+ mRenderer->getMaxVertexUniformVectors());
return false;
}
}
- else if (shader == GL_FRAGMENT_SHADER)
+
+ if (uniform.psRegisterIndex != GL_INVALID_INDEX)
{
- if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
+ if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS,
+ &mUsedPixelSamplerRange, MAX_TEXTURE_IMAGE_UNITS))
{
- infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
+ infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).",
+ MAX_TEXTURE_IMAGE_UNITS);
+ return false;
+ }
+
+ unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() +
+ mRenderer->getMaxFragmentUniformVectors();
+ if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors)
+ {
+ infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)",
+ mRenderer->getMaxFragmentUniformVectors());
return false;
}
}
- else UNREACHABLE();
return true;
}
-std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
+bool ProgramBinary::indexUniforms(InfoLog &infoLog)
{
- // for now we only handle point sprite emulation
- ASSERT(usesPointSpriteEmulation());
- return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
+ for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+ {
+ const LinkedUniform &uniform = *mUniforms[uniformIndex];
+
+ if (IsSampler(uniform.type))
+ {
+ if (!indexSamplerUniform(uniform, infoLog))
+ {
+ return false;
+ }
+ }
+
+ for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++)
+ {
+ mUniformIndex.push_back(VariableLocation(uniform.name, arrayElementIndex, uniformIndex));
+ }
+ }
+
+ return true;
}
-std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
+bool ProgramBinary::assignSamplers(unsigned int startSamplerIndex,
+ GLenum samplerType,
+ unsigned int samplerCount,
+ Sampler *outArray,
+ GLuint *usedRange,
+ unsigned int limit)
{
- ASSERT(registers >= 0);
- ASSERT(vertexShader->mUsesPointSize);
- ASSERT(mRenderer->getMajorShaderModel() >= 4);
+ unsigned int samplerIndex = startSamplerIndex;
- std::string geomHLSL;
+ do
+ {
+ if (samplerIndex < limit)
+ {
+ outArray[samplerIndex].active = true;
+ outArray[samplerIndex].textureType = GetTextureType(samplerType);
+ outArray[samplerIndex].logicalTextureUnit = 0;
+ *usedRange = std::max(samplerIndex + 1, *usedRange);
+ }
+ else
+ {
+ return false;
+ }
- std::string varyingSemantic = "TEXCOORD";
+ samplerIndex++;
+ } while (samplerIndex < startSamplerIndex + samplerCount);
- std::string fragCoordSemantic;
- std::string pointCoordSemantic;
+ return true;
+}
- int reservedRegisterIndex = registers;
+bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
+{
+ const char* blockName = vertexInterfaceBlock.name.c_str();
- if (fragmentShader->mUsesFragCoord)
+ // validate blocks for the same member types
+ if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
{
- fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
+ infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
+ return false;
}
- if (fragmentShader->mUsesPointCoord)
+ if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
{
- pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
+ infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
+ return false;
}
- geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
- "\n"
- "struct GS_INPUT\n"
- "{\n";
-
- for (int r = 0; r < registers; r++)
+ if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
{
- int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
-
- geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
+ infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
+ return false;
}
- if (fragmentShader->mUsesFragCoord)
+ const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
+ for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
{
- geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
+ const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
+ const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
+
+ if (vertexMember.name != fragmentMember.name)
+ {
+ infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
+ blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
+ return false;
+ }
+
+ std::string uniformName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
+ if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember))
+ {
+ return false;
+ }
}
- geomHLSL += " float gl_PointSize : PSIZE;\n"
- " float4 gl_Position : SV_Position;\n"
- "};\n"
- "\n"
- "struct GS_OUTPUT\n"
- "{\n";
+ return true;
+}
+
+bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const VertexShader &vertexShader,
+ const FragmentShader &fragmentShader)
+{
+ const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
+ const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
+
+ // Check that interface blocks defined in the vertex and fragment shaders are identical
+ typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
+ UniformBlockMap linkedUniformBlocks;
- for (int r = 0; r < registers; r++)
+ for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
{
- int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
+ const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
+ linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
+ }
- geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
+ for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
+ {
+ const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
+ UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
+ if (entry != linkedUniformBlocks.end())
+ {
+ const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
+ if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
+ {
+ return false;
+ }
+ }
}
- if (fragmentShader->mUsesFragCoord)
+ for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
{
- geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
+ if (!defineUniformBlock(infoLog, vertexShader, vertexInterfaceBlocks[blockIndex]))
+ {
+ return false;
+ }
}
- if (fragmentShader->mUsesPointCoord)
+ for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
{
- geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
+ if (!defineUniformBlock(infoLog, fragmentShader, fragmentInterfaceBlocks[blockIndex]))
+ {
+ return false;
+ }
}
- geomHLSL += " float gl_PointSize : PSIZE;\n"
- " float4 gl_Position : SV_Position;\n"
- "};\n"
- "\n"
- "static float2 pointSpriteCorners[] = \n"
- "{\n"
- " float2( 0.5f, -0.5f),\n"
- " float2( 0.5f, 0.5f),\n"
- " float2(-0.5f, -0.5f),\n"
- " float2(-0.5f, 0.5f)\n"
- "};\n"
- "\n"
- "static float2 pointSpriteTexcoords[] = \n"
- "{\n"
- " float2(1.0f, 1.0f),\n"
- " float2(1.0f, 0.0f),\n"
- " float2(0.0f, 1.0f),\n"
- " float2(0.0f, 0.0f)\n"
- "};\n"
- "\n"
- "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
- "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
- "\n"
- "[maxvertexcount(4)]\n"
- "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
- "{\n"
- " GS_OUTPUT output = (GS_OUTPUT)0;\n"
- " output.gl_PointSize = input[0].gl_PointSize;\n";
+ return true;
+}
+
+bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
+ const std::vector<std::string> &transformFeedbackVaryingNames,
+ GLenum transformFeedbackBufferMode,
+ std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings) const
+{
+ size_t totalComponents = 0;
+ const size_t maxSeparateComponents = mRenderer->getMaxTransformFeedbackSeparateComponents();
+ const size_t maxInterleavedComponents = mRenderer->getMaxTransformFeedbackInterleavedComponents();
- for (int r = 0; r < registers; r++)
+ // Gather the linked varyings that are used for transform feedback, they should all exist.
+ outTransformFeedbackLinkedVaryings->clear();
+ for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
{
- geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
+ bool found = false;
+ for (size_t j = 0; j < linkedVaryings.size(); j++)
+ {
+ if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
+ {
+ for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
+ {
+ if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
+ {
+ infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str());
+ return false;
+ }
+ }
+
+ size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
+ if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
+ componentCount > maxSeparateComponents)
+ {
+ infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).",
+ linkedVaryings[j].name.c_str(), componentCount, maxSeparateComponents);
+ return false;
+ }
+
+ totalComponents += componentCount;
+
+ outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
+ found = true;
+ break;
+ }
+ }
+
+ // All transform feedback varyings are expected to exist since packVaryings checks for them.
+ ASSERT(found);
}
- if (fragmentShader->mUsesFragCoord)
+ if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > maxInterleavedComponents)
{
- geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
+ infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
+ totalComponents, maxInterleavedComponents);
+ return false;
}
- geomHLSL += " \n"
- " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
- " float4 gl_Position = input[0].gl_Position;\n"
- " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * gl_Position.w;\n";
+ return true;
+}
- for (int corner = 0; corner < 4; corner++)
+void ProgramBinary::defineUniformBlockMembers(const std::vector<sh::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex,
+ sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes)
+{
+ for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
{
- geomHLSL += " \n"
- " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
+ const sh::InterfaceBlockField &field = fields[uniformIndex];
+ const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
- if (fragmentShader->mUsesPointCoord)
+ if (field.isStruct())
{
- geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
+ for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
+ {
+ encoder->enterAggregateType();
+
+ const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
+ defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes);
+
+ encoder->exitAggregateType();
+ }
}
+ else
+ {
+ sh::BlockMemberInfo memberInfo = encoder->encodeInterfaceBlockField(field);
+
+ LinkedUniform *newUniform = new LinkedUniform(field.type, field.precision, fieldName, field.arraySize,
+ blockIndex, memberInfo);
- geomHLSL += " outStream.Append(output);\n";
+ // add to uniform list, but not index, since uniform block uniforms have no location
+ blockUniformIndexes->push_back(mUniforms.size());
+ mUniforms.push_back(newUniform);
+ }
}
+}
+
+bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock)
+{
+ // create uniform block entries if they do not exist
+ if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
+ {
+ std::vector<unsigned int> blockUniformIndexes;
+ const unsigned int blockIndex = mUniformBlocks.size();
+
+ // define member uniforms
+ sh::BlockLayoutEncoder *encoder = NULL;
+
+ if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD)
+ {
+ encoder = new sh::Std140BlockEncoder;
+ }
+ else
+ {
+ encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED);
+ }
+ ASSERT(encoder);
+
+ defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes);
- geomHLSL += " \n"
- " outStream.RestartStrip();\n"
- "}\n";
+ size_t dataSize = encoder->getBlockSize();
- return geomHLSL;
+ // create all the uniform blocks
+ if (interfaceBlock.arraySize > 0)
+ {
+ for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
+ {
+ UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize);
+ newUniformBlock->memberUniformIndexes = blockUniformIndexes;
+ mUniformBlocks.push_back(newUniformBlock);
+ }
+ }
+ else
+ {
+ UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize);
+ newUniformBlock->memberUniformIndexes = blockUniformIndexes;
+ mUniformBlocks.push_back(newUniformBlock);
+ }
+ }
+
+ // Assign registers to the uniform blocks
+ const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
+ const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
+ ASSERT(blockIndex != GL_INVALID_INDEX);
+ ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
+
+ unsigned int interfaceBlockRegister = shader.getInterfaceBlockRegister(interfaceBlock.name);
+
+ for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
+ {
+ UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
+ ASSERT(uniformBlock->name == interfaceBlock.name);
+
+ if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(),
+ interfaceBlockRegister + uniformBlockElement))
+ {
+ return false;
+ }
+ }
+
+ return true;
}
-// This method needs to match OutputHLSL::decorate
-std::string ProgramBinary::decorateAttribute(const std::string &name)
+bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
{
- if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
+ if (shader == GL_VERTEX_SHADER)
{
- return "_" + name;
+ uniformBlock->vsRegisterIndex = registerIndex;
+ unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
+
+ if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
+ {
+ infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
+ return false;
+ }
}
-
- return name;
+ else if (shader == GL_FRAGMENT_SHADER)
+ {
+ uniformBlock->psRegisterIndex = registerIndex;
+ unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
+
+ if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
+ {
+ infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks);
+ return false;
+ }
+ }
+ else UNREACHABLE();
+
+ return true;
}
-bool ProgramBinary::isValidated() const
+bool ProgramBinary::isValidated() const
{
return mValidated;
}
@@ -2500,6 +2535,141 @@ GLint ProgramBinary::getActiveUniformMaxLength() const
return maxLength;
}
+GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
+{
+ const gl::LinkedUniform& uniform = *mUniforms[index];
+
+ switch (pname)
+ {
+ case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
+ case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
+ case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
+ case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
+
+ case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
+ case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
+ case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
+ case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return 0;
+}
+
+bool ProgramBinary::isValidUniformLocation(GLint location) const
+{
+ ASSERT(rx::IsIntegerCastSafe<GLint>(mUniformIndex.size()));
+ return (location >= 0 && location < static_cast<GLint>(mUniformIndex.size()));
+}
+
+LinkedUniform *ProgramBinary::getUniformByLocation(GLint location) const
+{
+ ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformIndex.size());
+ return mUniforms[mUniformIndex[location].index];
+}
+
+LinkedUniform *ProgramBinary::getUniformByName(const std::string &name) const
+{
+ for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+ {
+ if (mUniforms[uniformIndex]->name == name)
+ {
+ return mUniforms[uniformIndex];
+ }
+ }
+
+ return NULL;
+}
+
+void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
+{
+ ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
+
+ const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
+
+ if (bufSize > 0)
+ {
+ std::string string = uniformBlock.name;
+
+ if (uniformBlock.isArrayElement())
+ {
+ string += ArrayString(uniformBlock.elementIndex);
+ }
+
+ strncpy(uniformBlockName, string.c_str(), bufSize);
+ uniformBlockName[bufSize - 1] = '\0';
+
+ if (length)
+ {
+ *length = strlen(uniformBlockName);
+ }
+ }
+}
+
+void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
+{
+ ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
+
+ const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
+
+ switch (pname)
+ {
+ case GL_UNIFORM_BLOCK_DATA_SIZE:
+ *params = static_cast<GLint>(uniformBlock.dataSize);
+ break;
+ case GL_UNIFORM_BLOCK_NAME_LENGTH:
+ *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
+ break;
+ case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
+ *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
+ break;
+ case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
+ {
+ for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
+ {
+ params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
+ }
+ }
+ break;
+ case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
+ *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
+ break;
+ case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
+ *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+GLuint ProgramBinary::getActiveUniformBlockCount() const
+{
+ return mUniformBlocks.size();
+}
+
+GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
+{
+ unsigned int maxLength = 0;
+
+ unsigned int numUniformBlocks = mUniformBlocks.size();
+ for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
+ {
+ const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
+ if (!uniformBlock.name.empty())
+ {
+ const unsigned int length = uniformBlock.name.length() + 1;
+
+ // Counting in "[0]".
+ const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
+
+ maxLength = std::max(length + arrayLength, maxLength);
+ }
+ }
+
+ return maxLength;
+}
+
void ProgramBinary::validate(InfoLog &infoLog)
{
applyUniforms();
@@ -2518,6 +2688,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog)
// if any two active samplers in a program are of different types, but refer to the same
// texture image unit, and this is the current program, then ValidateProgram will fail, and
// DrawArrays and DrawElements will issue the INVALID_OPERATION error.
+ updateSamplerMapping();
const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
@@ -2532,7 +2703,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog)
if (mSamplersPS[i].active)
{
unsigned int unit = mSamplersPS[i].logicalTextureUnit;
-
+
if (unit >= maxCombinedTextureImageUnits)
{
if (infoLog)
@@ -2567,7 +2738,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog)
if (mSamplersVS[i].active)
{
unsigned int unit = mSamplersVS[i].logicalTextureUnit;
-
+
if (unit >= maxCombinedTextureImageUnits)
{
if (infoLog)
@@ -2648,4 +2819,71 @@ void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MA
}
}
+void ProgramBinary::initializeUniformStorage()
+{
+ // Compute total default block size
+ unsigned int vertexRegisters = 0;
+ unsigned int fragmentRegisters = 0;
+ for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+ {
+ const LinkedUniform &uniform = *mUniforms[uniformIndex];
+
+ if (!IsSampler(uniform.type))
+ {
+ if (uniform.isReferencedByVertexShader())
+ {
+ vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount);
+ }
+ if (uniform.isReferencedByFragmentShader())
+ {
+ fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount);
+ }
+ }
+ }
+
+ mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u);
+ mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u);
+}
+
+void ProgramBinary::reset()
+{
+ mVertexHLSL.clear();
+ mVertexWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE;
+ SafeDeleteContainer(mVertexExecutables);
+
+ mPixelHLSL.clear();
+ mPixelWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE;
+ mUsesFragDepth = false;
+ mPixelShaderKey.clear();
+ SafeDeleteContainer(mPixelExecutables);
+
+ SafeDelete(mGeometryExecutable);
+
+ mTransformFeedbackBufferMode = GL_NONE;
+ mTransformFeedbackLinkedVaryings.clear();
+
+ for (size_t i = 0; i < ArraySize(mSamplersPS); i++)
+ {
+ mSamplersPS[i] = Sampler();
+ }
+ for (size_t i = 0; i < ArraySize(mSamplersVS); i++)
+ {
+ mSamplersVS[i] = Sampler();
+ }
+ mUsedVertexSamplerRange = 0;
+ mUsedPixelSamplerRange = 0;
+ mUsesPointSize = false;
+ mShaderVersion = 0;
+ mDirtySamplerMapping = true;
+
+ SafeDeleteContainer(mUniforms);
+ SafeDeleteContainer(mUniformBlocks);
+ mUniformIndex.clear();
+ mOutputVariables.clear();
+ SafeDelete(mVertexUniformStorage);
+ SafeDelete(mFragmentUniformStorage);
+
+ mValidated = false;
+}
+
}