ES31: Add array element transformfeedback
This enhances the PackedVarying to be either one element of array, or
whole array. Correspondingly the VaryingPacking is expanded to pack it
properly.
BUG=angleproject:1950
Change-Id: I0529d7ac4367d42b2b433410fbf08351412aada8
Reviewed-on: https://chromium-review.googlesource.com/459115
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index ebedc4b..037283b 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -129,7 +129,33 @@
// true if varying x has a higher priority in packing than y
bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
{
- return gl::CompareShaderVar(*x.varying, *y.varying);
+ // If the PackedVarying 'x' or 'y' to be compared is an array element, this clones an equivalent
+ // non-array shader variable 'vx' or 'vy' for actual comparison instead.
+ sh::ShaderVariable vx, vy;
+ const sh::ShaderVariable *px, *py;
+ if (x.isArrayElement())
+ {
+ vx = *x.varying;
+ vx.arraySize = 0;
+ px = &vx;
+ }
+ else
+ {
+ px = x.varying;
+ }
+
+ if (y.isArrayElement())
+ {
+ vy = *y.varying;
+ vy.arraySize = 0;
+ py = &vy;
+ }
+ else
+ {
+ py = y.varying;
+ }
+
+ return gl::CompareShaderVar(*px, *py);
}
template <typename VarT>
@@ -171,6 +197,23 @@
}
}
+bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
+{
+ size_t subscript = GL_INVALID_INDEX;
+ std::string baseName = ParseResourceName(name, &subscript);
+ for (auto it = nameSet.begin(); it != nameSet.end(); ++it)
+ {
+ size_t arrayIndex = GL_INVALID_INDEX;
+ std::string arrayName = ParseResourceName(*it, &arrayIndex);
+ if (baseName == arrayName && (subscript == GL_INVALID_INDEX ||
+ arrayIndex == GL_INVALID_INDEX || subscript == arrayIndex))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
} // anonymous namespace
const char *const g_fakepath = "C:\\fakepath";
@@ -692,7 +735,7 @@
const auto &mergedVaryings = getMergedVaryings();
- if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, caps))
+ if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps))
{
return NoError();
}
@@ -735,7 +778,7 @@
{
mState.mAttributes.clear();
mState.mActiveAttribLocationsMask.reset();
- mState.mTransformFeedbackVaryingVars.clear();
+ mState.mLinkedTransformFeedbackVaryings.clear();
mState.mUniforms.clear();
mState.mUniformLocations.clear();
mState.mUniformBlocks.clear();
@@ -871,7 +914,7 @@
}
unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
- ASSERT(mState.mTransformFeedbackVaryingVars.empty());
+ ASSERT(mState.mLinkedTransformFeedbackVaryings.empty());
for (unsigned int transformFeedbackVaryingIndex = 0;
transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
++transformFeedbackVaryingIndex)
@@ -881,7 +924,9 @@
stream.readInt(&varying.type);
stream.readString(&varying.name);
- mState.mTransformFeedbackVaryingVars.push_back(varying);
+ GLuint arrayIndex = stream.readInt<GLuint>();
+
+ mState.mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
}
stream.readInt(&mState.mTransformFeedbackBufferMode);
@@ -1011,12 +1056,14 @@
stream.writeInt(binding);
}
- stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
- for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
+ stream.writeInt(mState.mLinkedTransformFeedbackVaryings.size());
+ for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
{
- stream.writeInt(varying.arraySize);
- stream.writeInt(varying.type);
- stream.writeString(varying.name);
+ stream.writeInt(var.arraySize);
+ stream.writeInt(var.type);
+ stream.writeString(var.name);
+
+ stream.writeIntOrNegOne(var.arrayIndex);
}
stream.writeInt(mState.mTransformFeedbackBufferMode);
@@ -1840,24 +1887,25 @@
{
if (mLinked)
{
- ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
- const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
- GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
+ ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
+ const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
+ std::string varName = var.nameWithArrayIndex();
+ GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
if (length)
{
*length = lastNameIdx;
}
if (size)
{
- *size = varying.elementCount();
+ *size = var.size();
}
if (type)
{
- *type = varying.type;
+ *type = var.type;
}
if (name)
{
- memcpy(name, varying.name.c_str(), lastNameIdx);
+ memcpy(name, varName.c_str(), lastNameIdx);
name[lastNameIdx] = '\0';
}
}
@@ -1867,7 +1915,7 @@
{
if (mLinked)
{
- return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
+ return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
}
else
{
@@ -1880,9 +1928,10 @@
if (mLinked)
{
GLsizei maxSize = 0;
- for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
+ for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
{
- maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
+ maxSize =
+ std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
}
return maxSize;
@@ -2427,7 +2476,8 @@
return true;
}
-bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
+bool Program::linkValidateTransformFeedback(const gl::Context *context,
+ InfoLog &infoLog,
const Program::MergedVaryings &varyings,
const Caps &caps) const
{
@@ -2438,11 +2488,14 @@
for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
{
bool found = false;
+ size_t subscript = GL_INVALID_INDEX;
+ std::string baseName = ParseResourceName(tfVaryingName, &subscript);
+
for (const auto &ref : varyings)
{
const sh::Varying *varying = ref.second.get();
- if (tfVaryingName == varying->name)
+ if (baseName == varying->name)
{
if (uniqueNames.count(tfVaryingName) > 0)
{
@@ -2450,16 +2503,29 @@
<< tfVaryingName << ").";
return false;
}
- uniqueNames.insert(tfVaryingName);
-
- if (varying->isArray())
+ if (context->getClientVersion() >= Version(3, 1))
+ {
+ if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
+ {
+ infoLog
+ << "Two transform feedback varyings include the same array element ("
+ << tfVaryingName << ").";
+ return false;
+ }
+ }
+ else if (varying->isArray())
{
infoLog << "Capture of arrays is undefined and not supported.";
return false;
}
+ uniqueNames.insert(tfVaryingName);
+
// TODO(jmadill): Investigate implementation limits on D3D11
- size_t componentCount = VariableComponentCount(varying->type);
+ size_t elementCount =
+ ((varying->isArray() && subscript == GL_INVALID_INDEX) ? varying->elementCount()
+ : 1);
+ size_t componentCount = VariableComponentCount(varying->type) * elementCount;
if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
componentCount > caps.maxTransformFeedbackSeparateComponents)
{
@@ -2474,13 +2540,12 @@
break;
}
}
-
- if (tfVaryingName.find('[') != std::string::npos)
+ if (context->getClientVersion() < Version(3, 1) &&
+ tfVaryingName.find('[') != std::string::npos)
{
infoLog << "Capture of array elements is undefined and not supported.";
return false;
}
-
// All transform feedback varyings are expected to exist since packVaryings checks for them.
ASSERT(found);
}
@@ -2500,15 +2565,18 @@
void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
{
// Gather the linked varyings that are used for transform feedback, they should all exist.
- mState.mTransformFeedbackVaryingVars.clear();
+ mState.mLinkedTransformFeedbackVaryings.clear();
for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
{
+ size_t subscript = GL_INVALID_INDEX;
+ std::string baseName = ParseResourceName(tfVaryingName, &subscript);
for (const auto &ref : varyings)
{
const sh::Varying *varying = ref.second.get();
- if (tfVaryingName == varying->name)
+ if (baseName == varying->name)
{
- mState.mTransformFeedbackVaryingVars.push_back(*varying);
+ mState.mLinkedTransformFeedbackVaryings.emplace_back(
+ *varying, static_cast<GLuint>(subscript));
break;
}
}
@@ -2537,6 +2605,7 @@
{
const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
std::vector<PackedVarying> packedVaryings;
+ std::set<std::string> uniqueFullNames;
for (const auto &ref : mergedVaryings)
{
@@ -2574,7 +2643,13 @@
for (const std::string &tfVarying : tfVaryings)
{
- if (tfVarying == input->name)
+ size_t subscript = GL_INVALID_INDEX;
+ std::string baseName = ParseResourceName(tfVarying, &subscript);
+ if (uniqueFullNames.count(tfVarying) > 0)
+ {
+ continue;
+ }
+ if (baseName == input->name)
{
// Transform feedback for varying structs is underspecified.
// See Khronos bug 9856.
@@ -2583,8 +2658,13 @@
{
packedVaryings.push_back(PackedVarying(*input, input->interpolation));
packedVaryings.back().vertexOnly = true;
+ packedVaryings.back().arrayIndex = static_cast<GLuint>(subscript);
+ uniqueFullNames.insert(tfVarying);
}
- break;
+ if (subscript == GL_INVALID_INDEX)
+ {
+ break;
+ }
}
}
}