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
......@@ -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