Commit a9042d3c by jchen10 Committed by Commit Bot

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: 's avatarCorentin Wallez <cwallez@chromium.org>
parent e839078e
...@@ -129,7 +129,33 @@ void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int co ...@@ -129,7 +129,33 @@ void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int co
// true if varying x has a higher priority in packing than y // true if varying x has a higher priority in packing than y
bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &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> template <typename VarT>
...@@ -171,6 +197,23 @@ void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSi ...@@ -171,6 +197,23 @@ void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSi
} }
} }
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 } // anonymous namespace
const char *const g_fakepath = "C:\\fakepath"; const char *const g_fakepath = "C:\\fakepath";
...@@ -692,7 +735,7 @@ Error Program::link(const gl::Context *context) ...@@ -692,7 +735,7 @@ Error Program::link(const gl::Context *context)
const auto &mergedVaryings = getMergedVaryings(); const auto &mergedVaryings = getMergedVaryings();
if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, caps)) if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps))
{ {
return NoError(); return NoError();
} }
...@@ -735,7 +778,7 @@ void Program::unlink() ...@@ -735,7 +778,7 @@ void Program::unlink()
{ {
mState.mAttributes.clear(); mState.mAttributes.clear();
mState.mActiveAttribLocationsMask.reset(); mState.mActiveAttribLocationsMask.reset();
mState.mTransformFeedbackVaryingVars.clear(); mState.mLinkedTransformFeedbackVaryings.clear();
mState.mUniforms.clear(); mState.mUniforms.clear();
mState.mUniformLocations.clear(); mState.mUniformLocations.clear();
mState.mUniformBlocks.clear(); mState.mUniformBlocks.clear();
...@@ -871,7 +914,7 @@ Error Program::loadBinary(const Context *context, ...@@ -871,7 +914,7 @@ Error Program::loadBinary(const Context *context,
} }
unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>(); unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
ASSERT(mState.mTransformFeedbackVaryingVars.empty()); ASSERT(mState.mLinkedTransformFeedbackVaryings.empty());
for (unsigned int transformFeedbackVaryingIndex = 0; for (unsigned int transformFeedbackVaryingIndex = 0;
transformFeedbackVaryingIndex < transformFeedbackVaryingCount; transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
++transformFeedbackVaryingIndex) ++transformFeedbackVaryingIndex)
...@@ -881,7 +924,9 @@ Error Program::loadBinary(const Context *context, ...@@ -881,7 +924,9 @@ Error Program::loadBinary(const Context *context,
stream.readInt(&varying.type); stream.readInt(&varying.type);
stream.readString(&varying.name); stream.readString(&varying.name);
mState.mTransformFeedbackVaryingVars.push_back(varying); GLuint arrayIndex = stream.readInt<GLuint>();
mState.mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
} }
stream.readInt(&mState.mTransformFeedbackBufferMode); stream.readInt(&mState.mTransformFeedbackBufferMode);
...@@ -1011,12 +1056,14 @@ Error Program::saveBinary(const Context *context, ...@@ -1011,12 +1056,14 @@ Error Program::saveBinary(const Context *context,
stream.writeInt(binding); stream.writeInt(binding);
} }
stream.writeInt(mState.mTransformFeedbackVaryingVars.size()); stream.writeInt(mState.mLinkedTransformFeedbackVaryings.size());
for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars) for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
{ {
stream.writeInt(varying.arraySize); stream.writeInt(var.arraySize);
stream.writeInt(varying.type); stream.writeInt(var.type);
stream.writeString(varying.name); stream.writeString(var.name);
stream.writeIntOrNegOne(var.arrayIndex);
} }
stream.writeInt(mState.mTransformFeedbackBufferMode); stream.writeInt(mState.mTransformFeedbackBufferMode);
...@@ -1840,24 +1887,25 @@ void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei ...@@ -1840,24 +1887,25 @@ void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei
{ {
if (mLinked) if (mLinked)
{ {
ASSERT(index < mState.mTransformFeedbackVaryingVars.size()); ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index]; const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length())); std::string varName = var.nameWithArrayIndex();
GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
if (length) if (length)
{ {
*length = lastNameIdx; *length = lastNameIdx;
} }
if (size) if (size)
{ {
*size = varying.elementCount(); *size = var.size();
} }
if (type) if (type)
{ {
*type = varying.type; *type = var.type;
} }
if (name) if (name)
{ {
memcpy(name, varying.name.c_str(), lastNameIdx); memcpy(name, varName.c_str(), lastNameIdx);
name[lastNameIdx] = '\0'; name[lastNameIdx] = '\0';
} }
} }
...@@ -1867,7 +1915,7 @@ GLsizei Program::getTransformFeedbackVaryingCount() const ...@@ -1867,7 +1915,7 @@ GLsizei Program::getTransformFeedbackVaryingCount() const
{ {
if (mLinked) if (mLinked)
{ {
return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size()); return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
} }
else else
{ {
...@@ -1880,9 +1928,10 @@ GLsizei Program::getTransformFeedbackVaryingMaxLength() const ...@@ -1880,9 +1928,10 @@ GLsizei Program::getTransformFeedbackVaryingMaxLength() const
if (mLinked) if (mLinked)
{ {
GLsizei maxSize = 0; 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; return maxSize;
...@@ -2427,7 +2476,8 @@ bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const ...@@ -2427,7 +2476,8 @@ bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const
return true; return true;
} }
bool Program::linkValidateTransformFeedback(InfoLog &infoLog, bool Program::linkValidateTransformFeedback(const gl::Context *context,
InfoLog &infoLog,
const Program::MergedVaryings &varyings, const Program::MergedVaryings &varyings,
const Caps &caps) const const Caps &caps) const
{ {
...@@ -2438,11 +2488,14 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, ...@@ -2438,11 +2488,14 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
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::string baseName = ParseResourceName(tfVaryingName, &subscript);
for (const auto &ref : varyings) for (const auto &ref : varyings)
{ {
const sh::Varying *varying = ref.second.get(); const sh::Varying *varying = ref.second.get();
if (tfVaryingName == varying->name) if (baseName == varying->name)
{ {
if (uniqueNames.count(tfVaryingName) > 0) if (uniqueNames.count(tfVaryingName) > 0)
{ {
...@@ -2450,16 +2503,29 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, ...@@ -2450,16 +2503,29 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
<< tfVaryingName << ")."; << tfVaryingName << ").";
return false; return false;
} }
uniqueNames.insert(tfVaryingName); if (context->getClientVersion() >= Version(3, 1))
{
if (varying->isArray()) 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."; infoLog << "Capture of arrays is undefined and not supported.";
return false; return false;
} }
uniqueNames.insert(tfVaryingName);
// TODO(jmadill): Investigate implementation limits on D3D11 // 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 && if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
componentCount > caps.maxTransformFeedbackSeparateComponents) componentCount > caps.maxTransformFeedbackSeparateComponents)
{ {
...@@ -2474,13 +2540,12 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, ...@@ -2474,13 +2540,12 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
break; break;
} }
} }
if (context->getClientVersion() < Version(3, 1) &&
if (tfVaryingName.find('[') != std::string::npos) tfVaryingName.find('[') != std::string::npos)
{ {
infoLog << "Capture of array elements is undefined and not supported."; infoLog << "Capture of array elements is undefined and not supported.";
return false; return false;
} }
// All transform feedback varyings are expected to exist since packVaryings checks for them. // All transform feedback varyings are expected to exist since packVaryings checks for them.
ASSERT(found); ASSERT(found);
} }
...@@ -2500,15 +2565,18 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, ...@@ -2500,15 +2565,18 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings) void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
{ {
// Gather the linked varyings that are used for transform feedback, they should all exist. // 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) for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
{ {
size_t subscript = GL_INVALID_INDEX;
std::string baseName = ParseResourceName(tfVaryingName, &subscript);
for (const auto &ref : varyings) for (const auto &ref : varyings)
{ {
const sh::Varying *varying = ref.second.get(); 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; break;
} }
} }
...@@ -2537,6 +2605,7 @@ std::vector<PackedVarying> Program::getPackedVaryings( ...@@ -2537,6 +2605,7 @@ std::vector<PackedVarying> Program::getPackedVaryings(
{ {
const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames(); const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
std::vector<PackedVarying> packedVaryings; std::vector<PackedVarying> packedVaryings;
std::set<std::string> uniqueFullNames;
for (const auto &ref : mergedVaryings) for (const auto &ref : mergedVaryings)
{ {
...@@ -2574,7 +2643,13 @@ std::vector<PackedVarying> Program::getPackedVaryings( ...@@ -2574,7 +2643,13 @@ std::vector<PackedVarying> Program::getPackedVaryings(
for (const std::string &tfVarying : tfVaryings) 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. // Transform feedback for varying structs is underspecified.
// See Khronos bug 9856. // See Khronos bug 9856.
...@@ -2583,11 +2658,16 @@ std::vector<PackedVarying> Program::getPackedVaryings( ...@@ -2583,11 +2658,16 @@ std::vector<PackedVarying> Program::getPackedVaryings(
{ {
packedVaryings.push_back(PackedVarying(*input, input->interpolation)); packedVaryings.push_back(PackedVarying(*input, input->interpolation));
packedVaryings.back().vertexOnly = true; packedVaryings.back().vertexOnly = true;
packedVaryings.back().arrayIndex = static_cast<GLuint>(subscript);
uniqueFullNames.insert(tfVarying);
} }
if (subscript == GL_INVALID_INDEX)
{
break; break;
} }
} }
} }
}
std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying); std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
......
...@@ -175,6 +175,29 @@ struct SamplerBinding ...@@ -175,6 +175,29 @@ struct SamplerBinding
std::vector<GLuint> boundTextureUnits; std::vector<GLuint> boundTextureUnits;
}; };
// A varying with tranform feedback enabled. If it's an array, either the whole array or one of its
// elements specified by 'arrayIndex' can set to be enabled.
struct TransformFeedbackVarying : public sh::Varying
{
TransformFeedbackVarying(const sh::Varying &varyingIn, GLuint index)
: sh::Varying(varyingIn), arrayIndex(index)
{
}
std::string nameWithArrayIndex() const
{
std::stringstream fullNameStr;
fullNameStr << name;
if (arrayIndex != GL_INVALID_INDEX)
{
fullNameStr << "[" << arrayIndex << "]";
}
return fullNameStr.str();
}
GLsizei size() const { return (arrayIndex == GL_INVALID_INDEX ? elementCount() : 1); }
GLuint arrayIndex;
};
class ProgramState final : angle::NonCopyable class ProgramState final : angle::NonCopyable
{ {
public: public:
...@@ -230,7 +253,7 @@ class ProgramState final : angle::NonCopyable ...@@ -230,7 +253,7 @@ class ProgramState final : angle::NonCopyable
Shader *mAttachedComputeShader; Shader *mAttachedComputeShader;
std::vector<std::string> mTransformFeedbackVaryingNames; std::vector<std::string> mTransformFeedbackVaryingNames;
std::vector<sh::Varying> mTransformFeedbackVaryingVars; std::vector<TransformFeedbackVarying> mLinkedTransformFeedbackVaryings;
GLenum mTransformFeedbackBufferMode; GLenum mTransformFeedbackBufferMode;
std::array<GLuint, IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS> mUniformBlockBindings; std::array<GLuint, IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS> mUniformBlockBindings;
...@@ -480,7 +503,8 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -480,7 +503,8 @@ class Program final : angle::NonCopyable, public LabeledObject
const sh::Varying &fragmentVarying, const sh::Varying &fragmentVarying,
int shaderVersion); int shaderVersion);
bool linkValidateBuiltInVaryings(InfoLog &infoLog) const; bool linkValidateBuiltInVaryings(InfoLog &infoLog) const;
bool linkValidateTransformFeedback(InfoLog &infoLog, bool linkValidateTransformFeedback(const gl::Context *context,
InfoLog &infoLog,
const MergedVaryings &linkedVaryings, const MergedVaryings &linkedVaryings,
const Caps &caps) const; const Caps &caps) const;
......
...@@ -48,7 +48,7 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying) ...@@ -48,7 +48,7 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
} }
// "Arrays of size N are assumed to take N times the size of the base type" // "Arrays of size N are assumed to take N times the size of the base type"
varyingRows *= varying.elementCount(); varyingRows *= (packedVarying.isArrayElement() ? 1 : varying.elementCount());
unsigned int maxVaryingVectors = static_cast<unsigned int>(mRegisterMap.size()); unsigned int maxVaryingVectors = static_cast<unsigned int>(mRegisterMap.size());
...@@ -142,7 +142,8 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying) ...@@ -142,7 +142,8 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
registerInfo.packedVarying = &packedVarying; registerInfo.packedVarying = &packedVarying;
registerInfo.registerRow = row + arrayIndex; registerInfo.registerRow = row + arrayIndex;
registerInfo.registerColumn = bestColumn; registerInfo.registerColumn = bestColumn;
registerInfo.varyingArrayIndex = arrayIndex; registerInfo.varyingArrayIndex =
(packedVarying.isArrayElement() ? packedVarying.arrayIndex : arrayIndex);
registerInfo.varyingRowIndex = 0; registerInfo.varyingRowIndex = 0;
// Do not record register info for builtins. // Do not record register info for builtins.
// TODO(jmadill): Clean this up. // TODO(jmadill): Clean this up.
...@@ -201,6 +202,10 @@ void VaryingPacking::insert(unsigned int registerRow, ...@@ -201,6 +202,10 @@ void VaryingPacking::insert(unsigned int registerRow,
for (unsigned int arrayElement = 0; arrayElement < varying.elementCount(); ++arrayElement) for (unsigned int arrayElement = 0; arrayElement < varying.elementCount(); ++arrayElement)
{ {
if (packedVarying.isArrayElement() && arrayElement != packedVarying.arrayIndex)
{
continue;
}
for (unsigned int varyingRow = 0; varyingRow < varyingRows; ++varyingRow) for (unsigned int varyingRow = 0; varyingRow < varyingRows; ++varyingRow)
{ {
registerInfo.registerRow = registerRow + (arrayElement * varyingRows) + varyingRow; registerInfo.registerRow = registerRow + (arrayElement * varyingRows) + varyingRow;
...@@ -241,15 +246,15 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog, ...@@ -241,15 +246,15 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
} }
ASSERT(!varying.isStruct()); ASSERT(!varying.isStruct());
ASSERT(uniqueVaryingNames.count(varying.name) == 0); ASSERT(uniqueVaryingNames.count(packedVarying.nameWithArrayIndex()) == 0);
if (packVarying(packedVarying)) if (packVarying(packedVarying))
{ {
uniqueVaryingNames.insert(varying.name); uniqueVaryingNames.insert(packedVarying.nameWithArrayIndex());
} }
else else
{ {
infoLog << "Could not pack varying " << varying.name; infoLog << "Could not pack varying " << packedVarying.nameWithArrayIndex();
return false; return false;
} }
} }
...@@ -266,22 +271,25 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog, ...@@ -266,22 +271,25 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
for (const PackedVarying &packedVarying : packedVaryings) for (const PackedVarying &packedVarying : packedVaryings)
{ {
const auto &varying = *packedVarying.varying; const auto &varying = *packedVarying.varying;
size_t subscript = GL_INVALID_INDEX;
std::string baseName = ParseResourceName(transformFeedbackVaryingName, &subscript);
// Make sure transform feedback varyings aren't optimized out. // Make sure transform feedback varyings aren't optimized out.
if (uniqueVaryingNames.count(transformFeedbackVaryingName) > 0) if (uniqueVaryingNames.count(transformFeedbackVaryingName) > 0 ||
uniqueVaryingNames.count(baseName) > 0)
{ {
found = true; found = true;
break; break;
} }
if (transformFeedbackVaryingName == varying.name) if (baseName == varying.name)
{ {
if (!packVarying(packedVarying)) if (!packVarying(packedVarying))
{ {
infoLog << "Could not pack varying " << varying.name; infoLog << "Could not pack varying " << varying.name;
return false; return false;
} }
uniqueVaryingNames.insert(packedVarying.nameWithArrayIndex());
found = true; found = true;
break; break;
} }
......
...@@ -24,7 +24,7 @@ class InfoLog; ...@@ -24,7 +24,7 @@ class InfoLog;
struct PackedVarying struct PackedVarying
{ {
PackedVarying(const sh::ShaderVariable &varyingIn, sh::InterpolationType interpolationIn) PackedVarying(const sh::ShaderVariable &varyingIn, sh::InterpolationType interpolationIn)
: varying(&varyingIn), vertexOnly(false), interpolation(interpolationIn) : PackedVarying(varyingIn, interpolationIn, "")
{ {
} }
PackedVarying(const sh::ShaderVariable &varyingIn, PackedVarying(const sh::ShaderVariable &varyingIn,
...@@ -33,12 +33,26 @@ struct PackedVarying ...@@ -33,12 +33,26 @@ struct PackedVarying
: varying(&varyingIn), : varying(&varyingIn),
vertexOnly(false), vertexOnly(false),
interpolation(interpolationIn), interpolation(interpolationIn),
parentStructName(parentStructNameIn) parentStructName(parentStructNameIn),
arrayIndex(GL_INVALID_INDEX)
{ {
} }
bool isStructField() const { return !parentStructName.empty(); } bool isStructField() const { return !parentStructName.empty(); }
bool isArrayElement() const { return arrayIndex != GL_INVALID_INDEX; }
std::string nameWithArrayIndex() const
{
std::stringstream fullNameStr;
fullNameStr << varying->name;
if (arrayIndex != GL_INVALID_INDEX)
{
fullNameStr << "[" << arrayIndex << "]";
}
return fullNameStr.str();
}
const sh::ShaderVariable *varying; const sh::ShaderVariable *varying;
// Transform feedback varyings can be only referenced in the VS. // Transform feedback varyings can be only referenced in the VS.
...@@ -49,6 +63,8 @@ struct PackedVarying ...@@ -49,6 +63,8 @@ struct PackedVarying
// Struct name // Struct name
std::string parentStructName; std::string parentStructName;
GLuint arrayIndex;
}; };
struct PackedVaryingRegister final struct PackedVaryingRegister final
......
...@@ -2415,6 +2415,8 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyi ...@@ -2415,6 +2415,8 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyi
} }
else else
{ {
size_t subscript = GL_INVALID_INDEX;
std::string baseName = gl::ParseResourceName(tfVaryingName, &subscript);
for (const auto &registerInfo : varyingPacking.getRegisterList()) for (const auto &registerInfo : varyingPacking.getRegisterList())
{ {
const auto &varying = *registerInfo.packedVarying->varying; const auto &varying = *registerInfo.packedVarying->varying;
...@@ -2430,7 +2432,8 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyi ...@@ -2430,7 +2432,8 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyi
// There can be more than one register assigned to a particular varying, and each // There can be more than one register assigned to a particular varying, and each
// register needs its own stream out entry. // register needs its own stream out entry.
if (tfVaryingName == varying.name) if (baseName == registerInfo.packedVarying->varying->name &&
(subscript == GL_INVALID_INDEX || subscript == registerInfo.varyingArrayIndex))
{ {
mStreamOutVaryings.push_back(D3DVarying( mStreamOutVaryings.push_back(D3DVarying(
varyingSemantic, registerInfo.semanticIndex, componentCount, outputSlot)); varyingSemantic, registerInfo.semanticIndex, componentCount, outputSlot));
......
...@@ -12,13 +12,10 @@ using namespace angle; ...@@ -12,13 +12,10 @@ using namespace angle;
namespace namespace
{ {
class TransformFeedbackTest : public ANGLETest class TransformFeedbackTestBase : public ANGLETest
{ {
protected: protected:
TransformFeedbackTest() TransformFeedbackTestBase() : mProgram(0), mTransformFeedbackBuffer(0), mTransformFeedback(0)
: mProgram(0),
mTransformFeedbackBuffer(0),
mTransformFeedback(0)
{ {
setWindowWidth(128); setWindowWidth(128);
setWindowHeight(128); setWindowHeight(128);
...@@ -65,6 +62,16 @@ class TransformFeedbackTest : public ANGLETest ...@@ -65,6 +62,16 @@ class TransformFeedbackTest : public ANGLETest
ANGLETest::TearDown(); ANGLETest::TearDown();
} }
GLuint mProgram;
static const size_t mTransformFeedbackBufferSize = 1 << 24;
GLuint mTransformFeedbackBuffer;
GLuint mTransformFeedback;
};
class TransformFeedbackTest : public TransformFeedbackTestBase
{
protected:
void compileDefaultProgram(const std::vector<std::string> &tfVaryings, GLenum bufferMode) void compileDefaultProgram(const std::vector<std::string> &tfVaryings, GLenum bufferMode)
{ {
ASSERT_EQ(0u, mProgram); ASSERT_EQ(0u, mProgram);
...@@ -94,12 +101,6 @@ class TransformFeedbackTest : public ANGLETest ...@@ -94,12 +101,6 @@ class TransformFeedbackTest : public ANGLETest
tfVaryings, bufferMode); tfVaryings, bufferMode);
ASSERT_NE(0u, mProgram); ASSERT_NE(0u, mProgram);
} }
GLuint mProgram;
static const size_t mTransformFeedbackBufferSize = 1 << 24;
GLuint mTransformFeedbackBuffer;
GLuint mTransformFeedback;
}; };
TEST_P(TransformFeedbackTest, ZeroSizedViewport) TEST_P(TransformFeedbackTest, ZeroSizedViewport)
...@@ -414,6 +415,7 @@ TEST_P(TransformFeedbackTest, VertexOnly) ...@@ -414,6 +415,7 @@ TEST_P(TransformFeedbackTest, VertexOnly)
{ {
EXPECT_EQ(attribData[cnt], mappedFloats[cnt]); EXPECT_EQ(attribData[cnt], mappedFloats[cnt]);
} }
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
...@@ -775,6 +777,7 @@ TEST_P(TransformFeedbackTest, PackingBug) ...@@ -775,6 +777,7 @@ TEST_P(TransformFeedbackTest, PackingBug)
EXPECT_EQ(attrib1Data[vectorIndex], vecPointer[stream1Index]); EXPECT_EQ(attrib1Data[vectorIndex], vecPointer[stream1Index]);
EXPECT_EQ(attrib2Data[vectorIndex], vecPointer[stream2Index]); EXPECT_EQ(attrib2Data[vectorIndex], vecPointer[stream2Index]);
} }
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
...@@ -875,7 +878,7 @@ TEST_P(TransformFeedbackTest, TwoUnreferencedInFragShader) ...@@ -875,7 +878,7 @@ TEST_P(TransformFeedbackTest, TwoUnreferencedInFragShader)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
const GLvoid *mapPointer = const GLvoid *mapPointer =
glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector2) * 2 * 6, GL_MAP_READ_BIT); glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector3) * 2 * 6, GL_MAP_READ_BIT);
ASSERT_NE(nullptr, mapPointer); ASSERT_NE(nullptr, mapPointer);
const auto &quadVertices = GetQuadVertices(); const auto &quadVertices = GetQuadVertices();
...@@ -888,9 +891,11 @@ TEST_P(TransformFeedbackTest, TwoUnreferencedInFragShader) ...@@ -888,9 +891,11 @@ TEST_P(TransformFeedbackTest, TwoUnreferencedInFragShader)
EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream1Index]); EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream1Index]);
EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream2Index]); EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream2Index]);
} }
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
class TransformFeedbackLifetimeTest : public TransformFeedbackTest class TransformFeedbackLifetimeTest : public TransformFeedbackTest
{ {
protected: protected:
...@@ -979,8 +984,108 @@ TEST_P(TransformFeedbackLifetimeTest, DeletedBuffer) ...@@ -979,8 +984,108 @@ TEST_P(TransformFeedbackLifetimeTest, DeletedBuffer)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
class TransformFeedbackTestES31 : public TransformFeedbackTestBase
{
};
// Test that program link fails in case that transform feedback names including same array element.
TEST_P(TransformFeedbackTestES31, SameArrayElementVaryings)
{
const std::string &vertexShaderSource =
"#version 310 es\n"
"in vec3 position;\n"
"out vec3 outAttribs[3];\n"
"void main() {"
" outAttribs[0] = position;\n"
" outAttribs[1] = vec3(0, 0, 0);\n"
" outAttribs[2] = position;\n"
" gl_Position = vec4(position, 1);\n"
"}";
const std::string &fragmentShaderSource =
"#version 310 es\n"
"precision mediump float;\n"
"out vec4 color;\n"
"in vec3 outAttribs[3];\n"
"void main() {\n"
" color = vec4(0);\n"
"}";
std::vector<std::string> tfVaryings;
tfVaryings.push_back("outAttribs");
tfVaryings.push_back("outAttribs[1]");
mProgram = CompileProgramWithTransformFeedback(vertexShaderSource, fragmentShaderSource,
tfVaryings, GL_INTERLEAVED_ATTRIBS);
ASSERT_EQ(0u, mProgram);
}
// Test transform feedback names can be specified using array element.
TEST_P(TransformFeedbackTestES31, DifferentArrayElementVaryings)
{
const std::string &vertexShaderSource =
"#version 310 es\n"
"in vec3 position;\n"
"out vec3 outAttribs[3];\n"
"void main() {"
" outAttribs[0] = position;\n"
" outAttribs[1] = vec3(0, 0, 0);\n"
" outAttribs[2] = position;\n"
" gl_Position = vec4(position, 1);\n"
"}";
const std::string &fragmentShaderSource =
"#version 310 es\n"
"precision mediump float;\n"
"out vec4 color;\n"
"in vec3 outAttribs[3];\n"
"void main() {\n"
" color = vec4(0);\n"
"}";
std::vector<std::string> tfVaryings;
tfVaryings.push_back("outAttribs[0]");
tfVaryings.push_back("outAttribs[2]");
mProgram = CompileProgramWithTransformFeedback(vertexShaderSource, fragmentShaderSource,
tfVaryings, GL_INTERLEAVED_ATTRIBS);
ASSERT_NE(0u, mProgram);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(Vector3) * 2 * 6, nullptr, GL_STREAM_DRAW);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glUseProgram(mProgram);
glBeginTransformFeedback(GL_TRIANGLES);
drawQuad(mProgram, "position", 0.5f);
glEndTransformFeedback();
glUseProgram(0);
ASSERT_GL_NO_ERROR();
const GLvoid *mapPointer =
glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector3) * 2 * 6, GL_MAP_READ_BIT);
ASSERT_NE(nullptr, mapPointer);
const auto &quadVertices = GetQuadVertices();
const Vector3 *vecPointer = static_cast<const Vector3 *>(mapPointer);
for (unsigned int vectorIndex = 0; vectorIndex < 3; ++vectorIndex)
{
unsigned int stream1Index = vectorIndex * 2;
unsigned int stream2Index = vectorIndex * 2 + 1;
EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream1Index]);
EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream2Index]);
}
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
ASSERT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(TransformFeedbackTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(TransformFeedbackTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(TransformFeedbackLifetimeTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(TransformFeedbackLifetimeTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(TransformFeedbackTestES31, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
} // anonymous namespace } // anonymous namespace
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