Re^4-land "Move Uniform and UBO info to the gl::Program layer."
This data was previously stored entirely in the Impl level. Move
as much as possible to the GL level, using a read-only view in the
Impl level. Some information in D3D-specific, and should be stored
separately in the Impl.
This patch has a lot of refactoring that splits the D3D and GL info,
and moves as much validation as possible to the GL layer, where it
is shared between the back-ends.
Re-land with fix for dEQP unused uniforms. The fix involves storing
a local copy of all uniform data in the GL layer. This will also
let us validate sampler indexes during draw calls at the GL layer.
Re-re-land with a fix for multiply defined symbols on Clang.
Re-re-re-land with a fix for boolean uniforms and Uniform{1234}f.
Re^4-land with a fix for boolean uniform arrays and UBO uniforms.
BUG=angleproject:1123
TEST=end2end_tests, bots, dEQP GLES3.ubo and GLES2.uniform_api
Change-Id: I4c9f5ed31b81380507bef7981f97086d642801ae
Reviewed-on: https://chromium-review.googlesource.com/298451
Tryjob-Request: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/common/mathutil.h b/src/common/mathutil.h
index 332ba3d..fb16a1c 100644
--- a/src/common/mathutil.h
+++ b/src/common/mathutil.h
@@ -69,13 +69,13 @@
template <typename DestT, typename SrcT>
inline DestT clampCast(SrcT value)
{
- // This assumes SrcT can properly represent DestT::min/max
- // Unfortunately we can't use META_ASSERT without C++11 constexpr support
- ASSERT(static_cast<DestT>(static_cast<SrcT>(std::numeric_limits<DestT>::min())) == std::numeric_limits<DestT>::min());
- ASSERT(static_cast<DestT>(static_cast<SrcT>(std::numeric_limits<DestT>::max())) == std::numeric_limits<DestT>::max());
-
SrcT lo = static_cast<SrcT>(std::numeric_limits<DestT>::min());
SrcT hi = static_cast<SrcT>(std::numeric_limits<DestT>::max());
+
+ // This assumes SrcT can properly represent DestT::min/max. Checking this is a bit tricky,
+ // especially given floating point representations.
+ ASSERT(lo < hi);
+
return static_cast<DestT>(value > lo ? (value > hi ? hi : value) : lo);
}
diff --git a/src/compiler/translator/blocklayout.h b/src/compiler/translator/blocklayout.h
index 96d3740..0d0a2ed 100644
--- a/src/compiler/translator/blocklayout.h
+++ b/src/compiler/translator/blocklayout.h
@@ -26,6 +26,8 @@
struct COMPILER_EXPORT BlockMemberInfo
{
+ BlockMemberInfo() : offset(-1), arrayStride(-1), matrixStride(-1), isRowMajorMatrix(false) {}
+
BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix)
: offset(offset),
arrayStride(arrayStride),
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 30386f7..1efa216 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -22,6 +22,7 @@
#include "libANGLE/features.h"
#include "libANGLE/renderer/Renderer.h"
#include "libANGLE/renderer/ProgramImpl.h"
+#include "libANGLE/queryconversions.h"
namespace gl
{
@@ -46,8 +47,135 @@
return subscript;
}
+void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
+{
+ stream->writeInt(var.type);
+ stream->writeInt(var.precision);
+ stream->writeString(var.name);
+ stream->writeString(var.mappedName);
+ stream->writeInt(var.arraySize);
+ stream->writeInt(var.staticUse);
+ stream->writeString(var.structName);
+ ASSERT(var.fields.empty());
}
+void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
+{
+ var->type = stream->readInt<GLenum>();
+ var->precision = stream->readInt<GLenum>();
+ var->name = stream->readString();
+ var->mappedName = stream->readString();
+ var->arraySize = stream->readInt<unsigned int>();
+ var->staticUse = stream->readBool();
+ var->structName = stream->readString();
+}
+
+template <typename VarT>
+void DefineUniformBlockMembers(const std::vector<VarT> &fields,
+ const std::string &prefix,
+ int blockIndex,
+ std::vector<LinkedUniform> *uniformsOut)
+{
+ for (const VarT &field : fields)
+ {
+ const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
+
+ if (field.isStruct())
+ {
+ for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
+ {
+ const std::string uniformElementName =
+ fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
+ DefineUniformBlockMembers(field.fields, uniformElementName, blockIndex,
+ uniformsOut);
+ }
+ }
+ else
+ {
+ // TODO(jmadill): record row-majorness?
+ // Block layout is recorded in the Impl.
+ LinkedUniform newUniform(field.type, field.precision, fieldName, field.arraySize,
+ blockIndex, sh::BlockMemberInfo::getDefaultBlockInfo());
+
+ // Since block uniforms have no location, we don't need to store them in the uniform
+ // locations list.
+ uniformsOut->push_back(newUniform);
+ }
+ }
+}
+
+// This simplified cast function doesn't need to worry about advanced concepts like
+// depth range values, or casting to bool.
+template <typename DestT, typename SrcT>
+DestT UniformStateQueryCast(SrcT value);
+
+// From-Float-To-Integer Casts
+template <>
+GLint UniformStateQueryCast(GLfloat value)
+{
+ return clampCast<GLint>(roundf(value));
+}
+
+template <>
+GLuint UniformStateQueryCast(GLfloat value)
+{
+ return clampCast<GLuint>(roundf(value));
+}
+
+// From-Integer-to-Integer Casts
+template <>
+GLint UniformStateQueryCast(GLuint value)
+{
+ return clampCast<GLint>(value);
+}
+
+template <>
+GLuint UniformStateQueryCast(GLint value)
+{
+ return clampCast<GLuint>(value);
+}
+
+// From-Boolean-to-Anything Casts
+template <>
+GLfloat UniformStateQueryCast(GLboolean value)
+{
+ return (value == GL_TRUE ? 1.0f : 0.0f);
+}
+
+template <>
+GLint UniformStateQueryCast(GLboolean value)
+{
+ return (value == GL_TRUE ? 1 : 0);
+}
+
+template <>
+GLuint UniformStateQueryCast(GLboolean value)
+{
+ return (value == GL_TRUE ? 1u : 0u);
+}
+
+// Default to static_cast
+template <typename DestT, typename SrcT>
+DestT UniformStateQueryCast(SrcT value)
+{
+ return static_cast<DestT>(value);
+}
+
+template <typename SrcT, typename DestT>
+void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
+{
+ for (int comp = 0; comp < components; ++comp)
+ {
+ // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
+ // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
+ size_t offset = comp * 4;
+ const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
+ dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
+ }
+}
+
+} // anonymous namespace
+
AttributeBindings::AttributeBindings()
{
}
@@ -162,6 +290,68 @@
}
}
+const LinkedUniform *Program::Data::getUniformByName(const std::string &name) const
+{
+ for (const LinkedUniform &linkedUniform : mUniforms)
+ {
+ if (linkedUniform.name == name)
+ {
+ return &linkedUniform;
+ }
+ }
+
+ return nullptr;
+}
+
+GLint Program::Data::getUniformLocation(const std::string &name) const
+{
+ size_t subscript = GL_INVALID_INDEX;
+ std::string baseName = gl::ParseUniformName(name, &subscript);
+
+ for (size_t location = 0; location < mUniformLocations.size(); ++location)
+ {
+ const VariableLocation &uniformLocation = mUniformLocations[location];
+ const LinkedUniform &uniform = mUniforms[uniformLocation.index];
+
+ if (uniform.name == baseName)
+ {
+ if ((uniform.isArray() && uniformLocation.element == subscript) ||
+ (subscript == GL_INVALID_INDEX))
+ {
+ return static_cast<GLint>(location);
+ }
+ }
+ }
+
+ return -1;
+}
+
+GLuint Program::Data::getUniformIndex(const std::string &name) const
+{
+ size_t subscript = GL_INVALID_INDEX;
+ std::string baseName = gl::ParseUniformName(name, &subscript);
+
+ // The app is not allowed to specify array indices other than 0 for arrays of basic types
+ if (subscript != 0 && subscript != GL_INVALID_INDEX)
+ {
+ return GL_INVALID_INDEX;
+ }
+
+ for (size_t index = 0; index < mUniforms.size(); index++)
+ {
+ const LinkedUniform &uniform = mUniforms[index];
+ if (uniform.name == baseName)
+ {
+ if (uniform.isArray() || subscript == GL_INVALID_INDEX)
+ {
+ return static_cast<GLuint>(index);
+ }
+ }
+ }
+
+ return GL_INVALID_INDEX;
+}
+
Program::Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle)
: mProgram(factory->createProgram(mData)),
mValidated(false),
@@ -319,6 +509,7 @@
}
gatherTransformFeedbackVaryings(mergedVaryings);
+ mProgram->gatherUniformBlockInfo(&mData.mUniformBlocks, &mData.mUniforms);
mLinked = true;
return gl::Error(GL_NO_ERROR);
@@ -358,10 +549,11 @@
mData.mAttributes.clear();
mData.mActiveAttribLocationsMask.reset();
mData.mTransformFeedbackVaryingVars.clear();
+ mData.mUniforms.clear();
+ mData.mUniformLocations.clear();
+ mData.mUniformBlocks.clear();
mData.mOutputVariables.clear();
- mProgram->reset();
-
mValidated = false;
mLinked = false;
@@ -415,15 +607,66 @@
for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
{
sh::Attribute attrib;
- attrib.type = stream.readInt<GLenum>();
- attrib.precision = stream.readInt<GLenum>();
- attrib.name = stream.readString();
- attrib.arraySize = stream.readInt<GLint>();
- attrib.location = stream.readInt<int>();
- attrib.staticUse = stream.readBool();
+ LoadShaderVar(&stream, &attrib);
+ attrib.location = stream.readInt<int>();
mData.mAttributes.push_back(attrib);
}
+ unsigned int uniformCount = stream.readInt<unsigned int>();
+ ASSERT(mData.mUniforms.empty());
+ for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
+ {
+ LinkedUniform uniform;
+ LoadShaderVar(&stream, &uniform);
+
+ uniform.blockIndex = stream.readInt<int>();
+ uniform.blockInfo.offset = stream.readInt<int>();
+ uniform.blockInfo.arrayStride = stream.readInt<int>();
+ uniform.blockInfo.matrixStride = stream.readInt<int>();
+ uniform.blockInfo.isRowMajorMatrix = stream.readBool();
+
+ mData.mUniforms.push_back(uniform);
+ }
+
+ const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
+ ASSERT(mData.mUniformLocations.empty());
+ for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
+ uniformIndexIndex++)
+ {
+ VariableLocation variable;
+ stream.readString(&variable.name);
+ stream.readInt(&variable.element);
+ stream.readInt(&variable.index);
+
+ mData.mUniformLocations.push_back(variable);
+ }
+
+ unsigned int uniformBlockCount = stream.readInt<unsigned int>();
+ ASSERT(mData.mUniformBlocks.empty());
+ for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
+ ++uniformBlockIndex)
+ {
+ UniformBlock uniformBlock;
+ stream.readString(&uniformBlock.name);
+ stream.readBool(&uniformBlock.isArray);
+ stream.readInt(&uniformBlock.arrayElement);
+ stream.readInt(&uniformBlock.dataSize);
+ stream.readBool(&uniformBlock.vertexStaticUse);
+ stream.readBool(&uniformBlock.fragmentStaticUse);
+
+ unsigned int numMembers = stream.readInt<unsigned int>();
+ for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
+ {
+ uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
+ }
+
+ // TODO(jmadill): Make D3D-only
+ stream.readInt(&uniformBlock.psRegisterIndex);
+ stream.readInt(&uniformBlock.vsRegisterIndex);
+
+ mData.mUniformBlocks.push_back(uniformBlock);
+ }
+
stream.readInt(&mData.mTransformFeedbackBufferMode);
unsigned int outputVarCount = stream.readInt<unsigned int>();
@@ -467,12 +710,52 @@
stream.writeInt(mData.mAttributes.size());
for (const sh::Attribute &attrib : mData.mAttributes)
{
- stream.writeInt(attrib.type);
- stream.writeInt(attrib.precision);
- stream.writeString(attrib.name);
- stream.writeInt(attrib.arraySize);
+ WriteShaderVar(&stream, attrib);
stream.writeInt(attrib.location);
- stream.writeInt(attrib.staticUse);
+ }
+
+ stream.writeInt(mData.mUniforms.size());
+ for (const gl::LinkedUniform &uniform : mData.mUniforms)
+ {
+ WriteShaderVar(&stream, uniform);
+
+ // FIXME: referenced
+
+ stream.writeInt(uniform.blockIndex);
+ stream.writeInt(uniform.blockInfo.offset);
+ stream.writeInt(uniform.blockInfo.arrayStride);
+ stream.writeInt(uniform.blockInfo.matrixStride);
+ stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
+ }
+
+ stream.writeInt(mData.mUniformLocations.size());
+ for (const auto &variable : mData.mUniformLocations)
+ {
+ stream.writeString(variable.name);
+ stream.writeInt(variable.element);
+ stream.writeInt(variable.index);
+ }
+
+ stream.writeInt(mData.mUniformBlocks.size());
+ for (const UniformBlock &uniformBlock : mData.mUniformBlocks)
+ {
+ stream.writeString(uniformBlock.name);
+ stream.writeInt(uniformBlock.isArray);
+ stream.writeInt(uniformBlock.arrayElement);
+ stream.writeInt(uniformBlock.dataSize);
+
+ stream.writeInt(uniformBlock.vertexStaticUse);
+ stream.writeInt(uniformBlock.fragmentStaticUse);
+
+ stream.writeInt(uniformBlock.memberUniformIndexes.size());
+ for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
+ {
+ stream.writeInt(memberUniformIndex);
+ }
+
+ // TODO(jmadill): make D3D-only
+ stream.writeInt(uniformBlock.psRegisterIndex);
+ stream.writeInt(uniformBlock.vsRegisterIndex);
}
stream.writeInt(mData.mTransformFeedbackBufferMode);
@@ -728,13 +1011,14 @@
{
if (mLinked)
{
- ASSERT(index < mProgram->getUniforms().size()); // index must be smaller than getActiveUniformCount()
- LinkedUniform *uniform = mProgram->getUniforms()[index];
+ // index must be smaller than getActiveUniformCount()
+ ASSERT(index < mData.mUniforms.size());
+ const LinkedUniform &uniform = mData.mUniforms[index];
if (bufsize > 0)
{
- std::string string = uniform->name;
- if (uniform->isArray())
+ std::string string = uniform.name;
+ if (uniform.isArray())
{
string += "[0]";
}
@@ -748,8 +1032,8 @@
}
}
- *size = uniform->elementCount();
- *type = uniform->type;
+ *size = uniform.elementCount();
+ *type = uniform.type;
}
else
{
@@ -772,7 +1056,7 @@
{
if (mLinked)
{
- return static_cast<GLint>(mProgram->getUniforms().size());
+ return static_cast<GLint>(mData.mUniforms.size());
}
else
{
@@ -782,17 +1066,16 @@
GLint Program::getActiveUniformMaxLength()
{
- int maxLength = 0;
+ size_t maxLength = 0;
if (mLinked)
{
- unsigned int numUniforms = static_cast<unsigned int>(mProgram->getUniforms().size());
- for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
+ for (const LinkedUniform &uniform : mData.mUniforms)
{
- if (!mProgram->getUniforms()[uniformIndex]->name.empty())
+ if (!uniform.name.empty())
{
- int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1);
- if (mProgram->getUniforms()[uniformIndex]->isArray())
+ size_t length = uniform.name.length() + 1u;
+ if (uniform.isArray())
{
length += 3; // Counting in "[0]".
}
@@ -801,12 +1084,13 @@
}
}
- return maxLength;
+ return static_cast<GLint>(maxLength);
}
GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
{
- const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index];
+ ASSERT(static_cast<size_t>(index) < mData.mUniforms.size());
+ const gl::LinkedUniform &uniform = mData.mUniforms[index];
switch (pname)
{
case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
@@ -826,149 +1110,165 @@
bool Program::isValidUniformLocation(GLint location) const
{
- const auto &uniformIndices = mProgram->getUniformIndices();
- ASSERT(rx::IsIntegerCastSafe<GLint>(uniformIndices.size()));
- return (location >= 0 && uniformIndices.find(location) != uniformIndices.end());
+ ASSERT(rx::IsIntegerCastSafe<GLint>(mData.mUniformLocations.size()));
+ return (location >= 0 && static_cast<size_t>(location) < mData.mUniformLocations.size());
}
-LinkedUniform *Program::getUniformByLocation(GLint location) const
+const LinkedUniform &Program::getUniformByLocation(GLint location) const
{
- return mProgram->getUniformByLocation(location);
+ ASSERT(location >= 0 && static_cast<size_t>(location) < mData.mUniformLocations.size());
+ return mData.mUniforms[mData.mUniformLocations[location].index];
}
-LinkedUniform *Program::getUniformByName(const std::string &name) const
+GLint Program::getUniformLocation(const std::string &name) const
{
- return mProgram->getUniformByName(name);
+ return mData.getUniformLocation(name);
}
-GLint Program::getUniformLocation(const std::string &name)
+GLuint Program::getUniformIndex(const std::string &name) const
{
- return mProgram->getUniformLocation(name);
-}
-
-GLuint Program::getUniformIndex(const std::string &name)
-{
- return mProgram->getUniformIndex(name);
+ return mData.getUniformIndex(name);
}
void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
{
+ setUniformInternal(location, count * 1, v);
mProgram->setUniform1fv(location, count, v);
}
void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
{
+ setUniformInternal(location, count * 2, v);
mProgram->setUniform2fv(location, count, v);
}
void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
{
+ setUniformInternal(location, count * 3, v);
mProgram->setUniform3fv(location, count, v);
}
void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
{
+ setUniformInternal(location, count * 4, v);
mProgram->setUniform4fv(location, count, v);
}
void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
{
+ setUniformInternal(location, count * 1, v);
mProgram->setUniform1iv(location, count, v);
}
void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
{
+ setUniformInternal(location, count * 2, v);
mProgram->setUniform2iv(location, count, v);
}
void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
{
+ setUniformInternal(location, count * 3, v);
mProgram->setUniform3iv(location, count, v);
}
void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
{
+ setUniformInternal(location, count * 4, v);
mProgram->setUniform4iv(location, count, v);
}
void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
{
+ setUniformInternal(location, count * 1, v);
mProgram->setUniform1uiv(location, count, v);
}
void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
{
+ setUniformInternal(location, count * 2, v);
mProgram->setUniform2uiv(location, count, v);
}
void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
{
+ setUniformInternal(location, count * 3, v);
mProgram->setUniform3uiv(location, count, v);
}
void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
{
+ setUniformInternal(location, count * 4, v);
mProgram->setUniform4uiv(location, count, v);
}
void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<2, 2>(location, count, transpose, v);
mProgram->setUniformMatrix2fv(location, count, transpose, v);
}
void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<3, 3>(location, count, transpose, v);
mProgram->setUniformMatrix3fv(location, count, transpose, v);
}
void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<4, 4>(location, count, transpose, v);
mProgram->setUniformMatrix4fv(location, count, transpose, v);
}
void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<2, 3>(location, count, transpose, v);
mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
}
void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<2, 4>(location, count, transpose, v);
mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
}
void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<3, 2>(location, count, transpose, v);
mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
}
void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<3, 4>(location, count, transpose, v);
mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
}
void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<4, 2>(location, count, transpose, v);
mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
}
void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<4, 3>(location, count, transpose, v);
mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
}
void Program::getUniformfv(GLint location, GLfloat *v)
{
- mProgram->getUniformfv(location, v);
+ getUniformInternal(location, v);
}
void Program::getUniformiv(GLint location, GLint *v)
{
- mProgram->getUniformiv(location, v);
+ getUniformInternal(location, v);
}
void Program::getUniformuiv(GLint location, GLuint *v)
{
- mProgram->getUniformuiv(location, v);
+ getUniformInternal(location, v);
}
void Program::flagForDeletion()
@@ -1007,22 +1307,23 @@
GLuint Program::getActiveUniformBlockCount()
{
- return static_cast<GLuint>(mProgram->getUniformBlocks().size());
+ return static_cast<GLuint>(mData.mUniformBlocks.size());
}
void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
{
- ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
+ ASSERT(uniformBlockIndex <
+ mData.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
- const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+ const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
if (bufSize > 0)
{
std::string string = uniformBlock.name;
- if (uniformBlock.isArrayElement())
+ if (uniformBlock.isArray)
{
- string += ArrayString(uniformBlock.elementIndex);
+ string += ArrayString(uniformBlock.arrayElement);
}
strncpy(uniformBlockName, string.c_str(), bufSize);
@@ -1037,9 +1338,10 @@
void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
{
- ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
+ ASSERT(uniformBlockIndex <
+ mData.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
- const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+ const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
switch (pname)
{
@@ -1047,7 +1349,8 @@
*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));
+ *params =
+ static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArray ? 3 : 0));
break;
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
*params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
@@ -1061,10 +1364,10 @@
}
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
- *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
+ *params = static_cast<GLint>(uniformBlock.vertexStaticUse);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
- *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
+ *params = static_cast<GLint>(uniformBlock.fragmentStaticUse);
break;
default: UNREACHABLE();
}
@@ -1076,17 +1379,16 @@
if (mLinked)
{
- unsigned int numUniformBlocks =
- static_cast<unsigned int>(mProgram->getUniformBlocks().size());
+ unsigned int numUniformBlocks = static_cast<unsigned int>(mData.mUniformBlocks.size());
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
{
- const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+ const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
if (!uniformBlock.name.empty())
{
const int length = static_cast<int>(uniformBlock.name.length()) + 1;
// Counting in "[0]".
- const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
+ const int arrayLength = (uniformBlock.isArray ? 3 : 0);
maxLength = std::max(length + arrayLength, maxLength);
}
@@ -1098,12 +1400,32 @@
GLuint Program::getUniformBlockIndex(const std::string &name)
{
- return mProgram->getUniformBlockIndex(name);
+ size_t subscript = GL_INVALID_INDEX;
+ std::string baseName = gl::ParseUniformName(name, &subscript);
+
+ unsigned int numUniformBlocks = static_cast<unsigned int>(mData.mUniformBlocks.size());
+ for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
+ {
+ const gl::UniformBlock &uniformBlock = mData.mUniformBlocks[blockIndex];
+ if (uniformBlock.name == baseName)
+ {
+ const bool arrayElementZero =
+ (subscript == GL_INVALID_INDEX &&
+ (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
+ if (subscript == uniformBlock.arrayElement || arrayElementZero)
+ {
+ return blockIndex;
+ }
+ }
+ }
+
+ return GL_INVALID_INDEX;
}
-const UniformBlock *Program::getUniformBlockByIndex(GLuint index) const
+const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
{
- return mProgram->getUniformBlockByIndex(index);
+ ASSERT(index < static_cast<GLuint>(mData.mUniformBlocks.size()));
+ return mData.mUniformBlocks[index];
}
void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
@@ -1243,17 +1565,17 @@
return true;
}
-bool Program::linkUniforms(gl::InfoLog &infoLog, const gl::Caps & /*caps*/) const
+bool Program::linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps)
{
const std::vector<sh::Uniform> &vertexUniforms = mData.mAttachedVertexShader->getUniforms();
const std::vector<sh::Uniform> &fragmentUniforms = mData.mAttachedFragmentShader->getUniforms();
// Check that uniforms defined in the vertex and fragment shaders are identical
- std::map<std::string, const sh::Uniform *> linkedUniforms;
+ std::map<std::string, LinkedUniform> linkedUniforms;
for (const sh::Uniform &vertexUniform : vertexUniforms)
{
- linkedUniforms[vertexUniform.name] = &vertexUniform;
+ linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
}
for (const sh::Uniform &fragmentUniform : fragmentUniforms)
@@ -1261,19 +1583,45 @@
auto entry = linkedUniforms.find(fragmentUniform.name);
if (entry != linkedUniforms.end())
{
- const sh::Uniform &vertexUniform = *entry->second;
- const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
- if (!linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
+ LinkedUniform *vertexUniform = &entry->second;
+ const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
+ if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
{
return false;
}
}
}
- // TODO(jmadill): check sampler uniforms with caps
+ // Flatten the uniforms list (nested fields) into a simple list (no nesting).
+ // Also check the maximum uniform vector and sampler counts.
+ if (!flattenUniformsAndCheckCaps(caps, infoLog))
+ {
+ return false;
+ }
+
+ indexUniforms();
+
return true;
}
+void Program::indexUniforms()
+{
+ for (size_t uniformIndex = 0; uniformIndex < mData.mUniforms.size(); uniformIndex++)
+ {
+ const gl::LinkedUniform &uniform = mData.mUniforms[uniformIndex];
+
+ for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
+ {
+ if (!uniform.isBuiltIn())
+ {
+ // Assign in-order uniform locations
+ mData.mUniformLocations.push_back(gl::VariableLocation(
+ uniform.name, arrayIndex, static_cast<unsigned int>(uniformIndex)));
+ }
+ }
+ }
+}
+
bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
{
if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
@@ -1453,6 +1801,8 @@
}
}
+ gatherInterfaceBlockInfo();
+
return true;
}
@@ -1730,4 +2080,282 @@
}
}
}
+
+bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
+{
+ const gl::Shader *vertexShader = mData.getAttachedVertexShader();
+ VectorAndSamplerCount vsCounts;
+
+ for (const sh::Uniform &uniform : vertexShader->getUniforms())
+ {
+ if (uniform.staticUse)
+ {
+ vsCounts += flattenUniform(uniform, uniform.name);
+ }
+ }
+
+ if (vsCounts.vectorCount > caps.maxVertexUniformVectors)
+ {
+ infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS ("
+ << caps.maxVertexUniformVectors << ").";
+ return false;
+ }
+
+ if (vsCounts.samplerCount > caps.maxVertexTextureImageUnits)
+ {
+ infoLog << "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS ("
+ << caps.maxVertexTextureImageUnits << ").";
+ return false;
+ }
+
+ const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
+ VectorAndSamplerCount fsCounts;
+
+ for (const sh::Uniform &uniform : fragmentShader->getUniforms())
+ {
+ if (uniform.staticUse)
+ {
+ fsCounts += flattenUniform(uniform, uniform.name);
+ }
+ }
+
+ if (fsCounts.vectorCount > caps.maxFragmentUniformVectors)
+ {
+ infoLog << "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS ("
+ << caps.maxFragmentUniformVectors << ").";
+ return false;
+ }
+
+ if (fsCounts.samplerCount > caps.maxTextureImageUnits)
+ {
+ infoLog << "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
+ << caps.maxTextureImageUnits << ").";
+ return false;
+ }
+
+ return true;
+}
+
+Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
+ const std::string &fullName)
+{
+ VectorAndSamplerCount vectorAndSamplerCount;
+
+ if (uniform.isStruct())
+ {
+ for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
+ {
+ const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
+
+ for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
+ {
+ const sh::ShaderVariable &field = uniform.fields[fieldIndex];
+ const std::string &fieldFullName = (fullName + elementString + "." + field.name);
+
+ vectorAndSamplerCount += flattenUniform(field, fieldFullName);
+ }
+ }
+
+ return vectorAndSamplerCount;
+ }
+
+ // Not a struct
+ if (mData.getUniformByName(fullName) == nullptr)
+ {
+ gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName,
+ uniform.arraySize, -1,
+ sh::BlockMemberInfo::getDefaultBlockInfo());
+ linkedUniform.staticUse = true;
+ mData.mUniforms.push_back(linkedUniform);
+ }
+
+ vectorAndSamplerCount.vectorCount =
+ (VariableRegisterCount(uniform.type) * uniform.elementCount());
+ vectorAndSamplerCount.samplerCount = (IsSamplerType(uniform.type) ? uniform.elementCount() : 0);
+
+ return vectorAndSamplerCount;
+}
+
+void Program::gatherInterfaceBlockInfo()
+{
+ std::set<std::string> visitedList;
+
+ const gl::Shader *vertexShader = mData.getAttachedVertexShader();
+
+ ASSERT(mData.mUniformBlocks.empty());
+ for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
+ {
+ // Only 'packed' blocks are allowed to be considered inacive.
+ if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
+
+ if (visitedList.count(vertexBlock.name) > 0)
+ continue;
+
+ defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
+ visitedList.insert(vertexBlock.name);
+ }
+
+ const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
+
+ for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
+ {
+ // Only 'packed' blocks are allowed to be considered inacive.
+ if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
+
+ if (visitedList.count(fragmentBlock.name) > 0)
+ {
+ for (gl::UniformBlock &block : mData.mUniformBlocks)
+ {
+ if (block.name == fragmentBlock.name)
+ {
+ block.fragmentStaticUse = fragmentBlock.staticUse;
+ }
+ }
+
+ continue;
+ }
+
+ defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
+ visitedList.insert(fragmentBlock.name);
+ }
+}
+
+void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
+{
+ int blockIndex = static_cast<int>(mData.mUniformBlocks.size());
+ size_t firstBlockUniformIndex = mData.mUniforms.size();
+ DefineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, &mData.mUniforms);
+ size_t lastBlockUniformIndex = mData.mUniforms.size();
+
+ std::vector<unsigned int> blockUniformIndexes;
+ for (size_t blockUniformIndex = firstBlockUniformIndex;
+ blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
+ {
+ blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
+ }
+
+ if (interfaceBlock.arraySize > 0)
+ {
+ for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
+ {
+ UniformBlock block(interfaceBlock.name, true, arrayElement);
+ block.memberUniformIndexes = blockUniformIndexes;
+
+ if (shaderType == GL_VERTEX_SHADER)
+ {
+ block.vertexStaticUse = interfaceBlock.staticUse;
+ }
+ else
+ {
+ ASSERT(shaderType == GL_FRAGMENT_SHADER);
+ block.fragmentStaticUse = interfaceBlock.staticUse;
+ }
+
+ mData.mUniformBlocks.push_back(block);
+ }
+ }
+ else
+ {
+ UniformBlock block(interfaceBlock.name, false, 0);
+ block.memberUniformIndexes = blockUniformIndexes;
+
+ if (shaderType == GL_VERTEX_SHADER)
+ {
+ block.vertexStaticUse = interfaceBlock.staticUse;
+ }
+ else
+ {
+ ASSERT(shaderType == GL_FRAGMENT_SHADER);
+ block.fragmentStaticUse = interfaceBlock.staticUse;
+ }
+
+ mData.mUniformBlocks.push_back(block);
+ }
+}
+
+template <typename T>
+void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
+{
+ const VariableLocation &locationInfo = mData.mUniformLocations[location];
+ LinkedUniform *linkedUniform = &mData.mUniforms[locationInfo.index];
+ uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
+
+ if (VariableComponentType(linkedUniform->type) == GL_BOOL)
+ {
+ // Do a cast conversion for boolean types. From the spec:
+ // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
+ GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
+ for (GLsizei component = 0; component < count; ++component)
+ {
+ destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
+ }
+ }
+ else
+ {
+ memcpy(destPointer, v, sizeof(T) * count);
+ }
+}
+
+template <size_t cols, size_t rows, typename T>
+void Program::setMatrixUniformInternal(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const T *v)
+{
+ if (!transpose)
+ {
+ setUniformInternal(location, count * cols * rows, v);
+ return;
+ }
+
+ // Perform a transposing copy.
+ const VariableLocation &locationInfo = mData.mUniformLocations[location];
+ LinkedUniform *linkedUniform = &mData.mUniforms[locationInfo.index];
+ T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
+ for (size_t row = 0; row < rows; ++row)
+ {
+ for (size_t col = 0; col < cols; ++col)
+ {
+ destPtr[col * rows + row] = v[row * cols + col];
+ }
+ }
+}
+
+template <typename DestT>
+void Program::getUniformInternal(GLint location, DestT *dataOut) const
+{
+ const VariableLocation &locationInfo = mData.mUniformLocations[location];
+ const LinkedUniform &uniform = mData.mUniforms[locationInfo.index];
+
+ const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
+
+ GLenum componentType = VariableComponentType(uniform.type);
+ if (componentType == GLTypeToGLenum<DestT>::value)
+ {
+ memcpy(dataOut, srcPointer, uniform.getElementSize());
+ return;
+ }
+
+ int components = VariableComponentCount(uniform.type) * uniform.elementCount();
+
+ switch (componentType)
+ {
+ case GL_INT:
+ UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
+ break;
+ case GL_UNSIGNED_INT:
+ UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
+ break;
+ case GL_BOOL:
+ UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
+ break;
+ case GL_FLOAT:
+ UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
}
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
index b95d5b8..3dd7c46 100644
--- a/src/libANGLE/Program.h
+++ b/src/libANGLE/Program.h
@@ -189,6 +189,16 @@
{
return mOutputVariables;
}
+ const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
+ const std::vector<VariableLocation> &getUniformLocations() const
+ {
+ return mUniformLocations;
+ }
+ const std::vector<UniformBlock> &getUniformBlocks() const { return mUniformBlocks; }
+
+ const LinkedUniform *getUniformByName(const std::string &name) const;
+ GLint getUniformLocation(const std::string &name) const;
+ GLuint getUniformIndex(const std::string &name) const;
private:
friend class Program;
@@ -205,10 +215,12 @@
std::vector<sh::Attribute> mAttributes;
std::bitset<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
+ std::vector<LinkedUniform> mUniforms;
+ std::vector<VariableLocation> mUniformLocations;
+ std::vector<UniformBlock> mUniformBlocks;
+
// TODO(jmadill): use unordered/hash map when available
std::map<int, VariableLocation> mOutputVariables;
-
- // TODO(jmadill): move more state into Data.
};
Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle);
@@ -251,11 +263,10 @@
GLint getActiveUniformMaxLength();
GLint getActiveUniformi(GLuint index, GLenum pname) const;
bool isValidUniformLocation(GLint location) const;
- LinkedUniform *getUniformByLocation(GLint location) const;
- LinkedUniform *getUniformByName(const std::string &name) const;
+ const LinkedUniform &getUniformByLocation(GLint location) const;
- GLint getUniformLocation(const std::string &name);
- GLuint getUniformIndex(const std::string &name);
+ GLint getUniformLocation(const std::string &name) const;
+ GLuint getUniformIndex(const std::string &name) const;
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
void setUniform2fv(GLint location, GLsizei count, const GLfloat *v);
void setUniform3fv(GLint location, GLsizei count, const GLfloat *v);
@@ -292,7 +303,7 @@
void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding);
GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const;
- const UniformBlock *getUniformBlockByIndex(GLuint index) const;
+ const UniformBlock &getUniformBlockByIndex(GLuint index) const;
void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode);
void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const;
@@ -330,7 +341,8 @@
static bool linkVaryings(InfoLog &infoLog,
const Shader *vertexShader,
const Shader *fragmentShader);
- bool linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps) const;
+ bool linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps);
+ void indexUniforms();
bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
const sh::InterfaceBlock &fragmentInterfaceBlock);
@@ -352,6 +364,40 @@
std::vector<const sh::Varying *> getMergedVaryings() const;
void linkOutputVariables();
+ bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog);
+
+ struct VectorAndSamplerCount
+ {
+ VectorAndSamplerCount() : vectorCount(0), samplerCount(0) {}
+ VectorAndSamplerCount(const VectorAndSamplerCount &other) = default;
+ VectorAndSamplerCount &operator=(const VectorAndSamplerCount &other) = default;
+
+ VectorAndSamplerCount &operator+=(const VectorAndSamplerCount &other)
+ {
+ vectorCount += other.vectorCount;
+ samplerCount += other.samplerCount;
+ return *this;
+ }
+
+ unsigned int vectorCount;
+ unsigned int samplerCount;
+ };
+
+ VectorAndSamplerCount flattenUniform(const sh::ShaderVariable &uniform,
+ const std::string &fullName);
+
+ void gatherInterfaceBlockInfo();
+ void defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType);
+
+ template <typename T>
+ void setUniformInternal(GLint location, GLsizei count, const T *v);
+
+ template <size_t cols, size_t rows, typename T>
+ void setMatrixUniformInternal(GLint location, GLsizei count, GLboolean transpose, const T *v);
+
+ template <typename DestT>
+ void getUniformInternal(GLint location, DestT *dataOut) const;
+
Data mData;
rx::ProgramImpl *mProgram;
diff --git a/src/libANGLE/Uniform.cpp b/src/libANGLE/Uniform.cpp
index 24e7f11..3a20f4c 100644
--- a/src/libANGLE/Uniform.cpp
+++ b/src/libANGLE/Uniform.cpp
@@ -13,55 +13,51 @@
namespace gl
{
-LinkedUniform::LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize,
- const int blockIndex, const sh::BlockMemberInfo &blockInfo)
- : type(type),
- precision(precision),
- name(name),
- arraySize(arraySize),
- blockIndex(blockIndex),
- blockInfo(blockInfo),
- data(NULL),
- dirty(true),
- psRegisterIndex(GL_INVALID_INDEX),
- vsRegisterIndex(GL_INVALID_INDEX),
- registerCount(0),
- registerElement(0)
+LinkedUniform::LinkedUniform()
+ : blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
{
- // We use data storage for default block uniforms to cache values that are sent to D3D during rendering
- // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only)
- if (isInDefaultBlock())
- {
- size_t bytes = dataSize();
- data = new unsigned char[bytes];
- memset(data, 0, bytes);
- registerCount = VariableRowCount(type) * elementCount();
- }
+}
+
+LinkedUniform::LinkedUniform(GLenum typeIn,
+ GLenum precisionIn,
+ const std::string &nameIn,
+ unsigned int arraySizeIn,
+ const int blockIndexIn,
+ const sh::BlockMemberInfo &blockInfoIn)
+ : blockIndex(blockIndexIn), blockInfo(blockInfoIn)
+{
+ type = typeIn;
+ precision = precisionIn;
+ name = nameIn;
+ arraySize = arraySizeIn;
+}
+
+LinkedUniform::LinkedUniform(const sh::Uniform &uniform)
+ : sh::Uniform(uniform), blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
+{
+}
+
+LinkedUniform::LinkedUniform(const LinkedUniform &uniform)
+ : sh::Uniform(uniform), blockIndex(uniform.blockIndex), blockInfo(uniform.blockInfo)
+{
+ // This function is not intended to be called during runtime.
+ ASSERT(uniform.mLazyData.empty());
+}
+
+LinkedUniform &LinkedUniform::operator=(const LinkedUniform &uniform)
+{
+ // This function is not intended to be called during runtime.
+ ASSERT(uniform.mLazyData.empty());
+
+ sh::Uniform::operator=(uniform);
+ blockIndex = uniform.blockIndex;
+ blockInfo = uniform.blockInfo;
+
+ return *this;
}
LinkedUniform::~LinkedUniform()
{
- delete[] data;
-}
-
-bool LinkedUniform::isArray() const
-{
- return arraySize > 0;
-}
-
-unsigned int LinkedUniform::elementCount() const
-{
- return arraySize > 0 ? arraySize : 1;
-}
-
-bool LinkedUniform::isReferencedByVertexShader() const
-{
- return vsRegisterIndex != GL_INVALID_INDEX;
-}
-
-bool LinkedUniform::isReferencedByFragmentShader() const
-{
- return psRegisterIndex != GL_INVALID_INDEX;
}
bool LinkedUniform::isInDefaultBlock() const
@@ -72,7 +68,30 @@
size_t LinkedUniform::dataSize() const
{
ASSERT(type != GL_STRUCT_ANGLEX);
- return VariableInternalSize(type) * elementCount();
+ if (mLazyData.empty())
+ {
+ mLazyData.resize(VariableExternalSize(type) * elementCount());
+ ASSERT(!mLazyData.empty());
+ }
+
+ return mLazyData.size();
+}
+
+uint8_t *LinkedUniform::data()
+{
+ if (mLazyData.empty())
+ {
+ // dataSize() will init the data store.
+ size_t size = dataSize();
+ memset(mLazyData.data(), 0, size);
+ }
+
+ return mLazyData.data();
+}
+
+const uint8_t *LinkedUniform::data() const
+{
+ return const_cast<LinkedUniform *>(this)->data();
}
bool LinkedUniform::isSampler() const
@@ -80,33 +99,48 @@
return IsSamplerType(type);
}
-bool LinkedUniform::isBuiltIn() const
+bool LinkedUniform::isField() const
{
- return name.compare(0, 3, "gl_") == 0;
+ return name.find('.') != std::string::npos;
}
-UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize)
- : name(name),
- elementIndex(elementIndex),
- dataSize(dataSize),
+size_t LinkedUniform::getElementSize() const
+{
+ return VariableExternalSize(type);
+}
+
+uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex)
+{
+ ASSERT((!isArray() && elementIndex == 0) || (isArray() && elementIndex < arraySize));
+ return data() + getElementSize() * elementIndex;
+}
+
+const uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex) const
+{
+ return const_cast<LinkedUniform *>(this)->getDataPtrToElement(elementIndex);
+}
+
+UniformBlock::UniformBlock()
+ : isArray(false),
+ arrayElement(0),
+ dataSize(0),
+ vertexStaticUse(false),
+ fragmentStaticUse(false),
psRegisterIndex(GL_INVALID_INDEX),
vsRegisterIndex(GL_INVALID_INDEX)
{
}
-bool UniformBlock::isArrayElement() const
+UniformBlock::UniformBlock(const std::string &nameIn, bool isArrayIn, unsigned int arrayElementIn)
+ : name(nameIn),
+ isArray(isArrayIn),
+ arrayElement(arrayElementIn),
+ dataSize(0),
+ vertexStaticUse(false),
+ fragmentStaticUse(false),
+ psRegisterIndex(GL_INVALID_INDEX),
+ vsRegisterIndex(GL_INVALID_INDEX)
{
- return elementIndex != GL_INVALID_INDEX;
-}
-
-bool UniformBlock::isReferencedByVertexShader() const
-{
- return vsRegisterIndex != GL_INVALID_INDEX;
-}
-
-bool UniformBlock::isReferencedByFragmentShader() const
-{
- return psRegisterIndex != GL_INVALID_INDEX;
}
}
diff --git a/src/libANGLE/Uniform.h b/src/libANGLE/Uniform.h
index b73fc9d..040c978 100644
--- a/src/libANGLE/Uniform.h
+++ b/src/libANGLE/Uniform.h
@@ -12,6 +12,7 @@
#include "angle_gl.h"
#include "common/debug.h"
+#include "common/MemoryBuffer.h"
#include "compiler/translator/blocklayout.h"
#include "libANGLE/angletypes.h"
@@ -19,53 +20,47 @@
{
// Helper struct representing a single shader uniform
-struct LinkedUniform : angle::NonCopyable
+struct LinkedUniform : public sh::Uniform
{
+ LinkedUniform();
LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, const int blockIndex, const sh::BlockMemberInfo &blockInfo);
-
+ LinkedUniform(const sh::Uniform &uniform);
+ LinkedUniform(const LinkedUniform &uniform);
+ LinkedUniform &operator=(const LinkedUniform &uniform);
~LinkedUniform();
- bool isArray() const;
- unsigned int elementCount() const;
- bool isReferencedByVertexShader() const;
- bool isReferencedByFragmentShader() const;
- bool isInDefaultBlock() const;
size_t dataSize() const;
+ uint8_t *data();
+ const uint8_t *data() const;
bool isSampler() const;
- bool isBuiltIn() const;
+ bool isInDefaultBlock() const;
+ bool isField() const;
+ size_t getElementSize() const;
+ uint8_t *getDataPtrToElement(size_t elementIndex);
+ const uint8_t *getDataPtrToElement(size_t elementIndex) const;
- const GLenum type;
- const GLenum precision;
- const std::string name;
- const unsigned int arraySize;
- const int blockIndex;
- const sh::BlockMemberInfo blockInfo;
+ int blockIndex;
+ sh::BlockMemberInfo blockInfo;
- unsigned char *data;
- bool dirty;
-
- unsigned int psRegisterIndex;
- unsigned int vsRegisterIndex;
- unsigned int registerCount;
-
- // Register "elements" are used for uniform structs in ES3, to appropriately identify single uniforms
- // inside aggregate types, which are packed according C-like structure rules.
- unsigned int registerElement;
+ private:
+ mutable rx::MemoryBuffer mLazyData;
};
// Helper struct representing a single shader uniform block
-struct UniformBlock : angle::NonCopyable
+struct UniformBlock
{
- // use GL_INVALID_INDEX for non-array elements
- UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize);
+ UniformBlock();
+ UniformBlock(const std::string &nameIn, bool isArrayIn, unsigned int arrayElementIn);
+ UniformBlock(const UniformBlock &other) = default;
+ UniformBlock &operator=(const UniformBlock &other) = default;
- bool isArrayElement() const;
- bool isReferencedByVertexShader() const;
- bool isReferencedByFragmentShader() const;
+ std::string name;
+ bool isArray;
+ unsigned int arrayElement;
+ unsigned int dataSize;
- const std::string name;
- const unsigned int elementIndex;
- const unsigned int dataSize;
+ bool vertexStaticUse;
+ bool fragmentStaticUse;
std::vector<unsigned int> memberUniformIndexes;
diff --git a/src/libANGLE/queryconversions.cpp b/src/libANGLE/queryconversions.cpp
index d18a8e1..5633ce4 100644
--- a/src/libANGLE/queryconversions.cpp
+++ b/src/libANGLE/queryconversions.cpp
@@ -6,32 +6,24 @@
// queryconversions.cpp: Implementation of state query cast conversions
+#include "libANGLE/queryconversions.h"
+
#include "libANGLE/Context.h"
#include "common/utilities.h"
namespace gl
{
-// Helper class for converting a GL type to a GLenum:
-// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap.
-// We restrict our use to CastStateValue, where it eliminates duplicate parameters.
+namespace
+{
-template <typename GLType>
-struct CastStateValueEnum { static GLenum mEnumForType; };
-
-template <> GLenum CastStateValueEnum<GLint>::mEnumForType = GL_INT;
-template <> GLenum CastStateValueEnum<GLuint>::mEnumForType = GL_UNSIGNED_INT;
-template <> GLenum CastStateValueEnum<GLboolean>::mEnumForType = GL_BOOL;
-template <> GLenum CastStateValueEnum<GLint64>::mEnumForType = GL_INT_64_ANGLEX;
-template <> GLenum CastStateValueEnum<GLfloat>::mEnumForType = GL_FLOAT;
-
-static GLint64 ExpandFloatToInteger(GLfloat value)
+GLint64 ExpandFloatToInteger(GLfloat value)
{
return static_cast<GLint64>((static_cast<double>(0xFFFFFFFFULL) * value - 1.0) / 2.0);
}
template <typename QueryT>
-static QueryT ClampToQueryRange(GLint64 value)
+QueryT ClampToQueryRange(GLint64 value)
{
const GLint64 min = static_cast<GLint64>(std::numeric_limits<QueryT>::min());
const GLint64 max = static_cast<GLint64>(std::numeric_limits<QueryT>::max());
@@ -41,8 +33,8 @@
template <typename QueryT, typename NativeT>
QueryT CastStateValueToInt(GLenum pname, NativeT value)
{
- GLenum queryType = CastStateValueEnum<QueryT>::mEnumForType;
- GLenum nativeType = CastStateValueEnum<NativeT>::mEnumForType;
+ GLenum queryType = GLTypeToGLenum<QueryT>::value;
+ GLenum nativeType = GLTypeToGLenum<NativeT>::value;
if (nativeType == GL_FLOAT)
{
@@ -72,18 +64,37 @@
template <typename QueryT, typename NativeT>
QueryT CastStateValue(GLenum pname, NativeT value)
{
- GLenum queryType = CastStateValueEnum<QueryT>::mEnumForType;
+ GLenum queryType = GLTypeToGLenum<QueryT>::value;
switch (queryType)
{
- case GL_INT: return CastStateValueToInt<QueryT, NativeT>(pname, value);
- case GL_INT_64_ANGLEX: return CastStateValueToInt<QueryT, NativeT>(pname, value);
- case GL_FLOAT: return static_cast<QueryT>(value);
- case GL_BOOL: return static_cast<QueryT>(value == static_cast<NativeT>(0) ? GL_FALSE : GL_TRUE);
- default: UNREACHABLE(); return 0;
+ case GL_INT:
+ return CastStateValueToInt<QueryT, NativeT>(pname, value);
+ case GL_INT_64_ANGLEX:
+ return CastStateValueToInt<QueryT, NativeT>(pname, value);
+ case GL_FLOAT:
+ return static_cast<QueryT>(value);
+ case GL_BOOL:
+ return static_cast<QueryT>(value == static_cast<NativeT>(0) ? GL_FALSE : GL_TRUE);
+ default:
+ UNREACHABLE();
+ return 0;
}
}
+} // anonymous namespace
+
+template <>
+GLenum GLTypeToGLenum<GLint>::value = GL_INT;
+template <>
+GLenum GLTypeToGLenum<GLuint>::value = GL_UNSIGNED_INT;
+template <>
+GLenum GLTypeToGLenum<GLboolean>::value = GL_BOOL;
+template <>
+GLenum GLTypeToGLenum<GLint64>::value = GL_INT_64_ANGLEX;
+template <>
+GLenum GLTypeToGLenum<GLfloat>::value = GL_FLOAT;
+
template <typename QueryT>
void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
unsigned int numParams, QueryT *outParams)
diff --git a/src/libANGLE/queryconversions.h b/src/libANGLE/queryconversions.h
index da7047f..e0fdbe1 100644
--- a/src/libANGLE/queryconversions.h
+++ b/src/libANGLE/queryconversions.h
@@ -6,8 +6,25 @@
// queryconversions.h: Declaration of state query cast conversions
+#ifndef LIBANGLE_QUERY_CONVERSIONS_H_
+#define LIBANGLE_QUERY_CONVERSIONS_H_
+
+#include "angle_gl.h"
+#include "common/angleutils.h"
+
namespace gl
{
+class Context;
+
+// Helper class for converting a GL type to a GLenum:
+// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap.
+// We restrict our use to CastStateValue, where it eliminates duplicate parameters.
+
+template <typename GLType>
+struct GLTypeToGLenum
+{
+ static GLenum value;
+};
// The GL state query API types are: bool, int, uint, float, int64
template <typename QueryT>
@@ -15,3 +32,5 @@
unsigned int numParams, QueryT *outParams);
}
+
+#endif // LIBANGLE_QUERY_CONVERSIONS_H_
diff --git a/src/libANGLE/renderer/ProgramImpl.cpp b/src/libANGLE/renderer/ProgramImpl.cpp
deleted file mode 100644
index 051ef16..0000000
--- a/src/libANGLE/renderer/ProgramImpl.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-//
-// Copyright (c) 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.
-//
-
-// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl.
-
-#include "libANGLE/renderer/ProgramImpl.h"
-
-#include "common/utilities.h"
-
-namespace rx
-{
-
-LinkResult::LinkResult(bool linkSuccess, const gl::Error &error)
- : linkSuccess(linkSuccess),
- error(error)
-{
-}
-
-ProgramImpl::ProgramImpl(const gl::Program::Data &data) : mData(data)
-{
-}
-
-ProgramImpl::~ProgramImpl()
-{
- // Ensure that reset was called by the inherited class during destruction
- ASSERT(mUniformIndex.size() == 0);
-}
-
-gl::LinkedUniform *ProgramImpl::getUniformByLocation(GLint location) const
-{
- ASSERT(location >= 0 && mUniformIndex.find(location) != mUniformIndex.end());
- return mUniforms[mUniformIndex.at(location).index];
-}
-
-gl::LinkedUniform *ProgramImpl::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;
-}
-
-gl::UniformBlock *ProgramImpl::getUniformBlockByIndex(GLuint blockIndex) const
-{
- ASSERT(blockIndex < mUniformBlocks.size());
- return mUniformBlocks[blockIndex];
-}
-
-GLint ProgramImpl::getUniformLocation(const std::string &name) const
-{
- size_t subscript = GL_INVALID_INDEX;
- std::string baseName = gl::ParseUniformName(name, &subscript);
-
- for (const auto &info : mUniformIndex)
- {
- GLuint location = info.first;
- const gl::VariableLocation &uniform = info.second;
-
- if (uniform.name == baseName)
- {
- const bool isArray = mUniforms[uniform.index]->isArray();
-
- if ((isArray && uniform.element == subscript) ||
- (subscript == GL_INVALID_INDEX))
- {
- return location;
- }
- }
- }
-
- return -1;
-}
-
-GLuint ProgramImpl::getUniformIndex(const std::string &name) const
-{
- size_t subscript = GL_INVALID_INDEX;
- std::string baseName = gl::ParseUniformName(name, &subscript);
-
- // The app is not allowed to specify array indices other than 0 for arrays of basic types
- if (subscript != 0 && subscript != GL_INVALID_INDEX)
- {
- return GL_INVALID_INDEX;
- }
-
- unsigned int numUniforms = static_cast<unsigned int>(mUniforms.size());
- for (unsigned int index = 0; index < numUniforms; index++)
- {
- if (mUniforms[index]->name == baseName)
- {
- if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
- {
- return index;
- }
- }
- }
-
- return GL_INVALID_INDEX;
-}
-
-GLuint ProgramImpl::getUniformBlockIndex(const std::string &name) const
-{
- size_t subscript = GL_INVALID_INDEX;
- std::string baseName = gl::ParseUniformName(name, &subscript);
-
- unsigned int numUniformBlocks = static_cast<unsigned int>(mUniformBlocks.size());
- for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
- {
- const gl::UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
- if (uniformBlock.name == baseName)
- {
- const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
- if (subscript == uniformBlock.elementIndex || arrayElementZero)
- {
- return blockIndex;
- }
- }
- }
-
- return GL_INVALID_INDEX;
-}
-
-void ProgramImpl::reset()
-{
- SafeDeleteContainer(mUniforms);
- mUniformIndex.clear();
- SafeDeleteContainer(mUniformBlocks);
-}
-
-}
diff --git a/src/libANGLE/renderer/ProgramImpl.h b/src/libANGLE/renderer/ProgramImpl.h
index 94da0c7..47fb9be 100644
--- a/src/libANGLE/renderer/ProgramImpl.h
+++ b/src/libANGLE/renderer/ProgramImpl.h
@@ -23,16 +23,17 @@
struct LinkResult
{
+ LinkResult(bool linkSuccess, const gl::Error &error) : linkSuccess(linkSuccess), error(error) {}
+
bool linkSuccess;
gl::Error error;
- LinkResult(bool linkSuccess, const gl::Error &error);
};
class ProgramImpl : angle::NonCopyable
{
public:
- ProgramImpl(const gl::Program::Data &data);
- virtual ~ProgramImpl();
+ ProgramImpl(const gl::Program::Data &data) : mData(data) {}
+ virtual ~ProgramImpl() {}
virtual int getShaderVersion() const = 0;
@@ -65,41 +66,16 @@
virtual void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0;
virtual void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0;
- virtual void getUniformfv(GLint location, GLfloat *params) = 0;
- virtual void getUniformiv(GLint location, GLint *params) = 0;
- virtual void getUniformuiv(GLint location, GLuint *params) = 0;
-
// TODO: The following functions are possibly only applicable to D3D backends. The should be carefully evaluated to
// determine if they can be removed from this interface.
virtual bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) = 0;
- const std::vector<gl::LinkedUniform*> &getUniforms() const { return mUniforms; }
- const std::map<GLuint, gl::VariableLocation> &getUniformIndices() const { return mUniformIndex; }
- const std::vector<gl::UniformBlock*> &getUniformBlocks() const { return mUniformBlocks; }
-
- std::vector<gl::LinkedUniform*> &getUniforms() { return mUniforms; }
- std::map<GLuint, gl::VariableLocation> &getUniformIndices() { return mUniformIndex; }
- std::vector<gl::UniformBlock*> &getUniformBlocks() { return mUniformBlocks; }
-
- gl::LinkedUniform *getUniformByLocation(GLint location) const;
- gl::LinkedUniform *getUniformByName(const std::string &name) const;
- gl::UniformBlock *getUniformBlockByIndex(GLuint blockIndex) const;
-
- GLint getUniformLocation(const std::string &name) const;
- GLuint getUniformIndex(const std::string &name) const;
- GLuint getUniformBlockIndex(const std::string &name) const;
-
- virtual void reset();
+ // Gather uniform block active uniform indices, and uniform block offset info.
+ virtual void gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
+ std::vector<gl::LinkedUniform> *uniforms) = 0;
protected:
const gl::Program::Data &mData;
-
- std::vector<gl::LinkedUniform*> mUniforms;
-
- // TODO: use a hash map
- std::map<GLuint, gl::VariableLocation> mUniformIndex;
-
- std::vector<gl::UniformBlock*> mUniformBlocks;
};
}
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index 13415a3..cfa7f8a 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -171,8 +171,92 @@
return packedVaryings;
}
+template <typename VarT>
+void GetUniformBlockInfo(const std::vector<VarT> &fields,
+ const std::string &prefix,
+ sh::BlockLayoutEncoder *encoder,
+ bool inRowMajorLayout,
+ std::map<std::string, sh::BlockMemberInfo> *blockInfoOut)
+{
+ for (const VarT &field : fields)
+ {
+ const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
+
+ if (field.isStruct())
+ {
+ bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
+
+ for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
+ {
+ encoder->enterAggregateType();
+
+ const std::string uniformElementName =
+ fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
+ GetUniformBlockInfo(field.fields, uniformElementName, encoder, rowMajorLayout,
+ blockInfoOut);
+
+ encoder->exitAggregateType();
+ }
+ }
+ else
+ {
+ bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout);
+ (*blockInfoOut)[fieldName] =
+ encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
+ }
+ }
+}
+
} // anonymous namespace
+D3DUniform::D3DUniform(GLenum typeIn,
+ const std::string &nameIn,
+ unsigned int arraySizeIn,
+ bool defaultBlock)
+ : type(typeIn),
+ name(nameIn),
+ arraySize(arraySizeIn),
+ data(nullptr),
+ dirty(true),
+ psRegisterIndex(GL_INVALID_INDEX),
+ vsRegisterIndex(GL_INVALID_INDEX),
+ registerCount(0),
+ registerElement(0)
+{
+ // We use data storage for default block uniforms to cache values that are sent to D3D during
+ // rendering
+ // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only)
+ if (defaultBlock)
+ {
+ size_t bytes = gl::VariableInternalSize(type) * elementCount();
+ data = new uint8_t[bytes];
+ memset(data, 0, bytes);
+
+ // TODO(jmadill): is this correct with non-square matrices?
+ registerCount = gl::VariableRowCount(type) * elementCount();
+ }
+}
+
+D3DUniform::~D3DUniform()
+{
+ SafeDeleteArray(data);
+}
+
+bool D3DUniform::isSampler() const
+{
+ return gl::IsSamplerType(type);
+}
+
+bool D3DUniform::isReferencedByVertexShader() const
+{
+ return vsRegisterIndex != GL_INVALID_INDEX;
+}
+
+bool D3DUniform::isReferencedByFragmentShader() const
+{
+ return psRegisterIndex != GL_INVALID_INDEX;
+}
+
ProgramD3D::VertexExecutable::VertexExecutable(const gl::InputLayout &inputLayout,
const Signature &signature,
ShaderExecutableD3D *shaderExecutable)
@@ -356,47 +440,45 @@
mDirtySamplerMapping = false;
// Retrieve sampler uniform values
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+ for (const D3DUniform *d3dUniform : mD3DUniforms)
{
- gl::LinkedUniform *targetUniform = mUniforms[uniformIndex];
+ if (!d3dUniform->dirty)
+ continue;
- if (targetUniform->dirty)
+ if (!d3dUniform->isSampler())
+ continue;
+
+ int count = d3dUniform->elementCount();
+ const GLint(*v)[4] = reinterpret_cast<const GLint(*)[4]>(d3dUniform->data);
+
+ if (d3dUniform->isReferencedByFragmentShader())
{
- if (gl::IsSamplerType(targetUniform->type))
+ unsigned int firstIndex = d3dUniform->psRegisterIndex;
+
+ for (int i = 0; i < count; i++)
{
- int count = targetUniform->elementCount();
- GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data);
+ unsigned int samplerIndex = firstIndex + i;
- if (targetUniform->isReferencedByFragmentShader())
+ if (samplerIndex < mSamplersPS.size())
{
- unsigned int firstIndex = targetUniform->psRegisterIndex;
-
- for (int i = 0; i < count; i++)
- {
- unsigned int samplerIndex = firstIndex + i;
-
- if (samplerIndex < mSamplersPS.size())
- {
- ASSERT(mSamplersPS[samplerIndex].active);
- mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
- }
- }
+ ASSERT(mSamplersPS[samplerIndex].active);
+ mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
}
+ }
+ }
- if (targetUniform->isReferencedByVertexShader())
+ if (d3dUniform->isReferencedByVertexShader())
+ {
+ unsigned int firstIndex = d3dUniform->vsRegisterIndex;
+
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int samplerIndex = firstIndex + i;
+
+ if (samplerIndex < mSamplersVS.size())
{
- unsigned int firstIndex = targetUniform->vsRegisterIndex;
-
- for (int i = 0; i < count; i++)
- {
- unsigned int samplerIndex = firstIndex + i;
-
- if (samplerIndex < mSamplersVS.size())
- {
- ASSERT(mSamplersVS[samplerIndex].active);
- mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
- }
- }
+ ASSERT(mSamplersVS[samplerIndex].active);
+ mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
}
}
}
@@ -505,6 +587,8 @@
LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
{
+ reset();
+
DeviceIdentifier binaryDeviceIdentifier = { 0 };
stream->readBytes(reinterpret_cast<unsigned char*>(&binaryDeviceIdentifier), sizeof(DeviceIdentifier));
@@ -559,79 +643,21 @@
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
- mUniforms.resize(uniformCount);
+ const auto &linkedUniforms = mData.getUniforms();
+ ASSERT(mD3DUniforms.empty());
for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++)
{
- 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>();
+ const gl::LinkedUniform &linkedUniform = linkedUniforms[uniformIndex];
- int offset = stream->readInt<int>();
- int arrayStride = stream->readInt<int>();
- int matrixStride = stream->readInt<int>();
- bool isRowMajorMatrix = stream->readBool();
+ D3DUniform *d3dUniform =
+ new D3DUniform(linkedUniform.type, linkedUniform.name, linkedUniform.arraySize,
+ linkedUniform.isInDefaultBlock());
+ stream->readInt(&d3dUniform->psRegisterIndex);
+ stream->readInt(&d3dUniform->vsRegisterIndex);
+ stream->readInt(&d3dUniform->registerCount);
+ stream->readInt(&d3dUniform->registerElement);
- const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
-
- gl::LinkedUniform *uniform = new gl::LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo);
-
- stream->readInt(&uniform->psRegisterIndex);
- stream->readInt(&uniform->vsRegisterIndex);
- stream->readInt(&uniform->registerCount);
- stream->readInt(&uniform->registerElement);
-
- mUniforms[uniformIndex] = uniform;
- }
-
- const unsigned int uniformIndexCount = stream->readInt<unsigned int>();
- if (stream->error())
- {
- infoLog << "Invalid program binary.";
- return LinkResult(false, gl::Error(GL_NO_ERROR));
- }
-
- for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++)
- {
- GLuint location;
- stream->readInt(&location);
-
- gl::VariableLocation variable;
- stream->readString(&variable.name);
- stream->readInt(&variable.element);
- stream->readInt(&variable.index);
-
- mUniformIndex[location] = variable;
- }
-
- unsigned int uniformBlockCount = stream->readInt<unsigned int>();
- if (stream->error())
- {
- infoLog << "Invalid program binary.";
- return LinkResult(false, gl::Error(GL_NO_ERROR));
- }
-
- mUniformBlocks.resize(uniformBlockCount);
- for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
- {
- std::string name = stream->readString();
- unsigned int elementIndex = stream->readInt<unsigned int>();
- unsigned int dataSize = stream->readInt<unsigned int>();
-
- gl::UniformBlock *uniformBlock = new gl::UniformBlock(name, elementIndex, dataSize);
-
- stream->readInt(&uniformBlock->psRegisterIndex);
- stream->readInt(&uniformBlock->vsRegisterIndex);
-
- unsigned int numMembers = stream->readInt<unsigned int>();
- uniformBlock->memberUniformIndexes.resize(numMembers);
- for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
- {
- stream->readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]);
- }
-
- mUniformBlocks[uniformBlockIndex] = uniformBlock;
+ mD3DUniforms.push_back(d3dUniform);
}
const unsigned int transformFeedbackVaryingCount = stream->readInt<unsigned int>();
@@ -805,59 +831,18 @@
stream->writeInt(mUsedVertexSamplerRange);
stream->writeInt(mUsedPixelSamplerRange);
- stream->writeInt(mUniforms.size());
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
+ stream->writeInt(mD3DUniforms.size());
+ for (size_t uniformIndex = 0; uniformIndex < mD3DUniforms.size(); ++uniformIndex)
{
- const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
+ const D3DUniform &uniform = *mD3DUniforms[uniformIndex];
- stream->writeInt(uniform.type);
- stream->writeInt(uniform.precision);
- stream->writeString(uniform.name);
- stream->writeInt(uniform.arraySize);
- stream->writeInt(uniform.blockIndex);
-
- stream->writeInt(uniform.blockInfo.offset);
- stream->writeInt(uniform.blockInfo.arrayStride);
- stream->writeInt(uniform.blockInfo.matrixStride);
- stream->writeInt(uniform.blockInfo.isRowMajorMatrix);
-
+ // Type, name and arraySize are redundant, so aren't stored in the binary.
stream->writeInt(uniform.psRegisterIndex);
stream->writeInt(uniform.vsRegisterIndex);
stream->writeInt(uniform.registerCount);
stream->writeInt(uniform.registerElement);
}
- stream->writeInt(mUniformIndex.size());
- for (const auto &uniform : mUniformIndex)
- {
- GLuint location = uniform.first;
- stream->writeInt(location);
-
- const gl::VariableLocation &variable = uniform.second;
- stream->writeString(variable.name);
- stream->writeInt(variable.element);
- stream->writeInt(variable.index);
- }
-
- stream->writeInt(mUniformBlocks.size());
- for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
- {
- const gl::UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
-
- stream->writeString(uniformBlock.name);
- stream->writeInt(uniformBlock.elementIndex);
- stream->writeInt(uniformBlock.dataSize);
-
- stream->writeInt(uniformBlock.memberUniformIndexes.size());
- for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
- {
- stream->writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]);
- }
-
- stream->writeInt(uniformBlock.psRegisterIndex);
- stream->writeInt(uniformBlock.vsRegisterIndex);
- }
-
stream->writeInt(mTransformFeedbackLinkedVaryings.size());
for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
{
@@ -1126,6 +1111,18 @@
LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog)
{
+ reset();
+
+ // TODO(jmadill): structures containing samplers
+ for (const gl::LinkedUniform &linkedUniform : mData.getUniforms())
+ {
+ if (linkedUniform.isSampler() && linkedUniform.isField())
+ {
+ infoLog << "Structures containing samplers not currently supported in D3D.";
+ return LinkResult(false, gl::Error(GL_NO_ERROR));
+ }
+ }
+
const gl::Shader *vertexShader = mData.getAttachedVertexShader();
const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
@@ -1175,12 +1172,7 @@
initSemanticIndex();
- if (!defineUniforms(infoLog, *data.caps))
- {
- return LinkResult(false, gl::Error(GL_NO_ERROR));
- }
-
- defineUniformBlocks(*data.caps);
+ assignUniformRegisters();
gatherTransformFeedbackVaryings(linkedVaryings);
@@ -1200,24 +1192,96 @@
return validateSamplers(infoLog, caps);
}
+void ProgramD3D::gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
+ std::vector<gl::LinkedUniform> *uniforms)
+{
+ const gl::Shader *vertexShader = mData.getAttachedVertexShader();
+
+ BlockInfoMap blockInfo;
+ std::map<std::string, size_t> blockDataSizes;
+
+ for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
+ {
+ if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
+
+ if (blockDataSizes.count(vertexBlock.name) > 0)
+ continue;
+
+ size_t dataSize = defineUniformBlock(vertexBlock, &blockInfo);
+ blockDataSizes[vertexBlock.name] = dataSize;
+ }
+
+ const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
+
+ for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
+ {
+ if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
+
+ if (blockDataSizes.count(fragmentBlock.name) > 0)
+ continue;
+
+ size_t dataSize = defineUniformBlock(fragmentBlock, &blockInfo);
+ blockDataSizes[fragmentBlock.name] = dataSize;
+ }
+
+ // Copy block info out to uniforms.
+ for (gl::LinkedUniform &linkedUniform : *uniforms)
+ {
+ const auto &infoEntry = blockInfo.find(linkedUniform.name);
+
+ if (infoEntry != blockInfo.end())
+ {
+ linkedUniform.blockInfo = infoEntry->second;
+ }
+ }
+
+ // Assign registers and update sizes.
+ const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(vertexShader);
+ const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(fragmentShader);
+
+ for (gl::UniformBlock &uniformBlock : *uniformBlocks)
+ {
+ unsigned int uniformBlockElement = uniformBlock.isArray ? uniformBlock.arrayElement : 0;
+
+ if (uniformBlock.vertexStaticUse)
+ {
+ unsigned int baseRegister =
+ vertexShaderD3D->getInterfaceBlockRegister(uniformBlock.name);
+ uniformBlock.vsRegisterIndex = baseRegister + uniformBlockElement;
+ }
+
+ if (uniformBlock.fragmentStaticUse)
+ {
+ unsigned int baseRegister =
+ fragmentShaderD3D->getInterfaceBlockRegister(uniformBlock.name);
+ uniformBlock.psRegisterIndex = baseRegister + uniformBlockElement;
+ }
+
+ ASSERT(blockDataSizes.count(uniformBlock.name) == 1);
+ uniformBlock.dataSize = static_cast<unsigned int>(blockDataSizes[uniformBlock.name]);
+ }
+}
+
void ProgramD3D::initializeUniformStorage()
{
// Compute total default block size
unsigned int vertexRegisters = 0;
unsigned int fragmentRegisters = 0;
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+ for (const D3DUniform *d3dUniform : mD3DUniforms)
{
- const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
-
- if (!gl::IsSamplerType(uniform.type))
+ if (!d3dUniform->isSampler())
{
- if (uniform.isReferencedByVertexShader())
+ if (d3dUniform->isReferencedByVertexShader())
{
- vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount);
+ vertexRegisters = std::max(vertexRegisters,
+ d3dUniform->vsRegisterIndex + d3dUniform->registerCount);
}
- if (uniform.isReferencedByFragmentShader())
+ if (d3dUniform->isReferencedByFragmentShader())
{
- fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount);
+ fragmentRegisters = std::max(
+ fragmentRegisters, d3dUniform->psRegisterIndex + d3dUniform->registerCount);
}
}
}
@@ -1230,15 +1294,15 @@
{
updateSamplerMapping();
- gl::Error error = mRenderer->applyUniforms(*this, mUniforms);
+ gl::Error error = mRenderer->applyUniforms(*this, mD3DUniforms);
if (error.isError())
{
return error;
}
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+ for (D3DUniform *d3dUniform : mD3DUniforms)
{
- mUniforms[uniformIndex]->dirty = false;
+ d3dUniform->dirty = false;
}
return gl::Error(GL_NO_ERROR);
@@ -1252,22 +1316,22 @@
const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
- for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
+ const auto &uniformBlocks = mData.getUniformBlocks();
+ for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlocks.size();
+ uniformBlockIndex++)
{
- gl::UniformBlock *uniformBlock = mUniformBlocks[uniformBlockIndex];
+ const gl::UniformBlock &uniformBlock = uniformBlocks[uniformBlockIndex];
GLuint blockBinding = mData.getUniformBlockBinding(uniformBlockIndex);
- ASSERT(uniformBlock);
-
// Unnecessary to apply an unreferenced standard or shared UBO
- if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader())
+ if (!uniformBlock.vertexStaticUse && !uniformBlock.fragmentStaticUse)
{
continue;
}
- if (uniformBlock->isReferencedByVertexShader())
+ if (uniformBlock.vertexStaticUse)
{
- unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
+ unsigned int registerIndex = uniformBlock.vsRegisterIndex - reservedBuffersInVS;
ASSERT(registerIndex < data.caps->maxVertexUniformBlocks);
if (mVertexUBOCache.size() <= registerIndex)
@@ -1279,9 +1343,9 @@
mVertexUBOCache[registerIndex] = blockBinding;
}
- if (uniformBlock->isReferencedByFragmentShader())
+ if (uniformBlock.fragmentStaticUse)
{
- unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
+ unsigned int registerIndex = uniformBlock.psRegisterIndex - reservedBuffersInFS;
ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks);
if (mFragmentUBOCache.size() <= registerIndex)
@@ -1297,31 +1361,11 @@
return mRenderer->setUniformBuffers(data, mVertexUBOCache, mFragmentUBOCache);
}
-void ProgramD3D::assignUniformBlockRegister(gl::UniformBlock *uniformBlock,
- GLenum shader,
- unsigned int registerIndex,
- const gl::Caps &caps)
-{
- // Validation done in the GL-level Program.
- if (shader == GL_VERTEX_SHADER)
- {
- uniformBlock->vsRegisterIndex = registerIndex;
- ASSERT(registerIndex < caps.maxVertexUniformBlocks);
- }
- else if (shader == GL_FRAGMENT_SHADER)
- {
- uniformBlock->psRegisterIndex = registerIndex;
- ASSERT(registerIndex < caps.maxFragmentUniformBlocks);
- }
- else UNREACHABLE();
-}
-
void ProgramD3D::dirtyAllUniforms()
{
- unsigned int numUniforms = static_cast<unsigned int>(mUniforms.size());
- for (unsigned int index = 0; index < numUniforms; index++)
+ for (D3DUniform *d3dUniform : mD3DUniforms)
{
- mUniforms[index]->dirty = true;
+ d3dUniform->dirty = true;
}
}
@@ -1430,93 +1474,68 @@
setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
}
-void ProgramD3D::getUniformfv(GLint location, GLfloat *params)
+void ProgramD3D::assignUniformRegisters()
{
- getUniformv(location, params, GL_FLOAT);
-}
+ const gl::Shader *vertexShader = mData.getAttachedVertexShader();
+ const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(vertexShader);
-void ProgramD3D::getUniformiv(GLint location, GLint *params)
-{
- getUniformv(location, params, GL_INT);
-}
+ for (const sh::Uniform &vertexUniform : vertexShader->getUniforms())
-void ProgramD3D::getUniformuiv(GLint location, GLuint *params)
-{
- getUniformv(location, params, GL_UNSIGNED_INT);
-}
-
-bool ProgramD3D::defineUniforms(gl::InfoLog &infoLog, const gl::Caps &caps)
-{
- const gl::Shader *vertexShader = mData.getAttachedVertexShader();
- const std::vector<sh::Uniform> &vertexUniforms = vertexShader->getUniforms();
- const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(vertexShader);
-
- if (vertexUniforms.size() > caps.maxVertexUniformVectors)
{
- infoLog << "Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS ("
- << caps.maxVertexUniformVectors << ").";
- return false;
- }
-
- for (const sh::Uniform &uniform : vertexUniforms)
- {
- if (uniform.staticUse)
+ if (vertexUniform.staticUse)
{
- unsigned int registerBase = uniform.isBuiltIn() ? GL_INVALID_INDEX :
- vertexShaderD3D->getUniformRegister(uniform.name);
- defineUniformBase(vertexShaderD3D, uniform, registerBase);
+ assignUniformRegistersBase(vertexShaderD3D, vertexUniform);
}
}
- const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
- const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader->getUniforms();
- const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(fragmentShader);
+ const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
+ const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(fragmentShader);
- if (fragmentUniforms.size() > caps.maxFragmentUniformVectors)
+ for (const sh::Uniform &fragmentUniform : fragmentShader->getUniforms())
{
- infoLog << "Vertex shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS ("
- << caps.maxFragmentUniformVectors << ").";
- return false;
- }
-
- for (const sh::Uniform &uniform : fragmentUniforms)
- {
- if (uniform.staticUse)
+ if (fragmentUniform.staticUse)
{
- unsigned int registerBase = uniform.isBuiltIn() ? GL_INVALID_INDEX :
- fragmentShaderD3D->getUniformRegister(uniform.name);
- defineUniformBase(fragmentShaderD3D, uniform, registerBase);
+ assignUniformRegistersBase(fragmentShaderD3D, fragmentUniform);
}
}
- // TODO(jmadill): move the validation part to gl::Program
- if (!indexUniforms(infoLog, caps))
- {
- return false;
- }
-
+ assignAllSamplerRegisters();
initializeUniformStorage();
-
- return true;
}
-void ProgramD3D::defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister)
+void ProgramD3D::assignUniformRegistersBase(const ShaderD3D *shader, const sh::Uniform &uniform)
{
- if (uniformRegister == GL_INVALID_INDEX)
+ if (uniform.isBuiltIn())
{
- defineUniform(shader, uniform, uniform.name, nullptr);
+ assignUniformRegisters(shader, uniform, uniform.name, nullptr);
return;
}
+ unsigned int startRegister = shader->getUniformRegister(uniform.name);
ShShaderOutput outputType = shader->getCompilerOutputType();
sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType));
- encoder.skipRegisters(uniformRegister);
+ encoder.skipRegisters(startRegister);
- defineUniform(shader, uniform, uniform.name, &encoder);
+ assignUniformRegisters(shader, uniform, uniform.name, &encoder);
}
-void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform,
- const std::string &fullName, sh::HLSLBlockEncoder *encoder)
+D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name)
+{
+ for (D3DUniform *d3dUniform : mD3DUniforms)
+ {
+ if (d3dUniform->name == name)
+ {
+ return d3dUniform;
+ }
+ }
+
+ return nullptr;
+}
+
+void ProgramD3D::assignUniformRegisters(const ShaderD3D *shader,
+ const sh::ShaderVariable &uniform,
+ const std::string &fullName,
+ sh::HLSLBlockEncoder *encoder)
{
if (uniform.isStruct())
{
@@ -1532,86 +1551,68 @@
const sh::ShaderVariable &field = uniform.fields[fieldIndex];
const std::string &fieldFullName = (fullName + elementString + "." + field.name);
- defineUniform(shader, field, fieldFullName, encoder);
+ assignUniformRegisters(shader, field, fieldFullName, encoder);
}
if (encoder)
encoder->exitAggregateType();
}
+ return;
}
- else // Not a struct
+
+ // Not a struct. Arrays are treated as aggregate types.
+ if (uniform.isArray() && encoder)
{
- // Arrays are treated as aggregate types
- if (uniform.isArray() && encoder)
- {
- encoder->enterAggregateType();
- }
+ encoder->enterAggregateType();
+ }
- gl::LinkedUniform *linkedUniform = getUniformByName(fullName);
+ // Advance the uniform offset, to track registers allocation for structs
+ sh::BlockMemberInfo blockInfo =
+ encoder ? encoder->encodeType(uniform.type, uniform.arraySize, false)
+ : sh::BlockMemberInfo::getDefaultBlockInfo();
- // Advance the uniform offset, to track registers allocation for structs
- sh::BlockMemberInfo blockInfo = encoder ?
- encoder->encodeType(uniform.type, uniform.arraySize, false) :
- sh::BlockMemberInfo::getDefaultBlockInfo();
+ D3DUniform *d3dUniform = getD3DUniformByName(fullName);
- if (!linkedUniform)
- {
- linkedUniform = new gl::LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
- -1, sh::BlockMemberInfo::getDefaultBlockInfo());
- ASSERT(linkedUniform);
+ if (!d3dUniform)
+ {
+ // We're building the list twice, make sure we use the same indexing. Special case
+ // built-ins.
+ ASSERT(fullName.compare(0, 3, "gl_") == 0 ||
+ mData.getUniformIndex(fullName) == static_cast<GLint>(mD3DUniforms.size()));
- if (encoder)
- linkedUniform->registerElement = static_cast<unsigned int>(
- sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo));
- mUniforms.push_back(linkedUniform);
- }
+ d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySize, true);
+ mD3DUniforms.push_back(d3dUniform);
if (encoder)
{
- if (shader->getShaderType() == GL_FRAGMENT_SHADER)
- {
- linkedUniform->psRegisterIndex =
- static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegister(blockInfo));
- }
- else if (shader->getShaderType() == GL_VERTEX_SHADER)
- {
- linkedUniform->vsRegisterIndex =
- static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegister(blockInfo));
- }
- else UNREACHABLE();
+ d3dUniform->registerElement =
+ static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo));
}
+ }
+
+ if (encoder)
+ {
+ unsigned int reg =
+ static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegister(blockInfo));
+ if (shader->getShaderType() == GL_FRAGMENT_SHADER)
+ {
+ d3dUniform->psRegisterIndex = reg;
+ }
+ else if (shader->getShaderType() == GL_VERTEX_SHADER)
+ {
+ d3dUniform->vsRegisterIndex = reg;
+ }
+ else
+ UNREACHABLE();
// Arrays are treated as aggregate types
- if (uniform.isArray() && encoder)
+ if (uniform.isArray())
{
encoder->exitAggregateType();
}
}
}
-void ProgramD3D::defineUniformBlocks(const gl::Caps &caps)
-{
- const gl::Shader *vertexShader = mData.getAttachedVertexShader();
-
- for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
- {
- if (vertexBlock.staticUse || vertexBlock.layout != sh::BLOCKLAYOUT_PACKED)
- {
- defineUniformBlock(*vertexShader, vertexBlock, caps);
- }
- }
-
- const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
-
- for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
- {
- if (fragmentBlock.staticUse || fragmentBlock.layout != sh::BLOCKLAYOUT_PACKED)
- {
- defineUniformBlock(*fragmentShader, fragmentBlock, caps);
- }
- }
-}
-
template <typename T>
static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag)
{
@@ -1623,22 +1624,22 @@
}
template <typename T>
-void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
+void ProgramD3D::setUniform(GLint location, GLsizei countIn, const T *v, GLenum targetUniformType)
{
const int components = gl::VariableComponentCount(targetUniformType);
const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType);
- gl::LinkedUniform *targetUniform = getUniformByLocation(location);
+ D3DUniform *targetUniform = getD3DUniformFromLocation(location);
- int elementCount = targetUniform->elementCount();
-
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+ unsigned int elementCount = targetUniform->elementCount();
+ unsigned int arrayElement = mData.getUniformLocations()[location].element;
+ unsigned int count = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn));
if (targetUniform->type == targetUniformType)
{
- T *target = reinterpret_cast<T*>(targetUniform->data) + mUniformIndex[location].element * 4;
+ T *target = reinterpret_cast<T *>(targetUniform->data) + arrayElement * 4;
- for (int i = 0; i < count; i++)
+ for (unsigned int i = 0; i < count; i++)
{
T *dest = target + (i * 4);
const T *source = v + (i * components);
@@ -1655,9 +1656,9 @@
}
else if (targetUniform->type == targetBoolType)
{
- GLint *boolParams = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
+ GLint *boolParams = reinterpret_cast<GLint *>(targetUniform->data) + arrayElement * 4;
- for (int i = 0; i < count; i++)
+ for (unsigned int i = 0; i < count; i++)
{
GLint *dest = boolParams + (i * 4);
const T *source = v + (i * components);
@@ -1672,15 +1673,15 @@
}
}
}
- else if (gl::IsSamplerType(targetUniform->type))
+ else if (targetUniform->isSampler())
{
ASSERT(targetUniformType == GL_INT);
- GLint *target = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
+ GLint *target = reinterpret_cast<GLint *>(targetUniform->data) + arrayElement * 4;
bool wasDirty = targetUniform->dirty;
- for (int i = 0; i < count; i++)
+ for (unsigned int i = 0; i < count; i++)
{
GLint *dest = target + (i * 4);
const GLint *source = reinterpret_cast<const GLint*>(v) + (i * components);
@@ -1768,17 +1769,23 @@
}
template <int cols, int rows>
-void ProgramD3D::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
+void ProgramD3D::setUniformMatrixfv(GLint location,
+ GLsizei countIn,
+ GLboolean transpose,
+ const GLfloat *value,
+ GLenum targetUniformType)
{
- gl::LinkedUniform *targetUniform = getUniformByLocation(location);
+ D3DUniform *targetUniform = getD3DUniformFromLocation(location);
- int elementCount = targetUniform->elementCount();
+ unsigned int elementCount = targetUniform->elementCount();
+ unsigned int arrayElement = mData.getUniformLocations()[location].element;
+ unsigned int count = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn));
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
const unsigned int targetMatrixStride = (4 * rows);
- GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
+ GLfloat *target =
+ (GLfloat *)(targetUniform->data + arrayElement * sizeof(GLfloat) * targetMatrixStride);
- for (int i = 0; i < count; i++)
+ for (unsigned int i = 0; i < count; i++)
{
// Internally store matrices as transposed versions to accomodate HLSL matrix indexing
if (transpose == GL_FALSE)
@@ -1794,186 +1801,63 @@
}
}
-template <typename T>
-void ProgramD3D::getUniformv(GLint location, T *params, GLenum uniformType)
+size_t ProgramD3D::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock,
+ BlockInfoMap *blockInfoOut)
{
- gl::LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED);
- if (gl::IsMatrixType(targetUniform->type))
+ // define member uniforms
+ sh::Std140BlockEncoder std140Encoder;
+ sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED);
+ sh::BlockLayoutEncoder *encoder = nullptr;
+
+ if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD)
{
- const int rows = gl::VariableRowCount(targetUniform->type);
- const int cols = gl::VariableColumnCount(targetUniform->type);
- transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows);
- }
- else if (uniformType == gl::VariableComponentType(targetUniform->type))
- {
- unsigned int size = gl::VariableComponentCount(targetUniform->type);
- memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
- size * sizeof(T));
+ encoder = &std140Encoder;
}
else
{
- unsigned int size = gl::VariableComponentCount(targetUniform->type);
- switch (gl::VariableComponentType(targetUniform->type))
- {
- case GL_BOOL:
- {
- GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
- }
- }
- break;
-
- case GL_FLOAT:
- {
- GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = static_cast<T>(roundf(floatParams[i]));
- }
- }
- break;
-
- case GL_INT:
- {
- GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = static_cast<T>(intParams[i]);
- }
- }
- break;
-
- case GL_UNSIGNED_INT:
- {
- GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = static_cast<T>(uintParams[i]);
- }
- }
- break;
-
- default: UNREACHABLE();
- }
+ encoder = &hlslEncoder;
}
+
+ GetUniformBlockInfo(interfaceBlock.fields, "", encoder, interfaceBlock.isRowMajorLayout,
+ blockInfoOut);
+
+ return encoder->getBlockSize();
}
-template <typename VarT>
-void ProgramD3D::defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
- sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
- bool inRowMajorLayout)
+void ProgramD3D::assignAllSamplerRegisters()
{
- for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
+ for (const D3DUniform *d3dUniform : mD3DUniforms)
{
- const VarT &field = fields[uniformIndex];
- const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
-
- if (field.isStruct())
+ if (d3dUniform->isSampler())
{
- bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
-
- 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, rowMajorLayout);
-
- encoder->exitAggregateType();
- }
- }
- else
- {
- bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout);
-
- sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
-
- gl::LinkedUniform *newUniform = new gl::LinkedUniform(field.type, field.precision, fieldName, field.arraySize,
- blockIndex, memberInfo);
-
- // add to uniform list, but not index, since uniform block uniforms have no location
- blockUniformIndexes->push_back(static_cast<GLenum>(mUniforms.size()));
- mUniforms.push_back(newUniform);
+ assignSamplerRegisters(d3dUniform);
}
}
}
-void ProgramD3D::defineUniformBlock(const gl::Shader &shader,
- const sh::InterfaceBlock &interfaceBlock,
- const gl::Caps &caps)
+void ProgramD3D::assignSamplerRegisters(const D3DUniform *d3dUniform)
{
- const ShaderD3D* shaderD3D = GetImplAs<ShaderD3D>(&shader);
+ ASSERT(d3dUniform->isSampler());
+ ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX ||
+ d3dUniform->psRegisterIndex != GL_INVALID_INDEX);
- // create uniform block entries if they do not exist
- if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
+ if (d3dUniform->vsRegisterIndex != GL_INVALID_INDEX)
{
- std::vector<unsigned int> blockUniformIndexes;
- const unsigned int blockIndex = static_cast<unsigned int>(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, interfaceBlock.isRowMajorLayout);
-
- unsigned int dataSize = static_cast<unsigned int>(encoder->getBlockSize());
-
- // create all the uniform blocks
- if (interfaceBlock.arraySize > 0)
- {
- for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
- {
- gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize);
- newUniformBlock->memberUniformIndexes = blockUniformIndexes;
- mUniformBlocks.push_back(newUniformBlock);
- }
- }
- else
- {
- gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize);
- newUniformBlock->memberUniformIndexes = blockUniformIndexes;
- mUniformBlocks.push_back(newUniformBlock);
- }
+ AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
+ mSamplersVS, &mUsedVertexSamplerRange);
}
- if (interfaceBlock.staticUse)
+ if (d3dUniform->psRegisterIndex != GL_INVALID_INDEX)
{
- // 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 = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name);
-
- for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
- {
- gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
- ASSERT(uniformBlock->name == interfaceBlock.name);
-
- assignUniformBlockRegister(uniformBlock, shader.getType(),
- interfaceBlockRegister + uniformBlockElement, caps);
- }
+ AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
+ mSamplersPS, &mUsedPixelSamplerRange);
}
}
-bool ProgramD3D::assignSamplers(unsigned int startSamplerIndex,
+// static
+void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex,
GLenum samplerType,
unsigned int samplerCount,
std::vector<Sampler> &outSamplers,
@@ -1983,103 +1867,18 @@
do
{
- if (samplerIndex < outSamplers.size())
- {
- Sampler& sampler = outSamplers[samplerIndex];
- sampler.active = true;
- sampler.textureType = GetTextureType(samplerType);
- sampler.logicalTextureUnit = 0;
- *outUsedRange = std::max(samplerIndex + 1, *outUsedRange);
- }
- else
- {
- return false;
- }
-
+ ASSERT(samplerIndex < outSamplers.size());
+ Sampler *sampler = &outSamplers[samplerIndex];
+ sampler->active = true;
+ sampler->textureType = GetTextureType(samplerType);
+ sampler->logicalTextureUnit = 0;
+ *outUsedRange = std::max(samplerIndex + 1, *outUsedRange);
samplerIndex++;
} while (samplerIndex < startSamplerIndex + samplerCount);
-
- return true;
-}
-
-bool ProgramD3D::indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps)
-{
- ASSERT(gl::IsSamplerType(uniform.type));
- ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX);
-
- if (uniform.vsRegisterIndex != GL_INVALID_INDEX)
- {
- if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS,
- &mUsedVertexSamplerRange))
- {
- infoLog << "Vertex shader sampler count exceeds the maximum vertex texture units ("
- << mSamplersVS.size() << ").";
- return false;
- }
-
- unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() + caps.maxVertexUniformVectors;
- if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors)
- {
- infoLog << "Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS ("
- << caps.maxVertexUniformVectors << ").";
- return false;
- }
- }
-
- if (uniform.psRegisterIndex != GL_INVALID_INDEX)
- {
- if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS,
- &mUsedPixelSamplerRange))
- {
- infoLog << "Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
- << mSamplersPS.size() << ").";
- return false;
- }
-
- unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() + caps.maxFragmentUniformVectors;
- if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors)
- {
- infoLog << "Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS ("
- << caps.maxFragmentUniformVectors << ").";
- return false;
- }
- }
-
- return true;
-}
-
-bool ProgramD3D::indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps)
-{
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
- {
- const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
-
- if (gl::IsSamplerType(uniform.type))
- {
- if (!indexSamplerUniform(uniform, infoLog, caps))
- {
- return false;
- }
- }
-
- for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
- {
- if (!uniform.isBuiltIn())
- {
- // Assign in-order uniform locations
- mUniformIndex[static_cast<GLuint>(mUniformIndex.size())] = gl::VariableLocation(
- uniform.name, arrayIndex, static_cast<unsigned int>(uniformIndex));
- }
- }
- }
-
- return true;
}
void ProgramD3D::reset()
{
- ProgramImpl::reset();
-
SafeDeleteContainer(mVertexExecutables);
SafeDeleteContainer(mPixelExecutables);
SafeDelete(mGeometryExecutable);
@@ -2094,6 +1893,8 @@
mPixelShaderKey.clear();
mUsesPointSize = false;
+ SafeDeleteContainer(mD3DUniforms);
+
SafeDelete(mVertexUniformStorage);
SafeDelete(mFragmentUniformStorage);
@@ -2203,4 +2004,9 @@
}
}
}
+
+D3DUniform *ProgramD3D::getD3DUniformFromLocation(GLint location)
+{
+ return mD3DUniforms[mData.getUniformLocations()[location].index];
+}
}
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h
index 6efc654..5e86516 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -20,13 +20,6 @@
#include "libANGLE/renderer/d3d/DynamicHLSL.h"
#include "libANGLE/renderer/d3d/WorkaroundsD3D.h"
-namespace gl
-{
-struct LinkedUniform;
-struct VariableLocation;
-struct VertexFormat;
-}
-
namespace rx
{
class RendererD3D;
@@ -39,6 +32,43 @@
#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL1
#endif
+// Helper struct representing a single shader uniform
+struct D3DUniform
+{
+ D3DUniform(GLenum typeIn,
+ const std::string &nameIn,
+ unsigned int arraySizeIn,
+ bool defaultBlock);
+ ~D3DUniform();
+
+ bool isSampler() const;
+ unsigned int elementCount() const { return std::max(1u, arraySize); }
+ bool isReferencedByVertexShader() const;
+ bool isReferencedByFragmentShader() const;
+
+ // Duplicated from the GL layer
+ GLenum type;
+ std::string name;
+ unsigned int arraySize;
+
+ // Pointer to a system copy of the data.
+ // TODO(jmadill): remove this in favor of gl::LinkedUniform::data().
+ uint8_t *data;
+
+ // Has the data been updated since the last sync?
+ bool dirty;
+
+ // Register information.
+ unsigned int vsRegisterIndex;
+ unsigned int psRegisterIndex;
+ unsigned int registerCount;
+
+ // Register "elements" are used for uniform structs in ES3, to appropriately identify single
+ // uniforms
+ // inside aggregate types, which are packed according C-like structure rules.
+ unsigned int registerElement;
+};
+
class ProgramD3D : public ProgramImpl
{
public:
@@ -73,13 +103,12 @@
LinkResult link(const gl::Data &data, gl::InfoLog &infoLog) override;
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
+ void gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
+ std::vector<gl::LinkedUniform> *uniforms) override;
+
void initializeUniformStorage();
gl::Error applyUniforms();
gl::Error applyUniformBuffers(const gl::Data &data);
- void assignUniformBlockRegister(gl::UniformBlock *uniformBlock,
- GLenum shader,
- unsigned int registerIndex,
- const gl::Caps &caps);
void dirtyAllUniforms();
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
@@ -104,15 +133,9 @@
void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
- void getUniformfv(GLint location, GLfloat *params);
- void getUniformiv(GLint location, GLint *params);
- void getUniformuiv(GLint location, GLuint *params);
-
const UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage; }
const UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage; }
- void reset();
-
unsigned int getSerial() const;
void sortAttributesByLayout(const std::vector<TranslatedAttribute> &unsortedAttributes,
@@ -175,19 +198,24 @@
GLenum textureType;
};
- bool defineUniforms(gl::InfoLog &infoLog, const gl::Caps &caps);
- void defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister);
- void defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform, const std::string &fullName,
- sh::HLSLBlockEncoder *encoder);
- bool indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps);
- bool indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps);
- static bool assignSamplers(unsigned int startSamplerIndex, GLenum samplerType, unsigned int samplerCount,
- std::vector<Sampler> &outSamplers, GLuint *outUsedRange);
+ typedef std::map<std::string, sh::BlockMemberInfo> BlockInfoMap;
- void defineUniformBlocks(const gl::Caps &caps);
- void defineUniformBlock(const gl::Shader &shader,
- const sh::InterfaceBlock &interfaceBlock,
- const gl::Caps &caps);
+ void assignUniformRegisters();
+ void assignUniformRegistersBase(const ShaderD3D *shader, const sh::Uniform &uniform);
+ void assignUniformRegisters(const ShaderD3D *shader,
+ const sh::ShaderVariable &uniform,
+ const std::string &fullName,
+ sh::HLSLBlockEncoder *encoder);
+ void assignAllSamplerRegisters();
+ void assignSamplerRegisters(const D3DUniform *d3dUniform);
+
+ static void AssignSamplers(unsigned int startSamplerIndex,
+ GLenum samplerType,
+ unsigned int samplerCount,
+ std::vector<Sampler> &outSamplers,
+ GLuint *outUsedRange);
+
+ size_t defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, BlockInfoMap *blockInfoOut);
template <typename T>
void setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType);
@@ -195,23 +223,19 @@
template <int cols, int rows>
void setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType);
- template <typename T>
- void getUniformv(GLint location, T *params, GLenum uniformType);
-
- template <typename VarT>
- void defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
- sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
- bool inRowMajorLayout);
-
LinkResult compileProgramExecutables(gl::InfoLog &infoLog,
int registers,
const std::vector<PackedVarying> &packedVaryings);
void gatherTransformFeedbackVaryings(const std::vector<gl::LinkedVarying> &varyings);
+ D3DUniform *getD3DUniformByName(const std::string &name);
+ D3DUniform *getD3DUniformFromLocation(GLint location);
void initSemanticIndex();
void initAttributesByLayout();
+ void reset();
+
RendererD3D *mRenderer;
DynamicHLSL *mDynamicHLSL;
@@ -259,6 +283,7 @@
gl::InputLayout mCachedInputLayout;
std::vector<gl::LinkedVarying> mTransformFeedbackLinkedVaryings;
+ std::vector<D3DUniform *> mD3DUniforms;
static unsigned int issueSerial();
static unsigned int mCurrentSerial;
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.h b/src/libANGLE/renderer/d3d/RendererD3D.h
index f2629dd..87bbadd 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.h
+++ b/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -37,8 +37,10 @@
namespace rx
{
+struct D3DUniform;
class ImageD3D;
class IndexBuffer;
+class ProgramD3D;
class RenderTargetD3D;
class ShaderExecutableD3D;
class SwapChainD3D;
@@ -157,7 +159,8 @@
const gl::Framebuffer *framebuffer,
bool rasterizerDiscard,
bool transformFeedbackActive) = 0;
- virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray) = 0;
+ virtual gl::Error applyUniforms(const ProgramD3D &programD3D,
+ const std::vector<D3DUniform *> &uniformArray) = 0;
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize) = 0;
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceIndexInfo) = 0;
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo) = 0;
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 33901aa..7eb834c 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -2095,7 +2095,8 @@
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray)
+gl::Error Renderer11::applyUniforms(const ProgramD3D &programD3D,
+ const std::vector<D3DUniform *> &uniformArray)
{
unsigned int totalRegisterCountVS = 0;
unsigned int totalRegisterCountPS = 0;
@@ -2103,26 +2104,25 @@
bool vertexUniformsDirty = false;
bool pixelUniformsDirty = false;
- for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++)
+ for (const D3DUniform *uniform : uniformArray)
{
- const gl::LinkedUniform &uniform = *uniformArray[uniformIndex];
-
- if (uniform.isReferencedByVertexShader() && !uniform.isSampler())
+ if (uniform->isReferencedByVertexShader() && !uniform->isSampler())
{
- totalRegisterCountVS += uniform.registerCount;
- vertexUniformsDirty = (vertexUniformsDirty || uniform.dirty);
+ totalRegisterCountVS += uniform->registerCount;
+ vertexUniformsDirty = (vertexUniformsDirty || uniform->dirty);
}
- if (uniform.isReferencedByFragmentShader() && !uniform.isSampler())
+ if (uniform->isReferencedByFragmentShader() && !uniform->isSampler())
{
- totalRegisterCountPS += uniform.registerCount;
- pixelUniformsDirty = (pixelUniformsDirty || uniform.dirty);
+ totalRegisterCountPS += uniform->registerCount;
+ pixelUniformsDirty = (pixelUniformsDirty || uniform->dirty);
}
}
- const ProgramD3D *programD3D = GetAs<ProgramD3D>(&program);
- const UniformStorage11 *vertexUniformStorage = GetAs<UniformStorage11>(&programD3D->getVertexUniformStorage());
- const UniformStorage11 *fragmentUniformStorage = GetAs<UniformStorage11>(&programD3D->getFragmentUniformStorage());
+ const UniformStorage11 *vertexUniformStorage =
+ GetAs<UniformStorage11>(&programD3D.getVertexUniformStorage());
+ const UniformStorage11 *fragmentUniformStorage =
+ GetAs<UniformStorage11>(&programD3D.getFragmentUniformStorage());
ASSERT(vertexUniformStorage);
ASSERT(fragmentUniformStorage);
@@ -2150,26 +2150,26 @@
mapPS = (float(*)[4])map.pData;
}
- for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++)
+ for (const D3DUniform *uniform : uniformArray)
{
- gl::LinkedUniform *uniform = uniformArray[uniformIndex];
+ if (uniform->isSampler())
+ continue;
- if (!uniform->isSampler())
+ unsigned int componentCount = (4 - uniform->registerElement);
+
+ // we assume that uniforms from structs are arranged in struct order in our uniforms list.
+ // otherwise we would overwrite previously written regions of memory.
+
+ if (uniform->isReferencedByVertexShader() && mapVS)
{
- unsigned int componentCount = (4 - uniform->registerElement);
+ memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data,
+ uniform->registerCount * sizeof(float) * componentCount);
+ }
- // we assume that uniforms from structs are arranged in struct order in our uniforms list. otherwise we would
- // overwrite previously written regions of memory.
-
- if (uniform->isReferencedByVertexShader() && mapVS)
- {
- memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount);
- }
-
- if (uniform->isReferencedByFragmentShader() && mapPS)
- {
- memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount);
- }
+ if (uniform->isReferencedByFragmentShader() && mapPS)
+ {
+ memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data,
+ uniform->registerCount * sizeof(float) * componentCount);
}
}
@@ -2255,7 +2255,7 @@
}
// GSSetConstantBuffers triggers device removal on 9_3, so we should only call it if necessary
- if (programD3D->usesGeometryShader())
+ if (programD3D.usesGeometryShader())
{
// needed for the point sprite geometry shader
if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS)
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index 6260add..2bce423 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -137,7 +137,8 @@
bool rasterizerDiscard,
bool transformFeedbackActive) override;
- virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
+ gl::Error applyUniforms(const ProgramD3D &programD3D,
+ const std::vector<D3DUniform *> &uniformArray) override;
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceIndexInfo);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo);
void applyTransformFeedbackBuffers(const gl::State &state) override;
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
index 8c59545..61dec0a 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -1910,46 +1910,45 @@
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer9::applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray)
+gl::Error Renderer9::applyUniforms(const ProgramD3D &programD3D,
+ const std::vector<D3DUniform *> &uniformArray)
{
- for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++)
+ for (const D3DUniform *targetUniform : uniformArray)
{
- gl::LinkedUniform *targetUniform = uniformArray[uniformIndex];
+ if (!targetUniform->dirty)
+ continue;
- if (targetUniform->dirty)
+ GLfloat *f = (GLfloat *)targetUniform->data;
+ GLint *i = (GLint *)targetUniform->data;
+
+ switch (targetUniform->type)
{
- GLfloat *f = (GLfloat*)targetUniform->data;
- GLint *i = (GLint*)targetUniform->data;
-
- switch (targetUniform->type)
- {
- case GL_SAMPLER_2D:
- case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
break;
- case GL_BOOL:
- case GL_BOOL_VEC2:
- case GL_BOOL_VEC3:
- case GL_BOOL_VEC4:
+ case GL_BOOL:
+ case GL_BOOL_VEC2:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
applyUniformnbv(targetUniform, i);
break;
- case GL_FLOAT:
- case GL_FLOAT_VEC2:
- case GL_FLOAT_VEC3:
- case GL_FLOAT_VEC4:
- case GL_FLOAT_MAT2:
- case GL_FLOAT_MAT3:
- case GL_FLOAT_MAT4:
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT4:
applyUniformnfv(targetUniform, f);
break;
- case GL_INT:
- case GL_INT_VEC2:
- case GL_INT_VEC3:
- case GL_INT_VEC4:
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
applyUniformniv(targetUniform, i);
break;
- default:
+ default:
UNREACHABLE();
- }
}
}
@@ -1964,7 +1963,7 @@
return gl::Error(GL_NO_ERROR);
}
-void Renderer9::applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v)
+void Renderer9::applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v)
{
if (targetUniform->isReferencedByFragmentShader())
{
@@ -1977,7 +1976,7 @@
}
}
-void Renderer9::applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v)
+void Renderer9::applyUniformniv(const D3DUniform *targetUniform, const GLint *v)
{
ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
@@ -1993,7 +1992,7 @@
applyUniformnfv(targetUniform, (GLfloat*)vector);
}
-void Renderer9::applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v)
+void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v)
{
ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
index 2cd84fc..95d9a52 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
@@ -32,10 +32,12 @@
{
class Blit9;
class IndexDataManager;
+class ProgramD3D;
class StreamingIndexBufferInterface;
class StaticIndexBufferInterface;
class VertexDataManager;
struct ClearParameters;
+struct D3DUniform;
struct TranslatedAttribute;
enum D3D9InitError
@@ -111,7 +113,8 @@
const gl::Framebuffer *framebuffer,
bool rasterizerDiscard,
bool transformFeedbackActive) override;
- virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
+ gl::Error applyUniforms(const ProgramD3D &programD3D,
+ const std::vector<D3DUniform *> &uniformArray) override;
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize);
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceInfo);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo);
@@ -258,9 +261,9 @@
void release();
- void applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v);
- void applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v);
- void applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v);
+ void applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v);
+ void applyUniformniv(const D3DUniform *targetUniform, const GLint *v);
+ void applyUniformnbv(const D3DUniform *targetUniform, const GLint *v);
gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
gl::Error drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
diff --git a/src/libANGLE/renderer/gl/ProgramGL.cpp b/src/libANGLE/renderer/gl/ProgramGL.cpp
index 3a70ae9..bae8389 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.cpp
+++ b/src/libANGLE/renderer/gl/ProgramGL.cpp
@@ -115,68 +115,41 @@
}
// Query the uniform information
- // TODO: A lot of this logic should be done at the gl::Program level
- GLint activeUniformMaxLength = 0;
- mFunctions->getProgramiv(mProgramID, GL_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformMaxLength);
-
- std::vector<GLchar> uniformNameBuffer(activeUniformMaxLength);
-
- GLint uniformCount = 0;
- mFunctions->getProgramiv(mProgramID, GL_ACTIVE_UNIFORMS, &uniformCount);
- for (GLint i = 0; i < uniformCount; i++)
+ ASSERT(mUniformRealLocationMap.empty());
+ const auto &uniforms = mData.getUniforms();
+ for (const gl::VariableLocation &entry : mData.getUniformLocations())
{
- GLsizei uniformNameLength = 0;
- GLint uniformSize = 0;
- GLenum uniformType = GL_NONE;
- mFunctions->getActiveUniform(mProgramID, i, static_cast<GLsizei>(uniformNameBuffer.size()),
- &uniformNameLength, &uniformSize, &uniformType,
- &uniformNameBuffer[0]);
-
- size_t subscript = 0;
- std::string uniformName = gl::ParseUniformName(std::string(&uniformNameBuffer[0], uniformNameLength), &subscript);
-
- bool isArray = uniformSize > 1 || subscript != GL_INVALID_INDEX;
-
- for (size_t arrayIndex = 0; arrayIndex < static_cast<size_t>(uniformSize); arrayIndex++)
+ // From the spec:
+ // "Locations for sequential array indices are not required to be sequential."
+ const gl::LinkedUniform &uniform = uniforms[entry.index];
+ std::stringstream fullNameStr;
+ fullNameStr << uniform.name;
+ if (uniform.isArray())
{
- std::string locationName = uniformName;
- if (isArray)
- {
- locationName += "[" + Str(static_cast<int>(arrayIndex)) + "]";
- }
-
- GLint location = mFunctions->getUniformLocation(mProgramID, locationName.c_str());
- if (location >= 0)
- {
- mUniformIndex[location] =
- gl::VariableLocation(uniformName, static_cast<unsigned int>(arrayIndex),
- static_cast<unsigned int>(mUniforms.size()));
-
- // If the uniform is a sampler, track it in the sampler bindings array
- if (gl::IsSamplerType(uniformType))
- {
- SamplerLocation samplerLoc;
- samplerLoc.samplerIndex = mSamplerBindings.size();
- samplerLoc.arrayIndex = arrayIndex;
- mSamplerUniformMap[location] = samplerLoc;
- }
- }
+ fullNameStr << "[" << entry.element << "]";
}
+ const std::string &fullName = fullNameStr.str();
- // ANGLE uses 0 to identify an non-array uniform.
- unsigned int arraySize = isArray ? static_cast<unsigned int>(uniformSize) : 0;
+ GLint realLocation = mFunctions->getUniformLocation(mProgramID, fullName.c_str());
+ mUniformRealLocationMap.push_back(realLocation);
+ }
- // TODO: determine uniform precision
- mUniforms.push_back(new gl::LinkedUniform(uniformType, GL_NONE, uniformName, arraySize, -1, sh::BlockMemberInfo::getDefaultBlockInfo()));
+ mUniformIndexToSamplerIndex.resize(mData.getUniforms().size(), GL_INVALID_INDEX);
+
+ for (size_t uniformId = 0; uniformId < uniforms.size(); ++uniformId)
+ {
+ const gl::LinkedUniform &linkedUniform = uniforms[uniformId];
+
+ if (!linkedUniform.isSampler() || !linkedUniform.staticUse)
+ continue;
+
+ mUniformIndexToSamplerIndex[uniformId] = mSamplerBindings.size();
// If uniform is a sampler type, insert it into the mSamplerBindings array
- if (gl::IsSamplerType(uniformType))
- {
- SamplerBindingGL samplerBinding;
- samplerBinding.textureType = gl::SamplerTypeToTextureType(uniformType);
- samplerBinding.boundTextureUnits.resize(uniformSize, 0);
- mSamplerBindings.push_back(samplerBinding);
- }
+ SamplerBindingGL samplerBinding;
+ samplerBinding.textureType = gl::SamplerTypeToTextureType(linkedUniform.type);
+ samplerBinding.boundTextureUnits.resize(linkedUniform.elementCount(), 0);
+ mSamplerBindings.push_back(samplerBinding);
}
return LinkResult(true, gl::Error(GL_NO_ERROR));
@@ -191,59 +164,61 @@
void ProgramGL::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform1fv(location, count, v);
+ mFunctions->uniform1fv(uniLoc(location), count, v);
}
void ProgramGL::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform2fv(location, count, v);
+ mFunctions->uniform2fv(uniLoc(location), count, v);
}
void ProgramGL::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform3fv(location, count, v);
+ mFunctions->uniform3fv(uniLoc(location), count, v);
}
void ProgramGL::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform4fv(location, count, v);
+ mFunctions->uniform4fv(uniLoc(location), count, v);
}
void ProgramGL::setUniform1iv(GLint location, GLsizei count, const GLint *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform1iv(location, count, v);
+ mFunctions->uniform1iv(uniLoc(location), count, v);
- auto iter = mSamplerUniformMap.find(location);
- if (iter != mSamplerUniformMap.end())
+ const gl::VariableLocation &locationEntry = mData.getUniformLocations()[location];
+
+ size_t samplerIndex = mUniformIndexToSamplerIndex[locationEntry.index];
+ if (samplerIndex != GL_INVALID_INDEX)
{
- const SamplerLocation &samplerLoc = iter->second;
- std::vector<GLuint> &boundTextureUnits = mSamplerBindings[samplerLoc.samplerIndex].boundTextureUnits;
+ std::vector<GLuint> &boundTextureUnits = mSamplerBindings[samplerIndex].boundTextureUnits;
- size_t copyCount = std::max<size_t>(count, boundTextureUnits.size() - samplerLoc.arrayIndex);
- std::copy(v, v + copyCount, boundTextureUnits.begin() + samplerLoc.arrayIndex);
+ size_t copyCount =
+ std::max<size_t>(count, boundTextureUnits.size() - locationEntry.element);
+ std::copy(v, v + copyCount, boundTextureUnits.begin() + locationEntry.element);
}
}
void ProgramGL::setUniform2iv(GLint location, GLsizei count, const GLint *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform2iv(location, count, v);
+ mFunctions->uniform2iv(uniLoc(location), count, v);
}
void ProgramGL::setUniform3iv(GLint location, GLsizei count, const GLint *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform3iv(location, count, v);
+ mFunctions->uniform3iv(uniLoc(location), count, v);
}
void ProgramGL::setUniform4iv(GLint location, GLsizei count, const GLint *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform4iv(location, count, v);
+ mFunctions->uniform4iv(uniLoc(location), count, v);
}
void ProgramGL::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
@@ -255,88 +230,73 @@
void ProgramGL::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform2uiv(location, count, v);
+ mFunctions->uniform2uiv(uniLoc(location), count, v);
}
void ProgramGL::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform3uiv(location, count, v);
+ mFunctions->uniform3uiv(uniLoc(location), count, v);
}
void ProgramGL::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniform4uiv(location, count, v);
+ mFunctions->uniform4uiv(uniLoc(location), count, v);
}
void ProgramGL::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniformMatrix2fv(location, count, transpose, value);
+ mFunctions->uniformMatrix2fv(uniLoc(location), count, transpose, value);
}
void ProgramGL::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniformMatrix3fv(location, count, transpose, value);
+ mFunctions->uniformMatrix3fv(uniLoc(location), count, transpose, value);
}
void ProgramGL::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniformMatrix4fv(location, count, transpose, value);
+ mFunctions->uniformMatrix4fv(uniLoc(location), count, transpose, value);
}
void ProgramGL::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniformMatrix2x3fv(location, count, transpose, value);
+ mFunctions->uniformMatrix2x3fv(uniLoc(location), count, transpose, value);
}
void ProgramGL::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniformMatrix3x2fv(location, count, transpose, value);
+ mFunctions->uniformMatrix3x2fv(uniLoc(location), count, transpose, value);
}
void ProgramGL::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniformMatrix2x4fv(location, count, transpose, value);
+ mFunctions->uniformMatrix2x4fv(uniLoc(location), count, transpose, value);
}
void ProgramGL::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniformMatrix4x2fv(location, count, transpose, value);
+ mFunctions->uniformMatrix4x2fv(uniLoc(location), count, transpose, value);
}
void ProgramGL::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniformMatrix3x4fv(location, count, transpose, value);
+ mFunctions->uniformMatrix3x4fv(uniLoc(location), count, transpose, value);
}
void ProgramGL::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
{
mStateManager->useProgram(mProgramID);
- mFunctions->uniformMatrix4x3fv(location, count, transpose, value);
-}
-
-void ProgramGL::getUniformfv(GLint location, GLfloat *params)
-{
- mFunctions->getUniformfv(mProgramID, location, params);
-}
-
-void ProgramGL::getUniformiv(GLint location, GLint *params)
-{
- mFunctions->getUniformiv(mProgramID, location, params);
-}
-
-void ProgramGL::getUniformuiv(GLint location, GLuint *params)
-{
- mFunctions->getUniformuiv(mProgramID, location, params);
+ mFunctions->uniformMatrix4x3fv(uniLoc(location), count, transpose, value);
}
bool ProgramGL::validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps)
@@ -347,10 +307,9 @@
void ProgramGL::reset()
{
- ProgramImpl::reset();
-
- mSamplerUniformMap.clear();
+ mUniformRealLocationMap.clear();
mSamplerBindings.clear();
+ mUniformIndexToSamplerIndex.clear();
}
GLuint ProgramGL::getProgramID() const
@@ -363,4 +322,9 @@
return mSamplerBindings;
}
+void ProgramGL::gatherUniformBlockInfo(std::vector<gl::UniformBlock> * /*uniformBlocks*/,
+ std::vector<gl::LinkedUniform> * /*uniforms*/)
+{
+ // TODO(jmadill): Gather uniform block layout info, and data sizes.
+}
}
diff --git a/src/libANGLE/renderer/gl/ProgramGL.h b/src/libANGLE/renderer/gl/ProgramGL.h
index e83d7da..9cc0a14 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.h
+++ b/src/libANGLE/renderer/gl/ProgramGL.h
@@ -62,32 +62,31 @@
void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override;
void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override;
- void getUniformfv(GLint location, GLfloat *params) override;
- void getUniformiv(GLint location, GLint *params) override;
- void getUniformuiv(GLint location, GLuint *params) override;
-
bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) override;
- void reset() override;
+ void gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
+ std::vector<gl::LinkedUniform> *uniforms) override;
GLuint getProgramID() const;
const std::vector<SamplerBindingGL> &getAppliedSamplerUniforms() const;
private:
+ void reset();
+
+ // Helper function, makes it simpler to type.
+ GLint uniLoc(GLint glLocation) const { return mUniformRealLocationMap[glLocation]; }
+
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
- // A map from uniform location to index of mSamplerBindings and array index of the uniform
- struct SamplerLocation
- {
- size_t samplerIndex;
- size_t arrayIndex;
- };
- std::map<GLint, SamplerLocation> mSamplerUniformMap;
+ std::vector<GLint> mUniformRealLocationMap;
// An array of the samplers that are used by the program
std::vector<SamplerBindingGL> mSamplerBindings;
+ // A map from a mData.getUniforms() index to a mSamplerBindings index.
+ std::vector<size_t> mUniformIndexToSamplerIndex;
+
GLuint mProgramID;
};
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index d8e1dd7..db00caf 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -1145,8 +1145,11 @@
return true;
}
-static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
- GLint location, GLsizei count, LinkedUniform **uniformOut)
+static bool ValidateUniformCommonBase(gl::Context *context,
+ GLenum targetUniformType,
+ GLint location,
+ GLsizei count,
+ const LinkedUniform **uniformOut)
{
if (count < 0)
{
@@ -1173,16 +1176,16 @@
return false;
}
- LinkedUniform *uniform = program->getUniformByLocation(location);
+ const LinkedUniform &uniform = program->getUniformByLocation(location);
// attempting to write an array to a non-array uniform is an INVALID_OPERATION
- if (!uniform->isArray() && count > 1)
+ if (!uniform.isArray() && count > 1)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
- *uniformOut = uniform;
+ *uniformOut = &uniform;
return true;
}
@@ -1195,7 +1198,7 @@
return false;
}
- LinkedUniform *uniform = NULL;
+ const LinkedUniform *uniform = nullptr;
if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
{
return false;
@@ -1230,7 +1233,7 @@
return false;
}
- LinkedUniform *uniform = NULL;
+ const LinkedUniform *uniform = nullptr;
if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
{
return false;
@@ -1526,7 +1529,7 @@
// Uniform buffer validation
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
{
- const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
+ const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
@@ -1545,7 +1548,7 @@
uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
}
- if (uniformBufferSize < uniformBlock->dataSize)
+ if (uniformBufferSize < uniformBlock.dataSize)
{
// undefined behaviour
context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
@@ -1944,8 +1947,8 @@
ASSERT(programObject);
// sized queries -- ensure the provided buffer is large enough
- LinkedUniform *uniform = programObject->getUniformByLocation(location);
- size_t requiredBytes = VariableExternalSize(uniform->type);
+ const LinkedUniform &uniform = programObject->getUniformByLocation(location);
+ size_t requiredBytes = VariableExternalSize(uniform.type);
if (static_cast<size_t>(bufSize) < requiredBytes)
{
context->recordError(Error(GL_INVALID_OPERATION));
diff --git a/src/libGLESv2.gypi b/src/libGLESv2.gypi
index b27fabc..634e3e4 100644
--- a/src/libGLESv2.gypi
+++ b/src/libGLESv2.gypi
@@ -140,7 +140,6 @@
'libANGLE/renderer/FramebufferImpl.h',
'libANGLE/renderer/ImageImpl.h',
'libANGLE/renderer/ImplFactory.h',
- 'libANGLE/renderer/ProgramImpl.cpp',
'libANGLE/renderer/ProgramImpl.h',
'libANGLE/renderer/QueryImpl.h',
'libANGLE/renderer/RenderbufferImpl.h',
diff --git a/src/tests/deqp_support/deqp_gles2_test_expectations.txt b/src/tests/deqp_support/deqp_gles2_test_expectations.txt
index e478f98..4c3bb61 100644
--- a/src/tests/deqp_support/deqp_gles2_test_expectations.txt
+++ b/src/tests/deqp_support/deqp_gles2_test_expectations.txt
@@ -144,9 +144,12 @@
1031 WIN : dEQP-GLES2.functional.uniform_api.random.41 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.51 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.54 = FAIL
+1031 WIN : dEQP-GLES2.functional.uniform_api.random.61 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.72 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.79 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.82 = FAIL
+1031 WIN : dEQP-GLES2.functional.uniform_api.random.87 = FAIL
+1031 WIN : dEQP-GLES2.functional.uniform_api.random.93 = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.basic_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.struct_in_array.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.array_in_struct.sampler2D_samplerCube_* = FAIL
diff --git a/src/tests/deqp_support/deqp_gles3_test_expectations.txt b/src/tests/deqp_support/deqp_gles3_test_expectations.txt
index 727fc1f..5e80236 100644
--- a/src/tests/deqp_support/deqp_gles3_test_expectations.txt
+++ b/src/tests/deqp_support/deqp_gles3_test_expectations.txt
@@ -982,11 +982,14 @@
1098 WIN : dEQP-GLES3.functional.uniform_api.random.3 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.6 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.8 = FAIL
+1098 WIN : dEQP-GLES3.functional.uniform_api.random.17 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.20 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.21 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.29 = FAIL
+1098 WIN : dEQP-GLES3.functional.uniform_api.random.54 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.81 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.83 = FAIL
+1098 WIN : dEQP-GLES3.functional.uniform_api.random.87 = FAIL
1099 WIN : dEQP-GLES3.functional.attribute_location.bind_aliasing.cond_float = FAIL
1099 WIN : dEQP-GLES3.functional.attribute_location.bind_aliasing.max_cond_float = FAIL
1099 WIN : dEQP-GLES3.functional.attribute_location.bind_aliasing.cond_vec2 = FAIL
diff --git a/src/tests/gl_tests/UniformBufferTest.cpp b/src/tests/gl_tests/UniformBufferTest.cpp
index dcb1750..d25c5ef 100644
--- a/src/tests/gl_tests/UniformBufferTest.cpp
+++ b/src/tests/gl_tests/UniformBufferTest.cpp
@@ -313,6 +313,51 @@
}
}
+// Tests that active uniforms have the right names.
+TEST_P(UniformBufferTest, ActiveUniformNames)
+{
+ const std::string &vertexShaderSource =
+ "#version 300 es\n"
+ "in vec2 position;\n"
+ "out float v;\n"
+ "uniform blockName {\n"
+ " float f;\n"
+ "} instanceName;\n"
+ "void main() {\n"
+ " v = instanceName.f;\n"
+ " gl_Position = vec4(position, 0, 1);\n"
+ "}";
+
+ const std::string &fragmentShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "in float v;\n"
+ "out vec4 color;\n"
+ "void main() {\n"
+ " color = vec4(v, 0, 0, 1);\n"
+ "}";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ ASSERT_NE(0u, program);
+
+ GLint activeUniforms;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniforms);
+
+ ASSERT_EQ(1, activeUniforms);
+
+ GLint maxLength, size;
+ GLenum type;
+ GLsizei length;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+ std::vector<GLchar> strBuffer(maxLength + 1, 0);
+ glGetActiveUniform(program, 0, maxLength, &length, &size, &type, &strBuffer[0]);
+
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_EQ(GL_FLOAT, type);
+ EXPECT_EQ("blockName.f", std::string(&strBuffer[0]));
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(UniformBufferTest, ES3_D3D11(), ES3_D3D11_FL11_1(), ES3_D3D11_FL11_1_REFERENCE());
diff --git a/src/tests/gl_tests/UniformTest.cpp b/src/tests/gl_tests/UniformTest.cpp
index 581f5ff..6f34218 100644
--- a/src/tests/gl_tests/UniformTest.cpp
+++ b/src/tests/gl_tests/UniformTest.cpp
@@ -16,11 +16,7 @@
class UniformTest : public ANGLETest
{
protected:
- UniformTest()
- : mProgram(0),
- mUniformFLocation(-1),
- mUniformILocation(-1),
- mUniformBLocation(-1)
+ UniformTest() : mProgram(0), mUniformFLocation(-1), mUniformILocation(-1), mUniformBLocation(-1)
{
setWindowWidth(128);
setWindowHeight(128);
@@ -40,7 +36,12 @@
"uniform float uniF;\n"
"uniform int uniI;\n"
"uniform bool uniB;\n"
- "void main() { gl_FragColor = vec4(uniF + float(uniI) + (uniB ? 1.0 : 0.0)); }";
+ "uniform bool uniBArr[4];\n"
+ "void main() {\n"
+ " gl_FragColor = vec4(uniF + float(uniI));\n"
+ " gl_FragColor += vec4(uniB ? 1.0 : 0.0);\n"
+ " gl_FragColor += vec4(uniBArr[0] ? 1.0 : 0.0);\n"
+ "}";
mProgram = CompileProgram(vertexShader, fragShader);
ASSERT_NE(mProgram, 0u);
@@ -169,13 +170,6 @@
// Test that float to integer GetUniform rounds values correctly.
TEST_P(UniformTest, FloatUniformStateQuery)
{
- // TODO(jmadill): remove this suppression once we support ANGLE-only state queries.
- if (isAMD() && (GetParam() == ES2_OPENGL() || GetParam() == ES3_OPENGL()))
- {
- std::cout << "Skipping test due to a driver bug on AMD." << std::endl;
- return;
- }
-
std::vector<GLfloat> inValues;
std::vector<GLfloat> expectedFValues;
std::vector<GLint> expectedIValues;
@@ -214,7 +208,7 @@
for (size_t index = 0; index < inValues.size(); ++index)
{
- GLfloat inValue = inValues[index];
+ GLfloat inValue = inValues[index];
GLfloat expectedValue = expectedFValues[index];
glUniform1f(mUniformFLocation, inValue);
@@ -226,7 +220,7 @@
for (size_t index = 0; index < inValues.size(); ++index)
{
- GLfloat inValue = inValues[index];
+ GLfloat inValue = inValues[index];
GLint expectedValue = expectedIValues[index];
glUniform1f(mUniformFLocation, inValue);
@@ -240,13 +234,6 @@
// Test that integer to float GetUniform rounds values correctly.
TEST_P(UniformTest, IntUniformStateQuery)
{
- // TODO(jmadill): remove this suppression once we support ANGLE-only state queries.
- if ((isAMD() || isIntel()) && (GetParam() == ES2_OPENGL() || GetParam() == ES3_OPENGL()))
- {
- std::cout << "Skipping test due to a driver bug." << std::endl;
- return;
- }
-
std::vector<GLint> inValues;
std::vector<GLint> expectedIValues;
std::vector<GLfloat> expectedFValues;
@@ -274,7 +261,7 @@
for (size_t index = 0; index < inValues.size(); ++index)
{
- GLint inValue = inValues[index];
+ GLint inValue = inValues[index];
GLint expectedValue = expectedIValues[index];
glUniform1i(mUniformILocation, inValue);
@@ -286,7 +273,7 @@
for (size_t index = 0; index < inValues.size(); ++index)
{
- GLint inValue = inValues[index];
+ GLint inValue = inValues[index];
GLfloat expectedValue = expectedFValues[index];
glUniform1i(mUniformILocation, inValue);
@@ -301,9 +288,10 @@
TEST_P(UniformTest, BooleanUniformStateQuery)
{
glUseProgram(mProgram);
- GLint intValue = 0;
+ GLint intValue = 0;
GLfloat floatValue = 0.0f;
+ // Calling Uniform1i
glUniform1i(mUniformBLocation, GL_FALSE);
glGetUniformiv(mProgram, mUniformBLocation, &intValue);
@@ -320,6 +308,67 @@
glGetUniformfv(mProgram, mUniformBLocation, &floatValue);
EXPECT_EQ(1.0f, floatValue);
+ // Calling Uniform1f
+ glUniform1f(mUniformBLocation, 0.0f);
+
+ glGetUniformiv(mProgram, mUniformBLocation, &intValue);
+ EXPECT_EQ(0, intValue);
+
+ glGetUniformfv(mProgram, mUniformBLocation, &floatValue);
+ EXPECT_EQ(0.0f, floatValue);
+
+ glUniform1f(mUniformBLocation, 1.0f);
+
+ glGetUniformiv(mProgram, mUniformBLocation, &intValue);
+ EXPECT_EQ(1, intValue);
+
+ glGetUniformfv(mProgram, mUniformBLocation, &floatValue);
+ EXPECT_EQ(1.0f, floatValue);
+
+ ASSERT_GL_NO_ERROR();
+}
+
+// Test queries for arrays of boolean uniforms.
+TEST_P(UniformTest, BooleanArrayUniformStateQuery)
+{
+ glUseProgram(mProgram);
+ GLint intValues[4] = {0};
+ GLfloat floatValues[4] = {0.0f};
+ GLint boolValuesi[4] = {0, 1, 0, 1};
+ GLfloat boolValuesf[4] = {0, 1, 0, 1};
+
+ GLint location = glGetUniformLocation(mProgram, "uniBArr");
+
+ // Calling Uniform1iv
+ glUniform1iv(location, 4, boolValuesi);
+
+ glGetUniformiv(mProgram, location, intValues);
+ for (unsigned int idx = 0; idx < 4; ++idx)
+ {
+ EXPECT_EQ(boolValuesi[idx], intValues[idx]);
+ }
+
+ glGetUniformfv(mProgram, location, floatValues);
+ for (unsigned int idx = 0; idx < 4; ++idx)
+ {
+ EXPECT_EQ(boolValuesf[idx], floatValues[idx]);
+ }
+
+ // Calling Uniform1fv
+ glUniform1fv(location, 4, boolValuesf);
+
+ glGetUniformiv(mProgram, location, intValues);
+ for (unsigned int idx = 0; idx < 4; ++idx)
+ {
+ EXPECT_EQ(boolValuesi[idx], intValues[idx]);
+ }
+
+ glGetUniformfv(mProgram, location, floatValues);
+ for (unsigned int idx = 0; idx < 4; ++idx)
+ {
+ EXPECT_EQ(boolValuesf[idx], floatValues[idx]);
+ }
+
ASSERT_GL_NO_ERROR();
}