Commit eeb14308 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Support xfb capture of I/O block fields

In the emulation path, it's ensured that the generated code references the I/O block field correctly (using the instance name if provided, and without it otherwise). In the extension path, the info map is augmented with an array of xfb decorations for its fields. Then when `OpDecorate %IOBlockId Block` is encountered, the transform feedback decorations on the fields are inserted: OpMemberDecorate %IOBlockId MemberN XfbBuffer buffer OpMemberDecorate %IOBlockId MemberN XfbStride stride OpMemberDecorate %IOBlockId MemberN Offset offset Future work includes removing the duplicate varying added for gl_PointSize and use this mechanism to decorate gl_PerVertex directly. Bug: angleproject:3606 Change-Id: I6fed0b1ee7245fe695337043b40b281fb01a1fb0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2599953Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 8065aa82
...@@ -75,8 +75,14 @@ struct TransformFeedbackVarying : public sh::ShaderVariable ...@@ -75,8 +75,14 @@ struct TransformFeedbackVarying : public sh::ShaderVariable
*thisVar = field; *thisVar = field;
interpolation = parent.interpolation; interpolation = parent.interpolation;
isInvariant = parent.isInvariant; isInvariant = parent.isInvariant;
name = parent.name + "." + name; ASSERT(parent.isShaderIOBlock || !parent.name.empty());
mappedName = parent.mappedName + "." + mappedName; if (!parent.name.empty())
{
name = parent.name + "." + name;
mappedName = parent.mappedName + "." + mappedName;
}
structName = parent.structName;
mappedStructName = parent.mappedStructName;
} }
std::string nameWithArrayIndex() const std::string nameWithArrayIndex() const
......
...@@ -522,18 +522,35 @@ void VaryingPacking::packUserVaryingTF(const ProgramVaryingRef &ref, size_t subs ...@@ -522,18 +522,35 @@ void VaryingPacking::packUserVaryingTF(const ProgramVaryingRef &ref, size_t subs
void VaryingPacking::packUserVaryingFieldTF(const ProgramVaryingRef &ref, void VaryingPacking::packUserVaryingFieldTF(const ProgramVaryingRef &ref,
const sh::ShaderVariable &field, const sh::ShaderVariable &field,
GLuint fieldIndex) GLuint fieldIndex,
GLuint secondaryFieldIndex)
{ {
const sh::ShaderVariable *input = ref.frontShader; const sh::ShaderVariable *input = ref.frontShader;
VaryingInShaderRef frontVarying(ref.frontShaderStage, &field); const sh::ShaderVariable *frontField = &field;
if (secondaryFieldIndex != GL_INVALID_INDEX)
{
frontField = &frontField->fields[secondaryFieldIndex];
}
VaryingInShaderRef frontVarying(ref.frontShaderStage, frontField);
VaryingInShaderRef backVarying(ref.backShaderStage, nullptr); VaryingInShaderRef backVarying(ref.backShaderStage, nullptr);
frontVarying.parentStructName = input->name; if (frontField->isShaderIOBlock)
frontVarying.parentStructMappedName = input->mappedName; {
frontVarying.parentStructName = input->structName;
frontVarying.parentStructMappedName = input->mappedStructName;
}
else
{
ASSERT(!frontField->isStruct() && !frontField->isArray());
frontVarying.parentStructName = input->name;
frontVarying.parentStructMappedName = input->mappedName;
}
mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying), mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying),
input->interpolation, GL_INVALID_INDEX, fieldIndex, 0); input->interpolation, GL_INVALID_INDEX, fieldIndex,
secondaryFieldIndex == GL_INVALID_INDEX ? 0 : secondaryFieldIndex);
} }
bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
...@@ -620,6 +637,10 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -620,6 +637,10 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
if (input) if (input)
{ {
uniqueFullNames[ref.frontShaderStage].insert(input->name); uniqueFullNames[ref.frontShaderStage].insert(input->name);
if (input->isShaderIOBlock)
{
uniqueFullNames[ref.frontShaderStage].insert(input->structName);
}
} }
if (output) if (output)
{ {
...@@ -655,9 +676,11 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -655,9 +676,11 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
{ {
subscript = subscripts.back(); subscript = subscripts.back();
} }
// Already packed for fragment shader. // Already packed as active varying.
if (uniqueFullNames[ref.frontShaderStage].count(tfVarying) > 0 || if (uniqueFullNames[ref.frontShaderStage].count(tfVarying) > 0 ||
uniqueFullNames[ref.frontShaderStage].count(baseName) > 0) uniqueFullNames[ref.frontShaderStage].count(baseName) > 0 ||
(input->isShaderIOBlock &&
uniqueFullNames[ref.frontShaderStage].count(input->structName) > 0))
{ {
continue; continue;
} }
...@@ -667,9 +690,38 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -667,9 +690,38 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
const sh::ShaderVariable *field = input->findField(tfVarying, &fieldIndex); const sh::ShaderVariable *field = input->findField(tfVarying, &fieldIndex);
if (field != nullptr) if (field != nullptr)
{ {
ASSERT(!field->isStruct() && (!field->isArray() || input->isShaderIOBlock)); ASSERT(input->isShaderIOBlock || (!field->isStruct() && !field->isArray()));
packUserVaryingFieldTF(ref, *field, fieldIndex); // If it's an I/O block whose member is being captured, pack every member of the
// block. Currently, we pack either all or none of an I/O block.
if (input->isShaderIOBlock)
{
for (fieldIndex = 0; fieldIndex < input->fields.size(); ++fieldIndex)
{
if (input->fields[fieldIndex].isStruct())
{
for (GLuint nestedIndex = 0;
nestedIndex < input->fields[fieldIndex].fields.size();
nestedIndex++)
{
packUserVaryingFieldTF(ref, input->fields[fieldIndex],
fieldIndex, nestedIndex);
}
}
else
{
packUserVaryingFieldTF(ref, input->fields[fieldIndex], fieldIndex,
GL_INVALID_INDEX);
}
}
uniqueFullNames[ref.frontShaderStage].insert(input->structName);
}
else
{
packUserVaryingFieldTF(ref, *field, fieldIndex, GL_INVALID_INDEX);
}
uniqueFullNames[ref.frontShaderStage].insert(tfVarying); uniqueFullNames[ref.frontShaderStage].insert(tfVarying);
} }
uniqueFullNames[ref.frontShaderStage].insert(input->name); uniqueFullNames[ref.frontShaderStage].insert(input->name);
......
...@@ -263,7 +263,8 @@ class VaryingPacking final : angle::NonCopyable ...@@ -263,7 +263,8 @@ class VaryingPacking final : angle::NonCopyable
void packUserVaryingTF(const ProgramVaryingRef &ref, size_t subscript); void packUserVaryingTF(const ProgramVaryingRef &ref, size_t subscript);
void packUserVaryingFieldTF(const ProgramVaryingRef &ref, void packUserVaryingFieldTF(const ProgramVaryingRef &ref,
const sh::ShaderVariable &field, const sh::ShaderVariable &field,
GLuint fieldIndex); GLuint fieldIndex,
GLuint secondaryFieldIndex);
void clearRegisterMap(); void clearRegisterMap();
......
...@@ -64,6 +64,15 @@ using SpirvBlob = std::vector<uint32_t>; ...@@ -64,6 +64,15 @@ using SpirvBlob = std::vector<uint32_t>;
using GlslangErrorCallback = std::function<angle::Result(GlslangError)>; using GlslangErrorCallback = std::function<angle::Result(GlslangError)>;
struct ShaderInterfaceVariableXfbInfo
{
static constexpr uint32_t kInvalid = std::numeric_limits<uint32_t>::max();
uint32_t buffer = kInvalid;
uint32_t offset = kInvalid;
uint32_t stride = kInvalid;
};
// Information for each shader interface variable. Not all fields are relevant to each shader // Information for each shader interface variable. Not all fields are relevant to each shader
// interface variable. For example opaque uniforms require a set and binding index, while vertex // interface variable. For example opaque uniforms require a set and binding index, while vertex
// attributes require a location. // attributes require a location.
...@@ -85,9 +94,8 @@ struct ShaderInterfaceVariableInfo ...@@ -85,9 +94,8 @@ struct ShaderInterfaceVariableInfo
// The stages this shader interface variable is active. // The stages this shader interface variable is active.
gl::ShaderBitSet activeStages; gl::ShaderBitSet activeStages;
// Used for transform feedback extension to decorate vertex shader output. // Used for transform feedback extension to decorate vertex shader output.
uint32_t xfbBuffer = kInvalid; ShaderInterfaceVariableXfbInfo xfb;
uint32_t xfbOffset = kInvalid; std::vector<ShaderInterfaceVariableXfbInfo> fieldXfb;
uint32_t xfbStride = kInvalid;
// Indicates that the precision needs to be modified in the generated SPIR-V // Indicates that the precision needs to be modified in the generated SPIR-V
// to support only transferring medium precision data when there's a precision // to support only transferring medium precision data when there's a precision
// mismatch between the shaders. For example, either the VS casts highp->mediump // mismatch between the shaders. For example, either the VS casts highp->mediump
......
...@@ -229,10 +229,17 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(gl::BinaryInputStream * ...@@ -229,10 +229,17 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(gl::BinaryInputStream *
info->location = stream->readInt<uint32_t>(); info->location = stream->readInt<uint32_t>();
info->component = stream->readInt<uint32_t>(); info->component = stream->readInt<uint32_t>();
// PackedEnumBitSet uses uint8_t // PackedEnumBitSet uses uint8_t
info->activeStages = gl::ShaderBitSet(stream->readInt<uint8_t>()); info->activeStages = gl::ShaderBitSet(stream->readInt<uint8_t>());
info->xfbBuffer = stream->readInt<uint32_t>(); info->xfb.buffer = stream->readInt<uint32_t>();
info->xfbOffset = stream->readInt<uint32_t>(); info->xfb.offset = stream->readInt<uint32_t>();
info->xfbStride = stream->readInt<uint32_t>(); info->xfb.stride = stream->readInt<uint32_t>();
info->fieldXfb.resize(stream->readInt<size_t>());
for (ShaderInterfaceVariableXfbInfo &xfb : info->fieldXfb)
{
xfb.buffer = stream->readInt<uint32_t>();
xfb.offset = stream->readInt<uint32_t>();
xfb.stride = stream->readInt<uint32_t>();
}
info->useRelaxedPrecision = stream->readBool(); info->useRelaxedPrecision = stream->readBool();
info->varyingIsInput = stream->readBool(); info->varyingIsInput = stream->readBool();
info->varyingIsOutput = stream->readBool(); info->varyingIsOutput = stream->readBool();
...@@ -258,9 +265,16 @@ void ProgramExecutableVk::save(gl::BinaryOutputStream *stream) ...@@ -258,9 +265,16 @@ void ProgramExecutableVk::save(gl::BinaryOutputStream *stream)
stream->writeInt(it.second.component); stream->writeInt(it.second.component);
// PackedEnumBitSet uses uint8_t // PackedEnumBitSet uses uint8_t
stream->writeInt(it.second.activeStages.bits()); stream->writeInt(it.second.activeStages.bits());
stream->writeInt(it.second.xfbBuffer); stream->writeInt(it.second.xfb.buffer);
stream->writeInt(it.second.xfbOffset); stream->writeInt(it.second.xfb.offset);
stream->writeInt(it.second.xfbStride); stream->writeInt(it.second.xfb.stride);
stream->writeInt(it.second.fieldXfb.size());
for (const ShaderInterfaceVariableXfbInfo &xfb : it.second.fieldXfb)
{
stream->writeInt(xfb.buffer);
stream->writeInt(xfb.offset);
stream->writeInt(xfb.stride);
}
stream->writeBool(it.second.useRelaxedPrecision); stream->writeBool(it.second.useRelaxedPrecision);
stream->writeBool(it.second.varyingIsInput); stream->writeBool(it.second.varyingIsInput);
stream->writeBool(it.second.varyingIsOutput); stream->writeBool(it.second.varyingIsOutput);
......
...@@ -2809,9 +2809,6 @@ TEST_P(TransformFeedbackTestES31, IOBlocksInterleaved) ...@@ -2809,9 +2809,6 @@ TEST_P(TransformFeedbackTestES31, IOBlocksInterleaved)
// http://anglebug.com/5488 // http://anglebug.com/5488
ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES()); ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES());
// Not supported in Vulkan yet. http://anglebug.com/3606
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr char kVS[] = R"(#version 310 es constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require #extension GL_EXT_shader_io_blocks : require
...@@ -2920,9 +2917,6 @@ TEST_P(TransformFeedbackTestES31, IOBlocksSeparate) ...@@ -2920,9 +2917,6 @@ TEST_P(TransformFeedbackTestES31, IOBlocksSeparate)
// http://anglebug.com/5488 // http://anglebug.com/5488
ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES()); ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES());
// Not supported in Vulkan yet. http://anglebug.com/3606
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr char kVS[] = R"(#version 310 es constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require #extension GL_EXT_shader_io_blocks : require
......
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