Vulkan: Move xfb position decl to translator in extension path
This change removes the @@ XFB-DECL @@ marker. The ANGLEXfbPosition
output is unconditionally emitted in VS, TES and GS by the translator,
and is appropriately decorated or removed by the SPIR-V transformer.
Bug: angleproject:3606
Change-Id: Ia76224f5a6d147362eeb2d288f05e333aaf75481
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2617658
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Charlie Lao <cclao@google.com>
diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h
index 4d3fba7..aaa089d 100644
--- a/include/GLSLANG/ShaderLang.h
+++ b/include/GLSLANG/ShaderLang.h
@@ -26,7 +26,7 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
-#define ANGLE_SH_VERSION 249
+#define ANGLE_SH_VERSION 250
enum ShShaderSpec
{
@@ -348,9 +348,13 @@
// Allow compiler to use specialization constant to do pre-rotation and y flip.
const ShCompileOptions SH_USE_SPECIALIZATION_CONSTANT = UINT64_C(1) << 58;
-// Ask compiler to generate transform feedback emulation support code.
+// Ask compiler to generate Vulkan transform feedback emulation support code.
const ShCompileOptions SH_ADD_VULKAN_XFB_EMULATION_SUPPORT_CODE = UINT64_C(1) << 59;
+// Ask compiler to generate Vulkan transform feedback support code when using the
+// VK_EXT_transform_feedback extension.
+const ShCompileOptions SH_ADD_VULKAN_XFB_EXTENSION_SUPPORT_CODE = UINT64_C(1) << 60;
+
// Defines alternate strategies for implementing array index clamping.
enum ShArrayIndexClampingStrategy
{
@@ -873,12 +877,15 @@
// Line raster emulation varying
extern const char kLineRasterEmulationPosition[];
-// Transform feedback emulation helper function
+// Transform feedback emulation support
extern const char kXfbEmulationGetOffsetsFunctionName[];
extern const char kXfbEmulationBufferBlockName[];
extern const char kXfbEmulationBufferName[];
extern const char kXfbEmulationBufferFieldName[];
+// Transform feedback extension support
+extern const char kXfbExtensionPositionOutName[];
+
} // namespace vk
namespace mtl
diff --git a/src/compiler/translator/ShaderLang.cpp b/src/compiler/translator/ShaderLang.cpp
index 5e2ed27..a07f28e 100644
--- a/src/compiler/translator/ShaderLang.cpp
+++ b/src/compiler/translator/ShaderLang.cpp
@@ -797,6 +797,8 @@
const char kXfbEmulationBufferName[] = "ANGLEXfb";
const char kXfbEmulationBufferFieldName[] = "xfbOut";
+const char kXfbExtensionPositionOutName[] = "ANGLEXfbPosition";
+
} // namespace vk
} // namespace sh
diff --git a/src/compiler/translator/TranslatorVulkan.cpp b/src/compiler/translator/TranslatorVulkan.cpp
index 8e80ed0..111202e 100644
--- a/src/compiler/translator/TranslatorVulkan.cpp
+++ b/src/compiler/translator/TranslatorVulkan.cpp
@@ -481,6 +481,48 @@
return compiler->validateAST(root);
}
+ANGLE_NO_DISCARD bool AddXfbExtensionSupport(TCompiler *compiler,
+ TIntermBlock *root,
+ TSymbolTable *symbolTable,
+ const DriverUniform *driverUniforms)
+{
+ // Generate the following output varying declaration used to capture transform feedback output
+ // from gl_Position, as it can't be captured directly due to changes that are applied to it for
+ // clip-space correction and pre-rotation.
+ //
+ // out vec4 ANGLEXfbPosition;
+
+ const TType *vec4Type = nullptr;
+
+ switch (compiler->getShaderType())
+ {
+ case GL_VERTEX_SHADER:
+ vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqVertexOut, 4, 1>();
+ break;
+ case GL_TESS_EVALUATION_SHADER_EXT:
+ vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqTessEvaluationOut, 4, 1>();
+ break;
+ case GL_GEOMETRY_SHADER_EXT:
+ vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqGeometryOut, 4, 1>();
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ TVariable *varyingVar =
+ new TVariable(symbolTable, ImmutableString(vk::kXfbExtensionPositionOutName), vec4Type,
+ SymbolType::AngleInternal);
+
+ TIntermDeclaration *varyingDecl = new TIntermDeclaration();
+ varyingDecl->appendDeclarator(new TIntermSymbol(varyingVar));
+
+ // Insert the varying declaration before the first function.
+ const size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
+ root->insertChildNodes(firstFunctionIndex, {varyingDecl});
+
+ return compiler->validateAST(root);
+}
+
ANGLE_NO_DISCARD bool InsertFragCoordCorrection(TCompiler *compiler,
ShCompileOptions compileOptions,
TIntermBlock *root,
@@ -829,8 +871,14 @@
if (gl::ShaderTypeSupportsTransformFeedback(packedShaderType))
{
- // Add a macro to declare transform feedback buffers.
- sink << "@@ XFB-DECL @@\n\n";
+ if (compileOptions & SH_ADD_VULKAN_XFB_EXTENSION_SUPPORT_CODE)
+ {
+ // Add support code for transform feedback extension.
+ if (!AddXfbExtensionSupport(this, root, &getSymbolTable(), driverUniforms))
+ {
+ return false;
+ }
+ }
// Append a macro for transform feedback substitution prior to modifying depth.
if (!AppendTransformFeedbackOutputToMain(this, root, &getSymbolTable()))
diff --git a/src/libANGLE/renderer/glslang_wrapper_utils.cpp b/src/libANGLE/renderer/glslang_wrapper_utils.cpp
index cd6f880..ec4457b 100644
--- a/src/libANGLE/renderer/glslang_wrapper_utils.cpp
+++ b/src/libANGLE/renderer/glslang_wrapper_utils.cpp
@@ -59,9 +59,7 @@
{
namespace
{
-constexpr char kXfbDeclMarker[] = "@@ XFB-DECL @@";
-constexpr char kXfbOutMarker[] = "@@ XFB-OUT @@;";
-constexpr char kXfbBuiltInPrefix[] = "xfbANGLE";
+constexpr char kXfbOutMarker[] = "@@ XFB-OUT @@;";
template <size_t N>
constexpr size_t ConstStrLen(const char (&)[N])
@@ -298,30 +296,22 @@
}
std::string SubstituteTransformFeedbackMarkers(const std::string &originalSource,
- const std::string &xfbDecl,
const std::string &xfbOut)
{
- const size_t xfbDeclMarkerStart = originalSource.find(kXfbDeclMarker);
- const size_t xfbDeclMarkerEnd = xfbDeclMarkerStart + ConstStrLen(kXfbDeclMarker);
-
- const size_t xfbOutMarkerStart = originalSource.find(kXfbOutMarker, xfbDeclMarkerStart);
+ const size_t xfbOutMarkerStart = originalSource.find(kXfbOutMarker);
const size_t xfbOutMarkerEnd = xfbOutMarkerStart + ConstStrLen(kXfbOutMarker);
// The shader is the following form:
//
// ..part1..
- // @@ XFB-DECL @@
- // ..part2..
// @@ XFB-OUT @@;
- // ..part3..
+ // ..part2..
//
- // Construct the string by concatenating these five pieces, replacing the markers with the given
- // values.
+ // Construct the string by concatenating these three pieces, replacing the marker with the given
+ // value.
std::string result;
- result.append(&originalSource[0], &originalSource[xfbDeclMarkerStart]);
- result.append(xfbDecl);
- result.append(&originalSource[xfbDeclMarkerEnd], &originalSource[xfbOutMarkerStart]);
+ result.append(&originalSource[0], &originalSource[xfbOutMarkerStart]);
result.append(xfbOut);
result.append(&originalSource[xfbOutMarkerEnd], &originalSource[originalSource.size()]);
@@ -403,6 +393,50 @@
}
}
+void AssignTransformFeedbackExtensionLocations(gl::ShaderType shaderType,
+ const gl::ProgramState &programState,
+ bool isTransformFeedbackStage,
+ GlslangProgramInterfaceInfo *programInterfaceInfo,
+ ShaderInterfaceVariableInfoMap *variableInfoMapOut)
+{
+ // The only varying that requires additional resources is gl_Position, as it's indirectly
+ // captured through ANGLEXfbPosition.
+
+ const std::vector<gl::TransformFeedbackVarying> &tfVaryings =
+ programState.getLinkedTransformFeedbackVaryings();
+
+ bool capturesPosition = false;
+
+ if (isTransformFeedbackStage)
+ {
+ for (uint32_t varyingIndex = 0; varyingIndex < tfVaryings.size(); ++varyingIndex)
+ {
+ const gl::TransformFeedbackVarying &tfVarying = tfVaryings[varyingIndex];
+ const std::string &tfVaryingName = tfVarying.mappedName;
+
+ if (tfVaryingName == "gl_Position")
+ {
+ ASSERT(tfVarying.isBuiltIn());
+ capturesPosition = true;
+ break;
+ }
+ }
+ }
+
+ if (capturesPosition)
+ {
+ AddLocationInfo(variableInfoMapOut, shaderType, sh::vk::kXfbExtensionPositionOutName,
+ programInterfaceInfo->locationsUsedForXfbExtension, 0, 0, 0);
+ ++programInterfaceInfo->locationsUsedForXfbExtension;
+ }
+ else
+ {
+ // Make sure this varying is removed from the other stages, or if position is not captured
+ // at all.
+ variableInfoMapOut->add(shaderType, sh::vk::kXfbExtensionPositionOutName);
+ }
+}
+
void GenerateTransformFeedbackEmulationOutputs(const GlslangSourceOptions &options,
gl::ShaderType shaderType,
const gl::ProgramState &programState,
@@ -459,7 +493,7 @@
}
xfbOut << "}\n";
- *vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, "", xfbOut.str());
+ *vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, xfbOut.str());
}
bool IsFirstRegisterOfVarying(const gl::PackedVaryingRegister &varyingReg, bool allowFields)
@@ -495,14 +529,11 @@
// Calculates XFB layout qualifier arguments for each tranform feedback varying. Stores calculated
// values for the SPIR-V transformation.
void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programState,
- const gl::VaryingPacking &varyingPacking,
- std::string *xfbShaderSource,
- uint32_t *locationsUsedForXfbExtensionOut)
+ std::string *xfbShaderSource)
{
const std::vector<gl::TransformFeedbackVarying> &tfVaryings =
programState.getLinkedTransformFeedbackVaryings();
- std::string xfbDecl;
std::string xfbOut;
for (uint32_t varyingIndex = 0; varyingIndex < tfVaryings.size(); ++varyingIndex)
@@ -514,25 +545,14 @@
{
ASSERT(tfVarying.isBuiltIn());
- // For gl_Position, create a copy of the builtin so xfb qualifiers could be added to
- // that instead. gl_Position is modified by the shader (to account for Vulkan depth
- // clip space and prerotation), so it cannot be captured directly.
- //
- // The rest of the builtins are captured by decorating gl_PerVertex directly.
- uint32_t xfbVaryingLocation =
- varyingPacking.getMaxSemanticIndex() + ++(*locationsUsedForXfbExtensionOut);
-
- std::string xfbVaryingName = kXfbBuiltInPrefix + tfVaryingName;
-
- // Add declaration and initialization code for the new varying.
- std::string varyingType = gl::GetGLSLTypeString(tfVarying.type);
- xfbDecl += "layout(location = " + Str(xfbVaryingLocation) + ") out " + varyingType +
- " " + xfbVaryingName + ";\n";
- xfbOut += xfbVaryingName + " = " + tfVaryingName + ";\n";
+ // Add initialization code for the position varying.
+ xfbOut = sh::vk::kXfbExtensionPositionOutName;
+ xfbOut += " = " + tfVaryingName + ";\n";
+ break;
}
}
- *xfbShaderSource = SubstituteTransformFeedbackMarkers(*xfbShaderSource, xfbDecl, xfbOut);
+ *xfbShaderSource = SubstituteTransformFeedbackMarkers(*xfbShaderSource, xfbOut);
}
void AssignAttributeLocations(const gl::ProgramExecutable &programExecutable,
@@ -717,7 +737,6 @@
// values for the SPIR-V transformation.
void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &programExecutable,
const gl::VaryingPacking &varyingPacking,
- uint32_t locationsUsedForXfbExtension,
const gl::ShaderType shaderType,
ShaderInterfaceVariableInfoMap *variableInfoMapOut)
{
@@ -727,12 +746,9 @@
const bool isInterleaved =
programExecutable.getTransformFeedbackBufferMode() == GL_INTERLEAVED_ATTRIBS;
- std::string xfbDecl;
- std::string xfbOut;
- uint32_t currentOffset = 0;
- uint32_t currentStride = 0;
- uint32_t bufferIndex = 0;
- uint32_t currentBuiltinLocation = 0;
+ uint32_t currentOffset = 0;
+ uint32_t currentStride = 0;
+ uint32_t bufferIndex = 0;
for (uint32_t varyingIndex = 0; varyingIndex < tfVaryings.size(); ++varyingIndex)
{
@@ -759,15 +775,8 @@
{
if (tfVarying.name == "gl_Position")
{
- uint32_t xfbVaryingLocation = currentBuiltinLocation++;
- std::string xfbVaryingName = kXfbBuiltInPrefix + tfVarying.mappedName;
-
- ASSERT(xfbVaryingLocation < locationsUsedForXfbExtension);
-
- AddLocationInfo(variableInfoMapOut, shaderType, xfbVaryingName, xfbVaryingLocation,
- ShaderInterfaceVariableInfo::kInvalid, 0, 0);
- SetXfbInfo(variableInfoMapOut, shaderType, xfbVaryingName, -1, bufferIndex,
- currentOffset, currentStride);
+ SetXfbInfo(variableInfoMapOut, shaderType, sh::vk::kXfbExtensionPositionOutName, -1,
+ bufferIndex, currentOffset, currentStride);
}
else
{
@@ -4386,6 +4395,15 @@
const gl::VaryingPacking &inputPacking = varyingPacking.getInputPacking(shaderType);
const gl::VaryingPacking &outputPacking = varyingPacking.getOutputPacking(shaderType);
+ // Assign location to varyings generated for transform feedback capture
+ if (options.supportsTransformFeedbackExtension &&
+ gl::ShaderTypeSupportsTransformFeedback(shaderType))
+ {
+ AssignTransformFeedbackExtensionLocations(shaderType, programState,
+ isTransformFeedbackStage,
+ programInterfaceInfo, variableInfoMapOut);
+ }
+
// Assign varying locations.
if (shaderType != gl::ShaderType::Vertex)
{
@@ -4398,13 +4416,13 @@
programInterfaceInfo, variableInfoMapOut);
}
+ // Assign qualifiers to all varyings captured by transform feedback
if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() &&
options.supportsTransformFeedbackExtension &&
(shaderType == programExecutable.getLinkedTransformFeedbackStage()))
{
- AssignTransformFeedbackExtensionQualifiers(
- programExecutable, outputPacking,
- programInterfaceInfo->locationsUsedForXfbExtension, shaderType, variableInfoMapOut);
+ AssignTransformFeedbackExtensionQualifiers(programExecutable, outputPacking, shaderType,
+ variableInfoMapOut);
}
}
@@ -4445,9 +4463,7 @@
{
if (options.supportsTransformFeedbackExtension)
{
- GenerateTransformFeedbackExtensionOutputs(
- programState, resources.varyingPacking.getOutputPacking(xfbStage), xfbSource,
- &programInterfaceInfo->locationsUsedForXfbExtension);
+ GenerateTransformFeedbackExtensionOutputs(programState, xfbSource);
}
else if (options.emulateTransformFeedback)
{
@@ -4458,25 +4474,25 @@
}
else
{
- *xfbSource = SubstituteTransformFeedbackMarkers(*xfbSource, "", "");
+ *xfbSource = SubstituteTransformFeedbackMarkers(*xfbSource, "");
}
}
else
{
- *xfbSource = SubstituteTransformFeedbackMarkers(*xfbSource, "", "");
+ *xfbSource = SubstituteTransformFeedbackMarkers(*xfbSource, "");
}
}
std::string *tessEvalSources = &(*shaderSourcesOut)[gl::ShaderType::TessEvaluation];
if (xfbStage > gl::ShaderType::TessEvaluation && !tessEvalSources->empty())
{
- *tessEvalSources = SubstituteTransformFeedbackMarkers(*tessEvalSources, "", "");
+ *tessEvalSources = SubstituteTransformFeedbackMarkers(*tessEvalSources, "");
}
std::string *vertexSource = &(*shaderSourcesOut)[gl::ShaderType::Vertex];
if (xfbStage > gl::ShaderType::Vertex && !vertexSource->empty())
{
- *vertexSource = SubstituteTransformFeedbackMarkers(*vertexSource, "", "");
+ *vertexSource = SubstituteTransformFeedbackMarkers(*vertexSource, "");
}
gl::ShaderType frontShaderType = gl::ShaderType::InvalidEnum;
diff --git a/src/libANGLE/renderer/vulkan/ShaderVk.cpp b/src/libANGLE/renderer/vulkan/ShaderVk.cpp
index 8a99044..055c78a 100644
--- a/src/libANGLE/renderer/vulkan/ShaderVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ShaderVk.cpp
@@ -87,7 +87,11 @@
compileOptions |= SH_ADD_PRE_ROTATION;
}
- if (contextVk->getFeatures().emulateTransformFeedback.enabled)
+ if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
+ {
+ compileOptions |= SH_ADD_VULKAN_XFB_EXTENSION_SUPPORT_CODE;
+ }
+ else if (contextVk->getFeatures().emulateTransformFeedback.enabled)
{
compileOptions |= SH_ADD_VULKAN_XFB_EMULATION_SUPPORT_CODE;
}