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