Commit c853804c by Olli Etuaho Committed by Commit Bot

Add support for arrays of arrays to VariableLocation

Array indices are sorted so that the outermost index is in the back. This is because we want to be consistent with future arrays of arrays parsing code. In parsing we'll have a utility function to make a TType object into an array, and there it's most natural to push the new outermost sizes to the back of the vector. Further patches will still be needed to parse arrays of arrays and add support to arrays of arrays into the API. BUG=angleproject:2125 TEST=angle_unittests, angle_end2end_tests Change-Id: I6c88edabf68ae9dbd803ec6d20543016c408b702 Reviewed-on: https://chromium-review.googlesource.com/686414Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent e416e527
...@@ -17,6 +17,34 @@ namespace angle ...@@ -17,6 +17,34 @@ namespace angle
const uintptr_t DirtyPointer = std::numeric_limits<uintptr_t>::max(); const uintptr_t DirtyPointer = std::numeric_limits<uintptr_t>::max();
} }
std::string ArrayString(unsigned int i)
{
// We assume that UINT_MAX and GL_INVALID_INDEX are equal.
ASSERT(i != UINT_MAX);
std::stringstream strstr;
strstr << "[";
strstr << i;
strstr << "]";
return strstr.str();
}
std::string ArrayIndexString(const std::vector<unsigned int> &indices)
{
std::stringstream strstr;
for (auto indicesIt = indices.rbegin(); indicesIt != indices.rend(); ++indicesIt)
{
// We assume that UINT_MAX and GL_INVALID_INDEX are equal.
ASSERT(*indicesIt != UINT_MAX);
strstr << "[";
strstr << (*indicesIt);
strstr << "]";
}
return strstr.str();
}
size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char>& outBuffer) size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char>& outBuffer)
{ {
// The state of the va_list passed to vsnprintf is undefined after the call, do a copy in case // The state of the va_list passed to vsnprintf is undefined after the call, do a copy in case
......
...@@ -160,23 +160,11 @@ inline const char* MakeStaticString(const std::string &str) ...@@ -160,23 +160,11 @@ inline const char* MakeStaticString(const std::string &str)
return strings.insert(str).first->c_str(); return strings.insert(str).first->c_str();
} }
inline std::string ArrayString(unsigned int i) std::string ArrayString(unsigned int i);
{
// We assume UINT_MAX and GL_INVALID_INDEX are equal
// See DynamicHLSL.cpp
if (i == UINT_MAX)
{
return "";
}
std::stringstream strstr;
strstr << "["; // Indices are stored in vectors with the outermost index in the back. In the output of the function
strstr << i; // the indices are reversed.
strstr << "]"; std::string ArrayIndexString(const std::vector<unsigned int> &indices);
return strstr.str();
}
inline std::string Str(int i) inline std::string Str(int i)
{ {
......
//
// Copyright (c) 2017 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.
//
// angleutils_unittest.cpp: Unit tests for ANGLE's common utilities.
#include "gtest/gtest.h"
#include "common/angleutils.h"
namespace
{
// Test that multiple array indices are written out in the right order.
TEST(ArrayIndexString, MultipleArrayIndices)
{
std::vector<unsigned int> indices;
indices.push_back(12);
indices.push_back(34);
indices.push_back(56);
EXPECT_EQ("[56][34][12]", ArrayIndexString(indices));
}
} // anonymous namespace
...@@ -735,35 +735,39 @@ int VariableSortOrder(GLenum type) ...@@ -735,35 +735,39 @@ int VariableSortOrder(GLenum type)
} }
} }
std::string ParseResourceName(const std::string &name, size_t *outSubscript) std::string ParseResourceName(const std::string &name, std::vector<unsigned int> *outSubscripts)
{ {
// Strip any trailing array operator and retrieve the subscript if (outSubscripts)
size_t open = name.find_last_of('[');
size_t close = name.find_last_of(']');
bool hasIndex = (open != std::string::npos) && (close == name.length() - 1);
if (!hasIndex)
{ {
if (outSubscript) outSubscripts->clear();
{
*outSubscript = GL_INVALID_INDEX;
}
return name;
} }
// Strip any trailing array indexing operators and retrieve the subscripts.
if (outSubscript) size_t baseNameLength = name.length();
bool hasIndex = true;
while (hasIndex)
{ {
int index = atoi(name.substr(open + 1).c_str()); size_t open = name.find_last_of('[', baseNameLength - 1);
if (index >= 0) size_t close = name.find_last_of(']', baseNameLength - 1);
{ hasIndex = (open != std::string::npos) && (close == baseNameLength - 1);
*outSubscript = index; if (hasIndex)
}
else
{ {
*outSubscript = GL_INVALID_INDEX; baseNameLength = open;
if (outSubscripts)
{
int index = atoi(name.substr(open + 1).c_str());
if (index >= 0)
{
outSubscripts->push_back(index);
}
else
{
outSubscripts->push_back(GL_INVALID_INDEX);
}
}
} }
} }
return name.substr(0, open); return name.substr(0, baseNameLength);
} }
unsigned int ParseAndStripArrayIndex(std::string *name) unsigned int ParseAndStripArrayIndex(std::string *name)
......
...@@ -12,9 +12,10 @@ ...@@ -12,9 +12,10 @@
#include <EGL/egl.h> #include <EGL/egl.h>
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include "angle_gl.h"
#include <string>
#include <math.h> #include <math.h>
#include <string>
#include <vector>
#include "angle_gl.h"
#include "common/mathutil.h" #include "common/mathutil.h"
...@@ -49,10 +50,12 @@ bool IsCubeMapTextureTarget(GLenum target); ...@@ -49,10 +50,12 @@ bool IsCubeMapTextureTarget(GLenum target);
size_t CubeMapTextureTargetToLayerIndex(GLenum target); size_t CubeMapTextureTargetToLayerIndex(GLenum target);
GLenum LayerIndexToCubeMapTextureTarget(size_t index); GLenum LayerIndexToCubeMapTextureTarget(size_t index);
// Parse the base resource name and array index. Returns the base name of the resource. // Parse the base resource name and array indices. Returns the base name of the resource.
// outSubscript is set to GL_INVALID_INDEX if the provided name is not an array or the array index // If the provided name doesn't index an array, the outSubscripts vector will be empty.
// is invalid. // If the provided name indexes an array, the outSubscripts vector will contain indices with
std::string ParseResourceName(const std::string &name, size_t *outSubscript); // outermost array indices in the back. If an array index is invalid, GL_INVALID_INDEX is added to
// outSubscripts.
std::string ParseResourceName(const std::string &name, std::vector<unsigned int> *outSubscripts);
// Find the range of index values in the provided indices pointer. Primitive restart indices are // Find the range of index values in the provided indices pointer. Primitive restart indices are
// only counted in the range if primitive restart is disabled. // only counted in the range if primitive restart is disabled.
......
...@@ -13,43 +13,66 @@ ...@@ -13,43 +13,66 @@
namespace namespace
{ {
// Test parsing valid single array indices
TEST(ParseResourceName, ArrayIndex) TEST(ParseResourceName, ArrayIndex)
{ {
size_t index; std::vector<unsigned int> indices;
EXPECT_EQ("foo", gl::ParseResourceName("foo[123]", &index)); EXPECT_EQ("foo", gl::ParseResourceName("foo[123]", &indices));
EXPECT_EQ(123u, index); ASSERT_EQ(1u, indices.size());
EXPECT_EQ(123u, indices[0]);
EXPECT_EQ("bar", gl::ParseResourceName("bar[0]", &index)); EXPECT_EQ("bar", gl::ParseResourceName("bar[0]", &indices));
EXPECT_EQ(0u, index); ASSERT_EQ(1u, indices.size());
EXPECT_EQ(0u, indices[0]);
} }
// Parsing a negative array index should result in INVALID_INDEX.
TEST(ParseResourceName, NegativeArrayIndex) TEST(ParseResourceName, NegativeArrayIndex)
{ {
size_t index; std::vector<unsigned int> indices;
EXPECT_EQ("foo", gl::ParseResourceName("foo[-1]", &index)); EXPECT_EQ("foo", gl::ParseResourceName("foo[-1]", &indices));
EXPECT_EQ(GL_INVALID_INDEX, index); ASSERT_EQ(1u, indices.size());
EXPECT_EQ(GL_INVALID_INDEX, indices.back());
} }
// Parsing no array indices should result in an empty array.
TEST(ParseResourceName, NoArrayIndex) TEST(ParseResourceName, NoArrayIndex)
{ {
size_t index; std::vector<unsigned int> indices;
EXPECT_EQ("foo", gl::ParseResourceName("foo", &index)); EXPECT_EQ("foo", gl::ParseResourceName("foo", &indices));
EXPECT_EQ(GL_INVALID_INDEX, index); EXPECT_TRUE(indices.empty());
} }
TEST(ParseResourceName, NULLArrayIndex) // The ParseResourceName function should work when a nullptr is passed as the indices output vector.
TEST(ParseResourceName, NULLArrayIndices)
{ {
EXPECT_EQ("foo", gl::ParseResourceName("foo[10]", nullptr)); EXPECT_EQ("foo", gl::ParseResourceName("foo[10]", nullptr));
} }
// Parsing multiple array indices should result in outermost array indices being last in the vector.
TEST(ParseResourceName, MultipleArrayIndices)
{
std::vector<unsigned int> indices;
EXPECT_EQ("foo", gl::ParseResourceName("foo[12][34][56]", &indices));
ASSERT_EQ(3u, indices.size());
// Indices are sorted with outermost array index last.
EXPECT_EQ(56u, indices[0]);
EXPECT_EQ(34u, indices[1]);
EXPECT_EQ(12u, indices[2]);
}
// Trailing whitespace should not be accepted by ParseResourceName.
TEST(ParseResourceName, TrailingWhitespace) TEST(ParseResourceName, TrailingWhitespace)
{ {
size_t index; std::vector<unsigned int> indices;
EXPECT_EQ("foo ", gl::ParseResourceName("foo ", &index)); EXPECT_EQ("foo ", gl::ParseResourceName("foo ", &indices));
EXPECT_EQ(GL_INVALID_INDEX, index); EXPECT_TRUE(indices.empty());
EXPECT_EQ("foo[10] ", gl::ParseResourceName("foo[10] ", &indices));
EXPECT_TRUE(indices.empty());
EXPECT_EQ("foo[10] ", gl::ParseResourceName("foo[10] ", &index)); EXPECT_EQ("foo[10][20] ", gl::ParseResourceName("foo[10][20] ", &indices));
EXPECT_EQ(GL_INVALID_INDEX, index); EXPECT_TRUE(indices.empty());
} }
} }
...@@ -46,6 +46,16 @@ class BinaryInputStream : angle::NonCopyable ...@@ -46,6 +46,16 @@ class BinaryInputStream : angle::NonCopyable
*outValue = readInt<IntT>(); *outValue = readInt<IntT>();
} }
template <class IntT, class VectorElementT>
void readIntVector(std::vector<VectorElementT> *param)
{
unsigned int size = readInt<unsigned int>();
for (unsigned int index = 0; index < size; ++index)
{
param->push_back(readInt<IntT>());
}
}
bool readBool() bool readBool()
{ {
int value = 0; int value = 0;
...@@ -197,6 +207,16 @@ class BinaryOutputStream : angle::NonCopyable ...@@ -197,6 +207,16 @@ class BinaryOutputStream : angle::NonCopyable
} }
} }
template <class IntT>
void writeIntVector(std::vector<IntT> param)
{
writeInt(param.size());
for (IntT element : param)
{
writeIntOrNegOne(element);
}
}
void writeString(const std::string &v) void writeString(const std::string &v)
{ {
writeInt(v.length()); writeInt(v.length());
......
...@@ -238,8 +238,9 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -238,8 +238,9 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
uniformIndexIndex++) uniformIndexIndex++)
{ {
VariableLocation variable; VariableLocation variable;
stream.readInt(&variable.element); stream.readIntVector<unsigned int>(&variable.arrayIndices);
stream.readInt(&variable.index); stream.readInt(&variable.index);
stream.readInt(&variable.flattenedArrayOffset);
stream.readBool(&variable.ignored); stream.readBool(&variable.ignored);
state->mUniformLocations.push_back(variable); state->mUniformLocations.push_back(variable);
...@@ -319,8 +320,9 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -319,8 +320,9 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
{ {
int locationIndex = stream.readInt<int>(); int locationIndex = stream.readInt<int>();
VariableLocation locationData; VariableLocation locationData;
stream.readInt(&locationData.element); stream.readIntVector<unsigned int>(&locationData.arrayIndices);
stream.readInt(&locationData.index); stream.readInt(&locationData.index);
stream.readInt(&locationData.flattenedArrayOffset);
stream.readBool(&locationData.ignored); stream.readBool(&locationData.ignored);
state->mOutputLocations[locationIndex] = locationData; state->mOutputLocations[locationIndex] = locationData;
} }
...@@ -427,8 +429,9 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -427,8 +429,9 @@ void MemoryProgramCache::Serialize(const Context *context,
stream.writeInt(state.getUniformLocations().size()); stream.writeInt(state.getUniformLocations().size());
for (const auto &variable : state.getUniformLocations()) for (const auto &variable : state.getUniformLocations())
{ {
stream.writeInt(variable.element); stream.writeIntVector(variable.arrayIndices);
stream.writeIntOrNegOne(variable.index); stream.writeIntOrNegOne(variable.index);
stream.writeInt(variable.flattenedArrayOffset);
stream.writeInt(variable.ignored); stream.writeInt(variable.ignored);
} }
...@@ -481,8 +484,9 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -481,8 +484,9 @@ void MemoryProgramCache::Serialize(const Context *context,
for (const auto &outputPair : state.getOutputLocations()) for (const auto &outputPair : state.getOutputLocations())
{ {
stream.writeInt(outputPair.first); stream.writeInt(outputPair.first);
stream.writeIntOrNegOne(outputPair.second.element); stream.writeIntVector(outputPair.second.arrayIndices);
stream.writeIntOrNegOne(outputPair.second.index); stream.writeIntOrNegOne(outputPair.second.index);
stream.writeInt(outputPair.second.flattenedArrayOffset);
stream.writeInt(outputPair.second.ignored); stream.writeInt(outputPair.second.ignored);
} }
......
...@@ -140,13 +140,16 @@ bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y) ...@@ -140,13 +140,16 @@ bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
template <typename VarT> template <typename VarT>
GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name) GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
{ {
size_t subscript = GL_INVALID_INDEX; std::vector<unsigned int> subscripts;
std::string baseName = ParseResourceName(name, &subscript); std::string baseName = ParseResourceName(name, &subscripts);
// The app is not allowed to specify array indices other than 0 for arrays of basic types // The app is not allowed to specify array indices other than 0 for arrays of basic types
if (subscript != 0 && subscript != GL_INVALID_INDEX) for (unsigned int subscript : subscripts)
{ {
return GL_INVALID_INDEX; if (subscript != 0u)
{
return GL_INVALID_INDEX;
}
} }
for (size_t index = 0; index < list.size(); index++) for (size_t index = 0; index < list.size(); index++)
...@@ -154,7 +157,9 @@ GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string ...@@ -154,7 +157,9 @@ GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string
const VarT &resource = list[index]; const VarT &resource = list[index];
if (resource.name == baseName) if (resource.name == baseName)
{ {
if (resource.isArray() || subscript == GL_INVALID_INDEX) // TODO(oetuaho@nvidia.com): Check array nesting >= number of specified
// subscripts once arrays of arrays are supported in ShaderVariable.
if ((resource.isArray() || subscripts.empty()) && subscripts.size() <= 1u)
{ {
return static_cast<GLuint>(index); return static_cast<GLuint>(index);
} }
...@@ -178,14 +183,14 @@ void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSi ...@@ -178,14 +183,14 @@ void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSi
bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name) bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
{ {
size_t subscript = GL_INVALID_INDEX; std::vector<unsigned int> subscripts;
std::string baseName = ParseResourceName(name, &subscript); std::string baseName = ParseResourceName(name, &subscripts);
for (auto it = nameSet.begin(); it != nameSet.end(); ++it) for (auto nameInSet : nameSet)
{ {
size_t arrayIndex = GL_INVALID_INDEX; std::vector<unsigned int> arrayIndices;
std::string arrayName = ParseResourceName(*it, &arrayIndex); std::string arrayName = ParseResourceName(nameInSet, &arrayIndices);
if (baseName == arrayName && (subscript == GL_INVALID_INDEX || if (baseName == arrayName &&
arrayIndex == GL_INVALID_INDEX || subscript == arrayIndex)) (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices))
{ {
return true; return true;
} }
...@@ -287,13 +292,26 @@ void InfoLog::reset() ...@@ -287,13 +292,26 @@ void InfoLog::reset()
{ {
} }
VariableLocation::VariableLocation() : element(0), index(kUnused), ignored(false) VariableLocation::VariableLocation() : index(kUnused), flattenedArrayOffset(0u), ignored(false)
{
}
VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
: arrayIndices(1, arrayIndex), index(index), flattenedArrayOffset(arrayIndex), ignored(false)
{ {
ASSERT(arrayIndex != GL_INVALID_INDEX);
} }
VariableLocation::VariableLocation(unsigned int element, unsigned int index) bool VariableLocation::areAllArrayIndicesZero() const
: element(element), index(index), ignored(false)
{ {
for (unsigned int arrayIndex : arrayIndices)
{
if (arrayIndex != 0)
{
return false;
}
}
return true;
} }
void Program::Bindings::bindLocation(GLuint index, const std::string &name) void Program::Bindings::bindLocation(GLuint index, const std::string &name)
...@@ -344,8 +362,8 @@ const std::string &ProgramState::getLabel() ...@@ -344,8 +362,8 @@ const std::string &ProgramState::getLabel()
GLint ProgramState::getUniformLocation(const std::string &name) const GLint ProgramState::getUniformLocation(const std::string &name) const
{ {
size_t subscript = GL_INVALID_INDEX; std::vector<unsigned int> subscripts;
std::string baseName = ParseResourceName(name, &subscript); std::string baseName = ParseResourceName(name, &subscripts);
for (size_t location = 0; location < mUniformLocations.size(); ++location) for (size_t location = 0; location < mUniformLocations.size(); ++location)
{ {
...@@ -361,15 +379,15 @@ GLint ProgramState::getUniformLocation(const std::string &name) const ...@@ -361,15 +379,15 @@ GLint ProgramState::getUniformLocation(const std::string &name) const
{ {
if (uniform.isArray()) if (uniform.isArray())
{ {
if (uniformLocation.element == subscript || if (uniformLocation.arrayIndices == subscripts ||
(uniformLocation.element == 0 && subscript == GL_INVALID_INDEX)) (uniformLocation.areAllArrayIndicesZero() && subscripts.empty()))
{ {
return static_cast<GLint>(location); return static_cast<GLint>(location);
} }
} }
else else
{ {
if (subscript == GL_INVALID_INDEX) if (subscripts.empty())
{ {
return static_cast<GLint>(location); return static_cast<GLint>(location);
} }
...@@ -1209,8 +1227,10 @@ GLint Program::getFragDataLocation(const std::string &name) const ...@@ -1209,8 +1227,10 @@ GLint Program::getFragDataLocation(const std::string &name) const
{ {
const VariableLocation &locationInfo = outputPair.second; const VariableLocation &locationInfo = outputPair.second;
const sh::OutputVariable &outputVariable = mState.mOutputVariables[locationInfo.index]; const sh::OutputVariable &outputVariable = mState.mOutputVariables[locationInfo.index];
ASSERT(locationInfo.arrayIndices.size() <= 1);
if (outputVariable.name == baseName && if (outputVariable.name == baseName &&
(arrayIndex == GL_INVALID_INDEX || arrayIndex == locationInfo.element)) (arrayIndex == GL_INVALID_INDEX || (!locationInfo.arrayIndices.empty() &&
arrayIndex == locationInfo.arrayIndices.back())))
{ {
return static_cast<GLint>(outputPair.first); return static_cast<GLint>(outputPair.first);
} }
...@@ -1685,8 +1705,8 @@ GLint Program::getActiveUniformBlockMaxLength() const ...@@ -1685,8 +1705,8 @@ GLint Program::getActiveUniformBlockMaxLength() const
GLuint Program::getUniformBlockIndex(const std::string &name) const GLuint Program::getUniformBlockIndex(const std::string &name) const
{ {
size_t subscript = GL_INVALID_INDEX; std::vector<unsigned int> subscripts;
std::string baseName = ParseResourceName(name, &subscript); std::string baseName = ParseResourceName(name, &subscripts);
unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size()); unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
...@@ -1695,9 +1715,10 @@ GLuint Program::getUniformBlockIndex(const std::string &name) const ...@@ -1695,9 +1715,10 @@ GLuint Program::getUniformBlockIndex(const std::string &name) const
if (uniformBlock.name == baseName) if (uniformBlock.name == baseName)
{ {
const bool arrayElementZero = const bool arrayElementZero =
(subscript == GL_INVALID_INDEX && (subscripts.empty() && (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
(!uniformBlock.isArray || uniformBlock.arrayElement == 0)); const bool arrayElementMatches =
if (subscript == uniformBlock.arrayElement || arrayElementZero) (subscripts.size() == 1 && subscripts[0] == uniformBlock.arrayElement);
if (arrayElementMatches || arrayElementZero)
{ {
return blockIndex; return blockIndex;
} }
...@@ -2466,8 +2487,8 @@ bool Program::linkValidateTransformFeedback(const gl::Context *context, ...@@ -2466,8 +2487,8 @@ bool Program::linkValidateTransformFeedback(const gl::Context *context,
for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames) for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
{ {
bool found = false; bool found = false;
size_t subscript = GL_INVALID_INDEX; std::vector<unsigned int> subscripts;
std::string baseName = ParseResourceName(tfVaryingName, &subscript); std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
for (const auto &ref : varyings) for (const auto &ref : varyings)
{ {
...@@ -2501,8 +2522,7 @@ bool Program::linkValidateTransformFeedback(const gl::Context *context, ...@@ -2501,8 +2522,7 @@ bool Program::linkValidateTransformFeedback(const gl::Context *context,
// TODO(jmadill): Investigate implementation limits on D3D11 // TODO(jmadill): Investigate implementation limits on D3D11
size_t elementCount = size_t elementCount =
((varying->isArray() && subscript == GL_INVALID_INDEX) ? varying->elementCount() ((varying->isArray() && subscripts.empty()) ? varying->elementCount() : 1);
: 1);
size_t componentCount = VariableComponentCount(varying->type) * elementCount; size_t componentCount = VariableComponentCount(varying->type) * elementCount;
if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
componentCount > caps.maxTransformFeedbackSeparateComponents) componentCount > caps.maxTransformFeedbackSeparateComponents)
...@@ -2577,8 +2597,13 @@ void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &var ...@@ -2577,8 +2597,13 @@ void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &var
mState.mLinkedTransformFeedbackVaryings.clear(); mState.mLinkedTransformFeedbackVaryings.clear();
for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames) for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
{ {
std::vector<unsigned int> subscripts;
std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
size_t subscript = GL_INVALID_INDEX; size_t subscript = GL_INVALID_INDEX;
std::string baseName = ParseResourceName(tfVaryingName, &subscript); if (!subscripts.empty())
{
subscript = subscripts.back();
}
for (const auto &ref : varyings) for (const auto &ref : varyings)
{ {
const sh::Varying *varying = ref.second.get(); const sh::Varying *varying = ref.second.get();
...@@ -2653,8 +2678,13 @@ std::vector<PackedVarying> Program::getPackedVaryings( ...@@ -2653,8 +2678,13 @@ std::vector<PackedVarying> Program::getPackedVaryings(
for (const std::string &tfVarying : tfVaryings) for (const std::string &tfVarying : tfVaryings)
{ {
std::vector<unsigned int> subscripts;
std::string baseName = ParseResourceName(tfVarying, &subscripts);
size_t subscript = GL_INVALID_INDEX; size_t subscript = GL_INVALID_INDEX;
std::string baseName = ParseResourceName(tfVarying, &subscript); if (!subscripts.empty())
{
subscript = subscripts.back();
}
if (uniqueFullNames.count(tfVarying) > 0) if (uniqueFullNames.count(tfVarying) > 0)
{ {
continue; continue;
...@@ -2742,8 +2772,17 @@ void Program::linkOutputVariables(const Context *context) ...@@ -2742,8 +2772,17 @@ void Program::linkOutputVariables(const Context *context)
{ {
const int location = baseLocation + elementIndex; const int location = baseLocation + elementIndex;
ASSERT(mState.mOutputLocations.count(location) == 0); ASSERT(mState.mOutputLocations.count(location) == 0);
unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX; if (outputVariable.isArray())
mState.mOutputLocations[location] = VariableLocation(element, outputVariableIndex); {
mState.mOutputLocations[location] =
VariableLocation(elementIndex, outputVariableIndex);
}
else
{
VariableLocation locationInfo;
locationInfo.index = outputVariableIndex;
mState.mOutputLocations[location] = locationInfo;
}
} }
} }
} }
...@@ -3034,7 +3073,7 @@ void Program::updateSamplerUniform(const VariableLocation &locationInfo, ...@@ -3034,7 +3073,7 @@ void Program::updateSamplerUniform(const VariableLocation &locationInfo,
std::vector<GLuint> *boundTextureUnits = std::vector<GLuint> *boundTextureUnits =
&mState.mSamplerBindings[samplerIndex].boundTextureUnits; &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.element); std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.flattenedArrayOffset);
// Invalidate the validation cache. // Invalidate the validation cache.
mCachedValidateSamplersResult.reset(); mCachedValidateSamplersResult.reset();
...@@ -3053,7 +3092,8 @@ GLsizei Program::clampUniformCount(const VariableLocation &locationInfo, ...@@ -3053,7 +3092,8 @@ GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
// OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
// element index used, as reported by GetActiveUniform, will be ignored by the GL." // element index used, as reported by GetActiveUniform, will be ignored by the GL."
unsigned int remainingElements = linkedUniform.elementCount() - locationInfo.element; unsigned int remainingElements =
linkedUniform.elementCount() - locationInfo.flattenedArrayOffset;
GLsizei maxElementCount = GLsizei maxElementCount =
static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents()); static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
...@@ -3082,7 +3122,8 @@ GLsizei Program::clampMatrixUniformCount(GLint location, ...@@ -3082,7 +3122,8 @@ GLsizei Program::clampMatrixUniformCount(GLint location,
// OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
// element index used, as reported by GetActiveUniform, will be ignored by the GL." // element index used, as reported by GetActiveUniform, will be ignored by the GL."
unsigned int remainingElements = linkedUniform.elementCount() - locationInfo.element; unsigned int remainingElements =
linkedUniform.elementCount() - locationInfo.flattenedArrayOffset;
return std::min(count, static_cast<GLsizei>(remainingElements)); return std::min(count, static_cast<GLsizei>(remainingElements));
} }
......
...@@ -138,7 +138,7 @@ struct VariableLocation ...@@ -138,7 +138,7 @@ struct VariableLocation
static constexpr unsigned int kUnused = GL_INVALID_INDEX; static constexpr unsigned int kUnused = GL_INVALID_INDEX;
VariableLocation(); VariableLocation();
VariableLocation(unsigned int element, unsigned int index); VariableLocation(unsigned int arrayIndex, unsigned int index);
// If used is false, it means this location is only used to fill an empty space in an array, // If used is false, it means this location is only used to fill an empty space in an array,
// and there is no corresponding uniform variable for this location. It can also mean the // and there is no corresponding uniform variable for this location. It can also mean the
...@@ -147,9 +147,18 @@ struct VariableLocation ...@@ -147,9 +147,18 @@ struct VariableLocation
void markUnused() { index = kUnused; } void markUnused() { index = kUnused; }
void markIgnored() { ignored = true; } void markIgnored() { ignored = true; }
unsigned int element; bool areAllArrayIndicesZero() const;
// The "arrayIndices" vector stores indices for the GLSL array. "index" is an index of the
// location.
std::vector<unsigned int> arrayIndices; // Outermost array indices are in the back.
unsigned int index; unsigned int index;
unsigned int flattenedArrayOffset; // For non-nested arrays this is the same as the array
// index. For arrays of arrays, the indices are converted to
// a single offset inside a one-dimensional array made up of
// the elements of the innermost arrays.
// If this location was bound to an unreferenced uniform. Setting data on this uniform is a // If this location was bound to an unreferenced uniform. Setting data on this uniform is a
// no-op. // no-op.
bool ignored; bool ignored;
......
...@@ -262,8 +262,7 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog, ...@@ -262,8 +262,7 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
// Make sure transform feedback varyings aren't optimized out. // Make sure transform feedback varyings aren't optimized out.
for (const std::string &transformFeedbackVaryingName : transformFeedbackVaryings) for (const std::string &transformFeedbackVaryingName : transformFeedbackVaryings)
{ {
size_t subscript = GL_INVALID_INDEX; std::string tfVaryingBaseName = ParseResourceName(transformFeedbackVaryingName, nullptr);
std::string tfVaryingBaseName = ParseResourceName(transformFeedbackVaryingName, &subscript);
bool found = (uniqueVaryingNames.count(transformFeedbackVaryingName) > 0 || bool found = (uniqueVaryingNames.count(transformFeedbackVaryingName) > 0 ||
uniqueVaryingNames.count(tfVaryingBaseName) > 0); uniqueVaryingNames.count(tfVaryingBaseName) > 0);
......
...@@ -1270,15 +1270,19 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data, ...@@ -1270,15 +1270,19 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data,
const VariableLocation &outputLocation = outputPair.second; const VariableLocation &outputLocation = outputPair.second;
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;
// Fragment outputs can't be arrays of arrays. ESSL 3.10 section 4.3.6.
ASSERT(outputLocation.arrayIndices.size() <= 1u);
const std::string &elementString = const std::string &elementString =
(outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element)); (outputLocation.arrayIndices.empty() ? ""
: Str(outputLocation.arrayIndices.back()));
ASSERT(outputVariable.staticUse); ASSERT(outputVariable.staticUse);
PixelShaderOutputVariable outputKeyVariable; PixelShaderOutputVariable outputKeyVariable;
outputKeyVariable.type = outputVariable.type; outputKeyVariable.type = outputVariable.type;
outputKeyVariable.name = variableName + elementString; outputKeyVariable.name = variableName + elementString;
outputKeyVariable.source = variableName + ArrayString(outputLocation.element); outputKeyVariable.source = variableName + ArrayIndexString(outputLocation.arrayIndices);
outputKeyVariable.outputIndex = outputPair.first; outputKeyVariable.outputIndex = outputPair.first;
outPixelShaderKey->push_back(outputKeyVariable); outPixelShaderKey->push_back(outputKeyVariable);
......
...@@ -2169,11 +2169,11 @@ void ProgramD3D::setUniformImpl(const gl::VariableLocation &locationInfo, ...@@ -2169,11 +2169,11 @@ void ProgramD3D::setUniformImpl(const gl::VariableLocation &locationInfo,
{ {
D3DUniform *targetUniform = mD3DUniforms[locationInfo.index]; D3DUniform *targetUniform = mD3DUniforms[locationInfo.index];
const int components = targetUniform->typeInfo.componentCount; const int components = targetUniform->typeInfo.componentCount;
unsigned int arrayElement = locationInfo.element; unsigned int arrayElementOffset = locationInfo.flattenedArrayOffset;
if (targetUniform->typeInfo.type == uniformType) if (targetUniform->typeInfo.type == uniformType)
{ {
T *dest = reinterpret_cast<T *>(targetData) + arrayElement * 4; T *dest = reinterpret_cast<T *>(targetData) + arrayElementOffset * 4;
const T *source = v; const T *source = v;
for (GLint i = 0; i < count; i++, dest += 4, source += components) for (GLint i = 0; i < count; i++, dest += 4, source += components)
...@@ -2184,7 +2184,7 @@ void ProgramD3D::setUniformImpl(const gl::VariableLocation &locationInfo, ...@@ -2184,7 +2184,7 @@ void ProgramD3D::setUniformImpl(const gl::VariableLocation &locationInfo,
else else
{ {
ASSERT(targetUniform->typeInfo.type == gl::VariableBoolVectorType(uniformType)); ASSERT(targetUniform->typeInfo.type == gl::VariableBoolVectorType(uniformType));
GLint *boolParams = reinterpret_cast<GLint *>(targetData) + arrayElement * 4; GLint *boolParams = reinterpret_cast<GLint *>(targetData) + arrayElementOffset * 4;
for (GLint i = 0; i < count; i++) for (GLint i = 0; i < count; i++)
{ {
...@@ -2209,7 +2209,7 @@ void ProgramD3D::setUniformInternal(GLint location, GLsizei count, const T *v, G ...@@ -2209,7 +2209,7 @@ void ProgramD3D::setUniformInternal(GLint location, GLsizei count, const T *v, G
{ {
ASSERT(uniformType == GL_INT); ASSERT(uniformType == GL_INT);
size_t size = count * sizeof(T); size_t size = count * sizeof(T);
auto dest = &targetUniform->mSamplerData[locationInfo.element]; auto dest = &targetUniform->mSamplerData[locationInfo.flattenedArrayOffset];
if (memcmp(dest, v, size) != 0) if (memcmp(dest, v, size) != 0)
{ {
memcpy(dest, v, size); memcpy(dest, v, size);
...@@ -2248,12 +2248,13 @@ bool ProgramD3D::setUniformMatrixfvImpl(GLint location, ...@@ -2248,12 +2248,13 @@ bool ProgramD3D::setUniformMatrixfvImpl(GLint location,
D3DUniform *targetUniform = getD3DUniformFromLocation(location); D3DUniform *targetUniform = getD3DUniformFromLocation(location);
unsigned int elementCount = targetUniform->elementCount(); unsigned int elementCount = targetUniform->elementCount();
unsigned int arrayElement = mState.getUniformLocations()[location].element; unsigned int arrayElementOffset = mState.getUniformLocations()[location].flattenedArrayOffset;
unsigned int count = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn)); unsigned int count =
std::min(elementCount - arrayElementOffset, static_cast<unsigned int>(countIn));
const unsigned int targetMatrixStride = (4 * rows); const unsigned int targetMatrixStride = (4 * rows);
GLfloat *target = reinterpret_cast<GLfloat *>(targetData + arrayElement * sizeof(GLfloat) * GLfloat *target = reinterpret_cast<GLfloat *>(
targetMatrixStride); targetData + arrayElementOffset * sizeof(GLfloat) * targetMatrixStride);
bool dirty = false; bool dirty = false;
...@@ -2586,8 +2587,13 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyi ...@@ -2586,8 +2587,13 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyi
} }
else else
{ {
std::vector<unsigned int> subscripts;
std::string baseName = gl::ParseResourceName(tfVaryingName, &subscripts);
size_t subscript = GL_INVALID_INDEX; size_t subscript = GL_INVALID_INDEX;
std::string baseName = gl::ParseResourceName(tfVaryingName, &subscript); if (!subscripts.empty())
{
subscript = subscripts.back();
}
for (const auto &registerInfo : varyingPacking.getRegisterList()) for (const auto &registerInfo : varyingPacking.getRegisterList())
{ {
const auto &varying = *registerInfo.packedVarying->varying; const auto &varying = *registerInfo.packedVarying->varying;
...@@ -2694,7 +2700,8 @@ void ProgramD3D::getUniformInternal(GLint location, DestT *dataOut) const ...@@ -2694,7 +2700,8 @@ void ProgramD3D::getUniformInternal(GLint location, DestT *dataOut) const
const gl::LinkedUniform &uniform = mState.getUniforms()[locationInfo.index]; const gl::LinkedUniform &uniform = mState.getUniforms()[locationInfo.index];
const D3DUniform *targetUniform = getD3DUniformFromLocation(location); const D3DUniform *targetUniform = getD3DUniformFromLocation(location);
const uint8_t *srcPointer = targetUniform->getDataPtrToElement(locationInfo.element); const uint8_t *srcPointer = targetUniform->getDataPtrToElement(
locationInfo.arrayIndices.empty() ? 0u : locationInfo.flattenedArrayOffset);
if (gl::IsMatrixType(uniform.type)) if (gl::IsMatrixType(uniform.type))
{ {
......
...@@ -659,14 +659,18 @@ void ProgramGL::postLink() ...@@ -659,14 +659,18 @@ void ProgramGL::postLink()
continue; continue;
} }
// From the spec: // From the GLES 3.0.5 spec:
// "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; fullNameStr << uniform.mappedName;
if (uniform.isArray()) if (uniform.isArray())
{ {
fullNameStr << "[" << entry.element << "]"; for (auto arrayElementIndexIt = entry.arrayIndices.rbegin();
arrayElementIndexIt != entry.arrayIndices.rend(); ++arrayElementIndexIt)
{
fullNameStr << "[" << (*arrayElementIndexIt) << "]";
}
} }
const std::string &fullName = fullNameStr.str(); const std::string &fullName = fullNameStr.str();
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
'angle_unittests_sources': 'angle_unittests_sources':
[ [
'<(angle_path)/src/common/Optional_unittest.cpp', '<(angle_path)/src/common/Optional_unittest.cpp',
'<(angle_path)/src/common/angleutils_unittest.cpp',
'<(angle_path)/src/common/bitset_utils_unittest.cpp', '<(angle_path)/src/common/bitset_utils_unittest.cpp',
'<(angle_path)/src/common/mathutil_unittest.cpp', '<(angle_path)/src/common/mathutil_unittest.cpp',
'<(angle_path)/src/common/matrix_utils_unittest.cpp', '<(angle_path)/src/common/matrix_utils_unittest.cpp',
......
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