Commit d255123c by Olli Etuaho Committed by Commit Bot

Store shader interface variables as per query spec

GLES 3.1 section 7.3.1.1 specifies how active variable entries should be generated and how active variables are named. The specs for program interface variable queries are built on top of this section. ANGLE has already followed this spec for the most part for generating variable lists in ProgramState, but now we also follow the naming spec for arrays and include [0] at the end of the stored name. This will make implementing arrays of arrays more straightforward. Most logic for variable queries will just keep working as is when arrays of arrays are added instead of needing more complex logic for handling array indexing. BUG=angleproject:2125 TEST=angle_end2end_tests Change-Id: I3acd14253153e10bc312114b0303065da2efb506 Reviewed-on: https://chromium-review.googlesource.com/739826Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent c67323a9
...@@ -158,6 +158,11 @@ Optional<std::vector<wchar_t>> WidenString(size_t length, const char *cString) ...@@ -158,6 +158,11 @@ Optional<std::vector<wchar_t>> WidenString(size_t length, const char *cString)
return Optional<std::vector<wchar_t>>(wcstring); return Optional<std::vector<wchar_t>>(wcstring);
} }
bool BeginsWith(const std::string &str, const std::string &prefix)
{
return strncmp(str.c_str(), prefix.c_str(), prefix.length()) == 0;
}
bool BeginsWith(const std::string &str, const char *prefix) bool BeginsWith(const std::string &str, const char *prefix)
{ {
return strncmp(str.c_str(), prefix, strlen(prefix)) == 0; return strncmp(str.c_str(), prefix, strlen(prefix)) == 0;
...@@ -168,6 +173,11 @@ bool BeginsWith(const char *str, const char *prefix) ...@@ -168,6 +173,11 @@ bool BeginsWith(const char *str, const char *prefix)
return strncmp(str, prefix, strlen(prefix)) == 0; return strncmp(str, prefix, strlen(prefix)) == 0;
} }
bool BeginsWith(const std::string &str, const std::string &prefix, const size_t prefixLength)
{
return strncmp(str.c_str(), prefix.c_str(), prefixLength) == 0;
}
bool EndsWith(const std::string &str, const char *suffix) bool EndsWith(const std::string &str, const char *suffix)
{ {
const auto len = strlen(suffix); const auto len = strlen(suffix);
......
...@@ -49,6 +49,10 @@ bool ReadFileToString(const std::string &path, std::string *stringOut); ...@@ -49,6 +49,10 @@ bool ReadFileToString(const std::string &path, std::string *stringOut);
Optional<std::vector<wchar_t>> WidenString(size_t length, const char *cString); Optional<std::vector<wchar_t>> WidenString(size_t length, const char *cString);
// Check if the string str begins with the given prefix. // Check if the string str begins with the given prefix.
// The comparison is case sensitive.
bool BeginsWith(const std::string &str, const std::string &prefix);
// Check if the string str begins with the given prefix.
// Prefix may not be NULL and needs to be NULL terminated. // Prefix may not be NULL and needs to be NULL terminated.
// The comparison is case sensitive. // The comparison is case sensitive.
bool BeginsWith(const std::string &str, const char *prefix); bool BeginsWith(const std::string &str, const char *prefix);
...@@ -58,6 +62,11 @@ bool BeginsWith(const std::string &str, const char *prefix); ...@@ -58,6 +62,11 @@ bool BeginsWith(const std::string &str, const char *prefix);
// The comparison is case sensitive. // The comparison is case sensitive.
bool BeginsWith(const char *str, const char *prefix); bool BeginsWith(const char *str, const char *prefix);
// Check if the string str begins with the first prefixLength characters of the given prefix.
// The length of the prefix string should be greater than or equal to prefixLength.
// The comparison is case sensitive.
bool BeginsWith(const std::string &str, const std::string &prefix, const size_t prefixLength);
// Check if the string str ends with the given suffix. // Check if the string str ends with the given suffix.
// Suffix may not be NUL and needs to be NULL terminated. // Suffix may not be NUL and needs to be NULL terminated.
// The comparison is case sensitive. // The comparison is case sensitive.
......
...@@ -138,18 +138,73 @@ TEST(StringUtilsTest, HexStringToUIntBasic) ...@@ -138,18 +138,73 @@ TEST(StringUtilsTest, HexStringToUIntBasic)
// Note: ReadFileToString is harder to test // Note: ReadFileToString is harder to test
class BeginsWithTest : public testing::Test
{
public:
BeginsWithTest() : mMode(TestMode::CHAR_ARRAY) {}
enum class TestMode
{
CHAR_ARRAY,
STRING_AND_CHAR_ARRAY,
STRING
};
void setMode(TestMode mode) { mMode = mode; }
bool runBeginsWith(const char *str, const char *prefix)
{
if (mMode == TestMode::CHAR_ARRAY)
{
return BeginsWith(str, prefix);
}
if (mMode == TestMode::STRING_AND_CHAR_ARRAY)
{
return BeginsWith(std::string(str), prefix);
}
return BeginsWith(std::string(str), std::string(prefix));
}
void runTest()
{
ASSERT_FALSE(runBeginsWith("foo", "bar"));
ASSERT_FALSE(runBeginsWith("", "foo"));
ASSERT_FALSE(runBeginsWith("foo", "foobar"));
ASSERT_TRUE(runBeginsWith("foobar", "foo"));
ASSERT_TRUE(runBeginsWith("foobar", ""));
ASSERT_TRUE(runBeginsWith("foo", "foo"));
ASSERT_TRUE(runBeginsWith("", ""));
}
private:
TestMode mMode;
};
// Test that BeginsWith works correctly for const char * arguments.
TEST_F(BeginsWithTest, CharArrays)
{
setMode(TestMode::CHAR_ARRAY);
runTest();
}
TEST(StringUtilsTest, BeginsEndsWith) // Test that BeginsWith works correctly for std::string and const char * arguments.
TEST_F(BeginsWithTest, StringAndCharArray)
{ {
ASSERT_FALSE(BeginsWith("foo", "bar")); setMode(TestMode::STRING_AND_CHAR_ARRAY);
ASSERT_FALSE(BeginsWith("", "foo")); runTest();
ASSERT_FALSE(BeginsWith("foo", "foobar")); }
ASSERT_TRUE(BeginsWith("foobar", "foo")); // Test that BeginsWith works correctly for std::string arguments.
ASSERT_TRUE(BeginsWith("foobar", "")); TEST_F(BeginsWithTest, Strings)
ASSERT_TRUE(BeginsWith("foo", "foo")); {
ASSERT_TRUE(BeginsWith("", "")); setMode(TestMode::STRING);
runTest();
}
// Test that EndsWith works correctly.
TEST(EndsWithTest, EndsWith)
{
ASSERT_FALSE(EndsWith("foo", "bar")); ASSERT_FALSE(EndsWith("foo", "bar"));
ASSERT_FALSE(EndsWith("", "bar")); ASSERT_FALSE(EndsWith("", "bar"));
ASSERT_FALSE(EndsWith("foo", "foobar")); ASSERT_FALSE(EndsWith("foo", "foobar"));
...@@ -160,4 +215,4 @@ TEST(StringUtilsTest, BeginsEndsWith) ...@@ -160,4 +215,4 @@ TEST(StringUtilsTest, BeginsEndsWith)
ASSERT_TRUE(EndsWith("", "")); ASSERT_TRUE(EndsWith("", ""));
} }
} } // anonymous namespace
\ No newline at end of file
...@@ -770,19 +770,33 @@ std::string ParseResourceName(const std::string &name, std::vector<unsigned int> ...@@ -770,19 +770,33 @@ std::string ParseResourceName(const std::string &name, std::vector<unsigned int>
return name.substr(0, baseNameLength); return name.substr(0, baseNameLength);
} }
unsigned int ParseAndStripArrayIndex(std::string *name) unsigned int ParseArrayIndex(const std::string &name, size_t *nameLengthWithoutArrayIndexOut)
{ {
ASSERT(nameLengthWithoutArrayIndexOut != nullptr);
unsigned int subscript = GL_INVALID_INDEX; unsigned int subscript = GL_INVALID_INDEX;
// Strip any trailing array operator and retrieve the subscript // Strip any trailing array operator and retrieve the subscript
size_t open = name->find_last_of('['); size_t open = name.find_last_of('[');
size_t close = name->find_last_of(']'); if (open != std::string::npos && name.back() == ']')
if (open != std::string::npos && close == name->length() - 1)
{ {
subscript = atoi(name->c_str() + open + 1); bool indexIsValidDecimalNumber = true;
name->erase(open); for (size_t i = open + 1; i < name.length() - 1u; ++i)
{
if (!isdigit(name[i]))
{
indexIsValidDecimalNumber = false;
break;
}
}
if (indexIsValidDecimalNumber)
{
subscript = atoi(name.c_str() + open + 1);
*nameLengthWithoutArrayIndexOut = open;
return subscript;
}
} }
*nameLengthWithoutArrayIndexOut = name.length();
return subscript; return subscript;
} }
......
...@@ -70,7 +70,10 @@ GLuint GetPrimitiveRestartIndex(GLenum indexType); ...@@ -70,7 +70,10 @@ GLuint GetPrimitiveRestartIndex(GLenum indexType);
bool IsTriangleMode(GLenum drawMode); bool IsTriangleMode(GLenum drawMode);
bool IsIntegerFormat(GLenum unsizedFormat); bool IsIntegerFormat(GLenum unsizedFormat);
unsigned int ParseAndStripArrayIndex(std::string *name); // Return the array index at the end of name, and write the length of name before the final array
// index into nameLengthWithoutArrayIndexOut. In case name doesn't include an array index, return
// GL_INVALID_INDEX and write the length of the original string.
unsigned int ParseArrayIndex(const std::string &name, size_t *nameLengthWithoutArrayIndexOut);
struct UniformTypeInfo final : angle::NonCopyable struct UniformTypeInfo final : angle::NonCopyable
{ {
......
...@@ -75,4 +75,97 @@ TEST(ParseResourceName, TrailingWhitespace) ...@@ -75,4 +75,97 @@ TEST(ParseResourceName, TrailingWhitespace)
EXPECT_TRUE(indices.empty()); EXPECT_TRUE(indices.empty());
} }
// Parse a string without any index.
TEST(ParseArrayIndex, NoArrayIndex)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(GL_INVALID_INDEX, gl::ParseArrayIndex("foo", &nameLengthWithoutArrayIndex));
EXPECT_EQ(3u, nameLengthWithoutArrayIndex);
}
// Parse an empty string for an array index.
TEST(ParseArrayIndex, EmptyString)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(GL_INVALID_INDEX, gl::ParseArrayIndex("", &nameLengthWithoutArrayIndex));
EXPECT_EQ(0u, nameLengthWithoutArrayIndex);
}
// A valid array index is parsed correctly from the end of the string.
TEST(ParseArrayIndex, ArrayIndex)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(123u, gl::ParseArrayIndex("foo[123]", &nameLengthWithoutArrayIndex));
EXPECT_EQ(3u, nameLengthWithoutArrayIndex);
}
// An array index from the middle of the string is not parsed.
TEST(ParseArrayIndex, ArrayIndexInMiddle)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(GL_INVALID_INDEX, gl::ParseArrayIndex("foo[123].bar", &nameLengthWithoutArrayIndex));
EXPECT_EQ(12u, nameLengthWithoutArrayIndex);
}
// Trailing whitespace in the parsed string is taken into account.
TEST(ParseArrayIndex, TrailingWhitespace)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(GL_INVALID_INDEX, gl::ParseArrayIndex("foo[123] ", &nameLengthWithoutArrayIndex));
EXPECT_EQ(9u, nameLengthWithoutArrayIndex);
}
// Only the last index is parsed.
TEST(ParseArrayIndex, MultipleArrayIndices)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(34u, gl::ParseArrayIndex("foo[12][34]", &nameLengthWithoutArrayIndex));
EXPECT_EQ(7u, nameLengthWithoutArrayIndex);
} }
// GetProgramResourceLocation spec in GLES 3.1 November 2016 page 87 mentions "decimal" integer.
// So an integer in hexadecimal format should not parse as an array index.
TEST(ParseArrayIndex, HexArrayIndex)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(GL_INVALID_INDEX, gl::ParseArrayIndex("foo[0xff]", &nameLengthWithoutArrayIndex));
EXPECT_EQ(9u, nameLengthWithoutArrayIndex);
}
// GetProgramResourceLocation spec in GLES 3.1 November 2016 page 87 mentions that the array
// index should not contain a leading plus sign.
TEST(ParseArrayIndex, ArrayIndexLeadingPlus)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(GL_INVALID_INDEX, gl::ParseArrayIndex("foo[+1]", &nameLengthWithoutArrayIndex));
EXPECT_EQ(7u, nameLengthWithoutArrayIndex);
}
// GetProgramResourceLocation spec in GLES 3.1 November 2016 page 87 says that index should not
// contain whitespace. Test leading whitespace.
TEST(ParseArrayIndex, ArrayIndexLeadingWhiteSpace)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(GL_INVALID_INDEX, gl::ParseArrayIndex("foo[ 0]", &nameLengthWithoutArrayIndex));
EXPECT_EQ(7u, nameLengthWithoutArrayIndex);
}
// GetProgramResourceLocation spec in GLES 3.1 November 2016 page 87 says that index should not
// contain whitespace. Test trailing whitespace.
TEST(ParseArrayIndex, ArrayIndexTrailingWhiteSpace)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(GL_INVALID_INDEX, gl::ParseArrayIndex("foo[0 ]", &nameLengthWithoutArrayIndex));
EXPECT_EQ(7u, nameLengthWithoutArrayIndex);
}
// GetProgramResourceLocation spec in GLES 3.1 November 2016 page 87 says that index should only
// contain an integer.
TEST(ParseArrayIndex, ArrayIndexBogus)
{
size_t nameLengthWithoutArrayIndex;
EXPECT_EQ(GL_INVALID_INDEX, gl::ParseArrayIndex("foo[0bogus]", &nameLengthWithoutArrayIndex));
EXPECT_EQ(11u, nameLengthWithoutArrayIndex);
}
} // anonymous namespace
...@@ -316,15 +316,15 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -316,15 +316,15 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
} }
unsigned int outputVarCount = stream.readInt<unsigned int>(); unsigned int outputVarCount = stream.readInt<unsigned int>();
ASSERT(state->mOutputLocations.empty());
for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex) for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
{ {
int locationIndex = stream.readInt<int>();
VariableLocation locationData; VariableLocation locationData;
stream.readIntVector<unsigned int>(&locationData.arrayIndices); stream.readIntVector<unsigned int>(&locationData.arrayIndices);
stream.readInt(&locationData.index); stream.readInt(&locationData.index);
stream.readInt(&locationData.flattenedArrayOffset); stream.readInt(&locationData.flattenedArrayOffset);
stream.readBool(&locationData.ignored); stream.readBool(&locationData.ignored);
state->mOutputLocations[locationIndex] = locationData; state->mOutputLocations.push_back(locationData);
} }
unsigned int outputTypeCount = stream.readInt<unsigned int>(); unsigned int outputTypeCount = stream.readInt<unsigned int>();
...@@ -481,13 +481,12 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -481,13 +481,12 @@ void MemoryProgramCache::Serialize(const Context *context,
} }
stream.writeInt(state.getOutputLocations().size()); stream.writeInt(state.getOutputLocations().size());
for (const auto &outputPair : state.getOutputLocations()) for (const auto &outputVar : state.getOutputLocations())
{ {
stream.writeInt(outputPair.first); stream.writeIntVector(outputVar.arrayIndices);
stream.writeIntVector(outputPair.second.arrayIndices); stream.writeIntOrNegOne(outputVar.index);
stream.writeIntOrNegOne(outputPair.second.index); stream.writeInt(outputVar.flattenedArrayOffset);
stream.writeInt(outputPair.second.flattenedArrayOffset); stream.writeInt(outputVar.ignored);
stream.writeInt(outputPair.second.ignored);
} }
stream.writeInt(state.mOutputVariableTypes.size()); stream.writeInt(state.mOutputVariableTypes.size());
......
...@@ -275,7 +275,7 @@ class ProgramState final : angle::NonCopyable ...@@ -275,7 +275,7 @@ class ProgramState final : angle::NonCopyable
unsigned int getMaxActiveAttribLocation() const { return mMaxActiveAttribLocation; } unsigned int getMaxActiveAttribLocation() const { return mMaxActiveAttribLocation; }
DrawBufferMask getActiveOutputVariables() const { return mActiveOutputVariables; } DrawBufferMask getActiveOutputVariables() const { return mActiveOutputVariables; }
const std::vector<sh::OutputVariable> &getOutputVariables() const { return mOutputVariables; } const std::vector<sh::OutputVariable> &getOutputVariables() const { return mOutputVariables; }
const std::map<int, VariableLocation> &getOutputLocations() const { return mOutputLocations; } const std::vector<VariableLocation> &getOutputLocations() const { return mOutputLocations; }
const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; } const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; } const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; }
const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; } const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; }
...@@ -299,7 +299,6 @@ class ProgramState final : angle::NonCopyable ...@@ -299,7 +299,6 @@ class ProgramState final : angle::NonCopyable
return mAtomicCounterBuffers; return mAtomicCounterBuffers;
} }
GLint getUniformLocation(const std::string &name) const;
GLuint getUniformIndexFromName(const std::string &name) const; GLuint getUniformIndexFromName(const std::string &name) const;
GLuint getUniformIndexFromLocation(GLint location) const; GLuint getUniformIndexFromLocation(GLint location) const;
Optional<GLuint> getSamplerIndex(GLint location) const; Optional<GLuint> getSamplerIndex(GLint location) const;
...@@ -340,7 +339,12 @@ class ProgramState final : angle::NonCopyable ...@@ -340,7 +339,12 @@ class ProgramState final : angle::NonCopyable
// 4. Atomic counter uniforms // 4. Atomic counter uniforms
// 5. Uniform block uniforms // 5. Uniform block uniforms
// This makes opaque uniform validation easier, since we don't need a separate list. // This makes opaque uniform validation easier, since we don't need a separate list.
// For generating the entries and naming them we follow the spec: GLES 3.1 November 2016 section
// 7.3.1.1 Naming Active Resources. There's a separate entry for each struct member and each
// inner array of an array of arrays. Names and mapped names of uniforms that are arrays include
// [0] in the end. This makes implementation of queries simpler.
std::vector<LinkedUniform> mUniforms; std::vector<LinkedUniform> mUniforms;
std::vector<VariableLocation> mUniformLocations; std::vector<VariableLocation> mUniformLocations;
std::vector<InterfaceBlock> mUniformBlocks; std::vector<InterfaceBlock> mUniformBlocks;
std::vector<InterfaceBlock> mShaderStorageBlocks; std::vector<InterfaceBlock> mShaderStorageBlocks;
...@@ -355,8 +359,10 @@ class ProgramState final : angle::NonCopyable ...@@ -355,8 +359,10 @@ class ProgramState final : angle::NonCopyable
// An array of the images that are used by the program // An array of the images that are used by the program
std::vector<gl::ImageBinding> mImageBindings; std::vector<gl::ImageBinding> mImageBindings;
// Names and mapped names of output variables that are arrays include [0] in the end, similarly
// to uniforms.
std::vector<sh::OutputVariable> mOutputVariables; std::vector<sh::OutputVariable> mOutputVariables;
std::map<int, VariableLocation> mOutputLocations; std::vector<VariableLocation> mOutputLocations;
DrawBufferMask mActiveOutputVariables; DrawBufferMask mActiveOutputVariables;
// Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location. // Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location.
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "libANGLE/UniformLinker.h" #include "libANGLE/UniformLinker.h"
#include "common/string_utils.h"
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/Caps.h" #include "libANGLE/Caps.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
...@@ -33,7 +34,21 @@ LinkedUniform *FindUniform(std::vector<LinkedUniform> &list, const std::string & ...@@ -33,7 +34,21 @@ LinkedUniform *FindUniform(std::vector<LinkedUniform> &list, const std::string &
return nullptr; return nullptr;
} }
} // anonymouse namespace int GetUniformLocationBinding(const Program::Bindings &uniformLocationBindings,
const sh::Uniform &uniform)
{
int binding = uniformLocationBindings.getBinding(uniform.name);
if (uniform.isArray() && binding == -1)
{
// Bindings for array uniforms can be set either with or without [0] in the end.
ASSERT(angle::EndsWith(uniform.name, "[0]"));
std::string nameWithoutIndex = uniform.name.substr(0u, uniform.name.length() - 3u);
return uniformLocationBindings.getBinding(nameWithoutIndex);
}
return binding;
}
} // anonymous namespace
UniformLinker::UniformLinker(const ProgramState &state) : mState(state) UniformLinker::UniformLinker(const ProgramState &state) : mState(state)
{ {
...@@ -191,7 +206,7 @@ bool UniformLinker::indexUniforms(InfoLog &infoLog, ...@@ -191,7 +206,7 @@ bool UniformLinker::indexUniforms(InfoLog &infoLog,
continue; continue;
} }
int preSetLocation = uniformLocationBindings.getBinding(uniform.name); int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
int shaderLocation = uniform.location; int shaderLocation = uniform.location;
if (shaderLocation != -1) if (shaderLocation != -1)
...@@ -264,7 +279,7 @@ bool UniformLinker::gatherUniformLocationsAndCheckConflicts( ...@@ -264,7 +279,7 @@ bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
continue; continue;
} }
int apiBoundLocation = uniformLocationBindings.getBinding(uniform.name); int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
int shaderLocation = uniform.location; int shaderLocation = uniform.location;
if (shaderLocation != -1) if (shaderLocation != -1)
...@@ -518,7 +533,19 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl( ...@@ -518,7 +533,19 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
{ {
uniformList = atomicCounterUniforms; uniformList = atomicCounterUniforms;
} }
LinkedUniform *existingUniform = FindUniform(*uniformList, fullName);
std::string fullNameWithArrayIndex(fullName);
std::string fullMappedNameWithArrayIndex(fullMappedName);
if (uniform.isArray())
{
// We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
// and including [0] at the end of array variable names.
fullNameWithArrayIndex += "[0]";
fullMappedNameWithArrayIndex += "[0]";
}
LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
if (existingUniform) if (existingUniform)
{ {
if (binding != -1) if (binding != -1)
...@@ -541,10 +568,10 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl( ...@@ -541,10 +568,10 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
} }
else else
{ {
LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize, LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
binding, offset, *location, -1, uniform.arraySize, binding, offset, *location, -1,
sh::BlockMemberInfo::getDefaultBlockInfo()); sh::BlockMemberInfo::getDefaultBlockInfo());
linkedUniform.mappedName = fullMappedName; linkedUniform.mappedName = fullMappedNameWithArrayIndex;
linkedUniform.staticUse = markStaticUse; linkedUniform.staticUse = markStaticUse;
if (markStaticUse) if (markStaticUse)
{ {
......
...@@ -453,15 +453,8 @@ GLint GetLocationVariableProperty(const sh::VariableWithLocation &var, GLenum pr ...@@ -453,15 +453,8 @@ GLint GetLocationVariableProperty(const sh::VariableWithLocation &var, GLenum pr
case GL_NAME_LENGTH: case GL_NAME_LENGTH:
{ {
size_t length = var.name.size();
if (var.isArray())
{
// Counts "[0]".
length += 3;
}
// ES31 spec p84: This counts the terminating null char. // ES31 spec p84: This counts the terminating null char.
++length; return clampCast<GLint>(var.name.size() + 1u);
return clampCast<GLint>(length);
} }
case GL_LOCATION: case GL_LOCATION:
...@@ -1471,7 +1464,7 @@ GLint QueryProgramResourceLocation(const Program *program, ...@@ -1471,7 +1464,7 @@ GLint QueryProgramResourceLocation(const Program *program,
return program->getFragDataLocation(name); return program->getFragDataLocation(name);
case GL_UNIFORM: case GL_UNIFORM:
return program->getState().getUniformLocation(name); return program->getUniformLocation(name);
default: default:
UNREACHABLE(); UNREACHABLE();
......
...@@ -1265,9 +1265,15 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data, ...@@ -1265,9 +1265,15 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data,
const auto &shaderOutputVars = const auto &shaderOutputVars =
metadata.getFragmentShader()->getData().getActiveOutputVariables(); metadata.getFragmentShader()->getData().getActiveOutputVariables();
for (auto outputPair : programData.getOutputLocations()) for (size_t outputLocationIndex = 0u;
outputLocationIndex < programData.getOutputLocations().size(); ++outputLocationIndex)
{ {
const VariableLocation &outputLocation = outputPair.second; const VariableLocation &outputLocation =
programData.getOutputLocations().at(outputLocationIndex);
if (!outputLocation.used())
{
continue;
}
const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index]; const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index];
const std::string &variableName = "out_" + outputVariable.name; const std::string &variableName = "out_" + outputVariable.name;
...@@ -1283,7 +1289,7 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data, ...@@ -1283,7 +1289,7 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data,
outputKeyVariable.type = outputVariable.type; outputKeyVariable.type = outputVariable.type;
outputKeyVariable.name = variableName + elementString; outputKeyVariable.name = variableName + elementString;
outputKeyVariable.source = variableName + ArrayIndexString(outputLocation.arrayIndices); outputKeyVariable.source = variableName + ArrayIndexString(outputLocation.arrayIndices);
outputKeyVariable.outputIndex = outputPair.first; outputKeyVariable.outputIndex = outputLocationIndex;
outPixelShaderKey->push_back(outputKeyVariable); outPixelShaderKey->push_back(outputKeyVariable);
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "libANGLE/renderer/d3d/ProgramD3D.h" #include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "common/bitset_utils.h" #include "common/bitset_utils.h"
#include "common/string_utils.h"
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/Framebuffer.h" #include "libANGLE/Framebuffer.h"
...@@ -1979,7 +1980,17 @@ void ProgramD3D::defineUniformsAndAssignRegisters(const gl::Context *context) ...@@ -1979,7 +1980,17 @@ void ProgramD3D::defineUniformsAndAssignRegisters(const gl::Context *context)
if (!glUniform.isInDefaultBlock()) if (!glUniform.isInDefaultBlock())
continue; continue;
auto mapEntry = uniformMap.find(glUniform.name); std::string name = glUniform.name;
if (glUniform.isArray())
{
// In the program state, array uniform names include [0] as in the program resource
// spec. Here we don't include it.
// TODO(oetuaho@nvidia.com): consider using the same uniform naming here as in the GL
// layer.
ASSERT(angle::EndsWith(name, "[0]"));
name.resize(name.length() - 3);
}
auto mapEntry = uniformMap.find(name);
ASSERT(mapEntry != uniformMap.end()); ASSERT(mapEntry != uniformMap.end());
mD3DUniforms.push_back(mapEntry->second); mD3DUniforms.push_back(mapEntry->second);
} }
...@@ -2588,8 +2599,9 @@ bool ProgramD3D::getUniformBlockSize(const std::string &blockName, ...@@ -2588,8 +2599,9 @@ bool ProgramD3D::getUniformBlockSize(const std::string &blockName,
const std::string & /* blockMappedName */, const std::string & /* blockMappedName */,
size_t *sizeOut) const size_t *sizeOut) const
{ {
std::string baseName = blockName; size_t nameLengthWithoutArrayIndex;
gl::ParseAndStripArrayIndex(&baseName); gl::ParseArrayIndex(blockName, &nameLengthWithoutArrayIndex);
std::string baseName = blockName.substr(0u, nameLengthWithoutArrayIndex);
auto sizeIter = mBlockDataSizes.find(baseName); auto sizeIter = mBlockDataSizes.find(baseName);
if (sizeIter == mBlockDataSizes.end()) if (sizeIter == mBlockDataSizes.end())
......
...@@ -50,7 +50,7 @@ struct D3DUniform : private angle::NonCopyable ...@@ -50,7 +50,7 @@ struct D3DUniform : private angle::NonCopyable
// Duplicated from the GL layer // Duplicated from the GL layer
const gl::UniformTypeInfo &typeInfo; const gl::UniformTypeInfo &typeInfo;
std::string name; std::string name; // Names of arrays don't include [0], unlike at the GL layer.
unsigned int arraySize; unsigned int arraySize;
// Pointer to a system copies of the data. Separate pointers for each uniform storage type. // Pointer to a system copies of the data. Separate pointers for each uniform storage type.
......
...@@ -663,14 +663,15 @@ void ProgramGL::postLink() ...@@ -663,14 +663,15 @@ void ProgramGL::postLink()
// "Locations for sequential array indices are not required to be sequential." // "Locations for sequential array indices are not required to be sequential."
const gl::LinkedUniform &uniform = uniforms[entry.index]; const gl::LinkedUniform &uniform = uniforms[entry.index];
std::stringstream fullNameStr; std::stringstream fullNameStr;
fullNameStr << uniform.mappedName;
if (uniform.isArray()) if (uniform.isArray())
{ {
for (auto arrayElementIndexIt = entry.arrayIndices.rbegin(); ASSERT(angle::EndsWith(uniform.mappedName, "[0]"));
arrayElementIndexIt != entry.arrayIndices.rend(); ++arrayElementIndexIt) fullNameStr << uniform.mappedName.substr(0, uniform.mappedName.length() - 3);
{ fullNameStr << "[" << entry.arrayIndices[0] << "]";
fullNameStr << "[" << (*arrayElementIndexIt) << "]"; }
} else
{
fullNameStr << uniform.mappedName;
} }
const std::string &fullName = fullNameStr.str(); const std::string &fullName = fullNameStr.str();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment