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
// 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 @@ 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
const char *const g_fakepath = "C:\\fakepath";
......@@ -692,7 +735,7 @@ Error Program::link(const gl::Context *context)
const auto &mergedVaryings = getMergedVaryings();
if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, caps))
if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps))
{
return NoError();
}
......@@ -735,7 +778,7 @@ void Program::unlink()
{
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 @@ Error Program::loadBinary(const Context *context,
}
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 @@ Error Program::loadBinary(const Context *context,
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 @@ Error Program::saveBinary(const Context *context,
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 @@ void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei
{
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 @@ GLsizei Program::getTransformFeedbackVaryingCount() const
{
if (mLinked)
{
return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
}
else
{
......@@ -1880,9 +1928,10 @@ GLsizei Program::getTransformFeedbackVaryingMaxLength() const
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 @@ bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const
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 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
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 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
<< 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 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
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 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
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 @@ std::vector<PackedVarying> Program::getPackedVaryings(
{
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 @@ std::vector<PackedVarying> Program::getPackedVaryings(
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 @@ std::vector<PackedVarying> Program::getPackedVaryings(
{
packedVaryings.push_back(PackedVarying(*input, input->interpolation));
packedVaryings.back().vertexOnly = true;
packedVaryings.back().arrayIndex = static_cast<GLuint>(subscript);
uniqueFullNames.insert(tfVarying);
}
if (subscript == GL_INVALID_INDEX)
{
break;
}
break;
}
}
}
......
......@@ -175,6 +175,29 @@ struct SamplerBinding
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
{
public:
......@@ -230,7 +253,7 @@ class ProgramState final : angle::NonCopyable
Shader *mAttachedComputeShader;
std::vector<std::string> mTransformFeedbackVaryingNames;
std::vector<sh::Varying> mTransformFeedbackVaryingVars;
std::vector<TransformFeedbackVarying> mLinkedTransformFeedbackVaryings;
GLenum mTransformFeedbackBufferMode;
std::array<GLuint, IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS> mUniformBlockBindings;
......@@ -480,7 +503,8 @@ class Program final : angle::NonCopyable, public LabeledObject
const sh::Varying &fragmentVarying,
int shaderVersion);
bool linkValidateBuiltInVaryings(InfoLog &infoLog) const;
bool linkValidateTransformFeedback(InfoLog &infoLog,
bool linkValidateTransformFeedback(const gl::Context *context,
InfoLog &infoLog,
const MergedVaryings &linkedVaryings,
const Caps &caps) const;
......
......@@ -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"
varyingRows *= varying.elementCount();
varyingRows *= (packedVarying.isArrayElement() ? 1 : varying.elementCount());
unsigned int maxVaryingVectors = static_cast<unsigned int>(mRegisterMap.size());
......@@ -142,7 +142,8 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
registerInfo.packedVarying = &packedVarying;
registerInfo.registerRow = row + arrayIndex;
registerInfo.registerColumn = bestColumn;
registerInfo.varyingArrayIndex = arrayIndex;
registerInfo.varyingArrayIndex =
(packedVarying.isArrayElement() ? packedVarying.arrayIndex : arrayIndex);
registerInfo.varyingRowIndex = 0;
// Do not record register info for builtins.
// TODO(jmadill): Clean this up.
......@@ -201,6 +202,10 @@ void VaryingPacking::insert(unsigned int registerRow,
for (unsigned int arrayElement = 0; arrayElement < varying.elementCount(); ++arrayElement)
{
if (packedVarying.isArrayElement() && arrayElement != packedVarying.arrayIndex)
{
continue;
}
for (unsigned int varyingRow = 0; varyingRow < varyingRows; ++varyingRow)
{
registerInfo.registerRow = registerRow + (arrayElement * varyingRows) + varyingRow;
......@@ -241,15 +246,15 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
}
ASSERT(!varying.isStruct());
ASSERT(uniqueVaryingNames.count(varying.name) == 0);
ASSERT(uniqueVaryingNames.count(packedVarying.nameWithArrayIndex()) == 0);
if (packVarying(packedVarying))
{
uniqueVaryingNames.insert(varying.name);
uniqueVaryingNames.insert(packedVarying.nameWithArrayIndex());
}
else
{
infoLog << "Could not pack varying " << varying.name;
infoLog << "Could not pack varying " << packedVarying.nameWithArrayIndex();
return false;
}
}
......@@ -266,22 +271,25 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
for (const PackedVarying &packedVarying : packedVaryings)
{
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.
if (uniqueVaryingNames.count(transformFeedbackVaryingName) > 0)
if (uniqueVaryingNames.count(transformFeedbackVaryingName) > 0 ||
uniqueVaryingNames.count(baseName) > 0)
{
found = true;
break;
}
if (transformFeedbackVaryingName == varying.name)
if (baseName == varying.name)
{
if (!packVarying(packedVarying))
{
infoLog << "Could not pack varying " << varying.name;
return false;
}
uniqueVaryingNames.insert(packedVarying.nameWithArrayIndex());
found = true;
break;
}
......
......@@ -24,7 +24,7 @@ class InfoLog;
struct PackedVarying
{
PackedVarying(const sh::ShaderVariable &varyingIn, sh::InterpolationType interpolationIn)
: varying(&varyingIn), vertexOnly(false), interpolation(interpolationIn)
: PackedVarying(varyingIn, interpolationIn, "")
{
}
PackedVarying(const sh::ShaderVariable &varyingIn,
......@@ -33,12 +33,26 @@ struct PackedVarying
: varying(&varyingIn),
vertexOnly(false),
interpolation(interpolationIn),
parentStructName(parentStructNameIn)
parentStructName(parentStructNameIn),
arrayIndex(GL_INVALID_INDEX)
{
}
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;
// Transform feedback varyings can be only referenced in the VS.
......@@ -49,6 +63,8 @@ struct PackedVarying
// Struct name
std::string parentStructName;
GLuint arrayIndex;
};
struct PackedVaryingRegister final
......
......@@ -2415,6 +2415,8 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyi
}
else
{
size_t subscript = GL_INVALID_INDEX;
std::string baseName = gl::ParseResourceName(tfVaryingName, &subscript);
for (const auto &registerInfo : varyingPacking.getRegisterList())
{
const auto &varying = *registerInfo.packedVarying->varying;
......@@ -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
// 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(
varyingSemantic, registerInfo.semanticIndex, componentCount, outputSlot));
......
......@@ -12,13 +12,10 @@ using namespace angle;
namespace
{
class TransformFeedbackTest : public ANGLETest
class TransformFeedbackTestBase : public ANGLETest
{
protected:
TransformFeedbackTest()
: mProgram(0),
mTransformFeedbackBuffer(0),
mTransformFeedback(0)
TransformFeedbackTestBase() : mProgram(0), mTransformFeedbackBuffer(0), mTransformFeedback(0)
{
setWindowWidth(128);
setWindowHeight(128);
......@@ -65,6 +62,16 @@ class TransformFeedbackTest : public ANGLETest
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)
{
ASSERT_EQ(0u, mProgram);
......@@ -94,12 +101,6 @@ class TransformFeedbackTest : public ANGLETest
tfVaryings, bufferMode);
ASSERT_NE(0u, mProgram);
}
GLuint mProgram;
static const size_t mTransformFeedbackBufferSize = 1 << 24;
GLuint mTransformFeedbackBuffer;
GLuint mTransformFeedback;
};
TEST_P(TransformFeedbackTest, ZeroSizedViewport)
......@@ -414,6 +415,7 @@ TEST_P(TransformFeedbackTest, VertexOnly)
{
EXPECT_EQ(attribData[cnt], mappedFloats[cnt]);
}
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
EXPECT_GL_NO_ERROR();
}
......@@ -775,6 +777,7 @@ TEST_P(TransformFeedbackTest, PackingBug)
EXPECT_EQ(attrib1Data[vectorIndex], vecPointer[stream1Index]);
EXPECT_EQ(attrib2Data[vectorIndex], vecPointer[stream2Index]);
}
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
ASSERT_GL_NO_ERROR();
}
......@@ -875,7 +878,7 @@ TEST_P(TransformFeedbackTest, TwoUnreferencedInFragShader)
ASSERT_GL_NO_ERROR();
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);
const auto &quadVertices = GetQuadVertices();
......@@ -888,9 +891,11 @@ TEST_P(TransformFeedbackTest, TwoUnreferencedInFragShader)
EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream1Index]);
EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream2Index]);
}
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
ASSERT_GL_NO_ERROR();
}
class TransformFeedbackLifetimeTest : public TransformFeedbackTest
{
protected:
......@@ -979,8 +984,108 @@ TEST_P(TransformFeedbackLifetimeTest, DeletedBuffer)
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.
ANGLE_INSTANTIATE_TEST(TransformFeedbackTest, 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
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