Commit aff17499 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Directly capture non-gl_Postion builtins

Building on support for transform feedback capture of I/O block members, this change optimizes capture of builtins other than gl_Position by directly decorating members of gl_PerVertex. Most importantly, this allows us to reserve only one varying for transform feedback, instead of as many builtins there could be (up to 4). Bug: angleproject:3606 Change-Id: Ie0957802c657ed6c5aac538d92b860582ed6da45 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2601072Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent b6ea6edc
...@@ -483,15 +483,15 @@ void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programSt ...@@ -483,15 +483,15 @@ void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programSt
const gl::TransformFeedbackVarying &tfVarying = tfVaryings[varyingIndex]; const gl::TransformFeedbackVarying &tfVarying = tfVaryings[varyingIndex];
const std::string &tfVaryingName = tfVarying.mappedName; const std::string &tfVaryingName = tfVarying.mappedName;
if (tfVarying.isBuiltIn()) if (tfVaryingName == "gl_Position")
{ {
// For simplicity, create a copy of every builtin that's captured so xfb qualifiers ASSERT(tfVarying.isBuiltIn());
// could be added to that instead. This allows the SPIR-V transformation to ignore
// OpMemberName and OpMemberDecorate instructions. Note that capturing gl_Position
// already requires such a copy, since the translator modifies this value at the end of
// main. Capturing the rest of the built-ins are niche enough that the inefficiency
// involved in doing this is not a concern.
// 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 = resources.varyingPacking.getMaxSemanticIndex() + uint32_t xfbVaryingLocation = resources.varyingPacking.getMaxSemanticIndex() +
++(*locationsUsedForXfbExtensionOut); ++(*locationsUsedForXfbExtensionOut);
...@@ -681,6 +681,10 @@ void AssignVaryingLocations(const GlslangSourceOptions &options, ...@@ -681,6 +681,10 @@ void AssignVaryingLocations(const GlslangSourceOptions &options,
info.varyingIsInput = true; info.varyingIsInput = true;
} }
} }
// Add an entry for gl_PerVertex, for use with transform feedback capture of built-ins.
ShaderInterfaceVariableInfo &info = variableInfoMapOut->add(shaderType, "gl_PerVertex");
info.activeStages.set(shaderType);
} }
// Calculates XFB layout qualifier arguments for each tranform feedback varying. Stores calculated // Calculates XFB layout qualifier arguments for each tranform feedback varying. Stores calculated
...@@ -726,15 +730,50 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &pro ...@@ -726,15 +730,50 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &pro
if (tfVarying.isBuiltIn()) if (tfVarying.isBuiltIn())
{ {
uint32_t xfbVaryingLocation = currentBuiltinLocation++; if (tfVarying.name == "gl_Position")
std::string xfbVaryingName = kXfbBuiltInPrefix + tfVarying.mappedName; {
uint32_t xfbVaryingLocation = currentBuiltinLocation++;
std::string xfbVaryingName = kXfbBuiltInPrefix + tfVarying.mappedName;
ASSERT(xfbVaryingLocation < locationsUsedForXfbExtension); ASSERT(xfbVaryingLocation < locationsUsedForXfbExtension);
AddLocationInfo(variableInfoMapOut, shaderType, xfbVaryingName, xfbVaryingLocation, AddLocationInfo(variableInfoMapOut, shaderType, xfbVaryingName, xfbVaryingLocation,
ShaderInterfaceVariableInfo::kInvalid, 0, 0); ShaderInterfaceVariableInfo::kInvalid, 0, 0);
SetXfbInfo(variableInfoMapOut, shaderType, xfbVaryingName, -1, bufferIndex, SetXfbInfo(variableInfoMapOut, shaderType, xfbVaryingName, -1, bufferIndex,
currentOffset, currentStride); currentOffset, currentStride);
}
else
{
// gl_PerVertex is always defined as:
//
// Field 0: gl_Position
// Field 1: gl_PointSize
// Field 2: gl_ClipDistance
// Field 3: gl_CullDistance
//
// All fields except gl_Position can be captured directly by decorating gl_PerVertex
// fields.
int fieldIndex = -1;
constexpr int kPerVertexMemberCount = 4;
constexpr std::array<const char *, kPerVertexMemberCount> kPerVertexMembers = {
"gl_Position",
"gl_PointSize",
"gl_ClipDistance",
"gl_CullDistance",
};
for (int index = 1; index < kPerVertexMemberCount; ++index)
{
if (tfVarying.name == kPerVertexMembers[index])
{
fieldIndex = index;
break;
}
}
ASSERT(fieldIndex != -1);
SetXfbInfo(variableInfoMapOut, shaderType, "gl_PerVertex", fieldIndex, bufferIndex,
currentOffset, currentStride);
}
} }
else if (!tfVarying.isArray() || tfVarying.arrayIndex == GL_INVALID_INDEX) else if (!tfVarying.isArray() || tfVarying.arrayIndex == GL_INVALID_INDEX)
{ {
...@@ -1784,13 +1823,8 @@ void SpirvTransformer::visitDecorate(const uint32_t *instruction) ...@@ -1784,13 +1823,8 @@ void SpirvTransformer::visitDecorate(const uint32_t *instruction)
const char *name = mNamesById[id]; const char *name = mNamesById[id];
ASSERT(name != nullptr); ASSERT(name != nullptr);
// TODO: decorate gl_PerVertex members for transform feedback similarly to I/O blocks const ShaderInterfaceVariableInfo &info = mVariableInfoMap.get(mShaderType, name);
// http://anglebug.com/3606 mVariableInfoById[id] = &info;
if (strcmp(name, "gl_PerVertex") != 0)
{
const ShaderInterfaceVariableInfo &info = mVariableInfoMap.get(mShaderType, name);
mVariableInfoById[id] = &info;
}
} }
} }
...@@ -1971,13 +2005,12 @@ void SpirvTransformer::visitVariable(const uint32_t *instruction) ...@@ -1971,13 +2005,12 @@ void SpirvTransformer::visitVariable(const uint32_t *instruction)
ASSERT(name != nullptr); ASSERT(name != nullptr);
// Handle builtins, which all start with "gl_". Either the variable name could be an indication // Handle builtins, which all start with "gl_". The variable name could be an indication of a
// of a builtin variable (such as with gl_FragCoord) or the type name (such as with // builtin variable (such as with gl_FragCoord). gl_PerVertex is the only builtin whose "type"
// gl_PerVertex). // name starts with gl_. However, gl_PerVertex has its own entry in the info map for its
const bool isNameBuiltin = isInOut && gl::IsBuiltInName(name); // potential use with transform feedback.
const bool isTypeBuiltin = const bool isNameBuiltin = isInOut && !isIOBlock && gl::IsBuiltInName(name);
isInOut && mNamesById[typeId] != nullptr && gl::IsBuiltInName(mNamesById[typeId]); if (isNameBuiltin)
if (isNameBuiltin || isTypeBuiltin)
{ {
// Make all builtins point to this no-op info. Adding this entry allows us to ASSERT that // Make all builtins point to this no-op info. Adding this entry allows us to ASSERT that
// every shader interface variable is processed during the SPIR-V transformation. This is // every shader interface variable is processed during the SPIR-V transformation. This is
...@@ -2001,7 +2034,7 @@ void SpirvTransformer::visitVariable(const uint32_t *instruction) ...@@ -2001,7 +2034,7 @@ void SpirvTransformer::visitVariable(const uint32_t *instruction)
// Note if the variable is captured by transform feedback. In that case, the TransformFeedback // Note if the variable is captured by transform feedback. In that case, the TransformFeedback
// capability needs to be added. // capability needs to be added.
if (mOptions.shaderType != gl::ShaderType::Fragment && if (mOptions.isTransformFeedbackStage &&
(info.xfb.buffer != ShaderInterfaceVariableInfo::kInvalid || !info.fieldXfb.empty()) && (info.xfb.buffer != ShaderInterfaceVariableInfo::kInvalid || !info.fieldXfb.empty()) &&
info.activeStages[mOptions.shaderType]) info.activeStages[mOptions.shaderType])
{ {
...@@ -2044,7 +2077,7 @@ bool SpirvTransformer::transformDecorate(const uint32_t *instruction, size_t wor ...@@ -2044,7 +2077,7 @@ bool SpirvTransformer::transformDecorate(const uint32_t *instruction, size_t wor
spv::DecorationOffset, spv::DecorationOffset,
}; };
if (mOptions.shaderType != gl::ShaderType::Fragment && decoration == spv::DecorationBlock && if (mOptions.isTransformFeedbackStage && decoration == spv::DecorationBlock &&
!info->fieldXfb.empty()) !info->fieldXfb.empty())
{ {
for (uint32_t fieldIndex = 0; fieldIndex < info->fieldXfb.size(); ++fieldIndex) for (uint32_t fieldIndex = 0; fieldIndex < info->fieldXfb.size(); ++fieldIndex)
...@@ -2151,7 +2184,7 @@ bool SpirvTransformer::transformDecorate(const uint32_t *instruction, size_t wor ...@@ -2151,7 +2184,7 @@ bool SpirvTransformer::transformDecorate(const uint32_t *instruction, size_t wor
} }
// Add Xfb decorations, if any. // Add Xfb decorations, if any.
if (mOptions.shaderType != gl::ShaderType::Fragment && if (mOptions.isTransformFeedbackStage &&
info->xfb.buffer != ShaderInterfaceVariableXfbInfo::kInvalid) info->xfb.buffer != ShaderInterfaceVariableXfbInfo::kInvalid)
{ {
ASSERT(info->xfb.stride != ShaderInterfaceVariableXfbInfo::kInvalid); ASSERT(info->xfb.stride != ShaderInterfaceVariableXfbInfo::kInvalid);
......
...@@ -58,6 +58,7 @@ struct GlslangSpirvOptions ...@@ -58,6 +58,7 @@ struct GlslangSpirvOptions
gl::ShaderType shaderType = gl::ShaderType::InvalidEnum; gl::ShaderType shaderType = gl::ShaderType::InvalidEnum;
bool removeEarlyFragmentTestsOptimization = false; bool removeEarlyFragmentTestsOptimization = false;
bool removeDebugInfo = false; bool removeDebugInfo = false;
bool isTransformFeedbackStage = false;
}; };
using SpirvBlob = std::vector<uint32_t>; using SpirvBlob = std::vector<uint32_t>;
......
...@@ -31,8 +31,9 @@ bool ValidateTransformedSpirV(ContextVk *contextVk, ...@@ -31,8 +31,9 @@ bool ValidateTransformedSpirV(ContextVk *contextVk,
for (gl::ShaderType shaderType : linkedShaderStages) for (gl::ShaderType shaderType : linkedShaderStages)
{ {
GlslangSpirvOptions options; GlslangSpirvOptions options;
options.shaderType = shaderType; options.shaderType = shaderType;
options.removeDebugInfo = true; options.removeDebugInfo = true;
options.isTransformFeedbackStage = shaderType == gl::ShaderType::Vertex;
SpirvBlob transformed; SpirvBlob transformed;
if (GlslangWrapperVk::TransformSpirV(contextVk, options, shaderType, variableInfoMap, if (GlslangWrapperVk::TransformSpirV(contextVk, options, shaderType, variableInfoMap,
...@@ -129,7 +130,8 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk, ...@@ -129,7 +130,8 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
options.shaderType = shaderType; options.shaderType = shaderType;
options.removeEarlyFragmentTestsOptimization = options.removeEarlyFragmentTestsOptimization =
shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization; shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization;
options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers(); options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers();
options.isTransformFeedbackStage = shaderType == gl::ShaderType::Vertex;
ANGLE_TRY(GlslangWrapperVk::TransformSpirV(contextVk, options, shaderType, variableInfoMap, ANGLE_TRY(GlslangWrapperVk::TransformSpirV(contextVk, options, shaderType, variableInfoMap,
originalSpirvBlob, &transformedSpirvBlob)); originalSpirvBlob, &transformedSpirvBlob));
......
...@@ -825,13 +825,10 @@ void RendererVk::ensureCapsInitialized() const ...@@ -825,13 +825,10 @@ void RendererVk::ensureCapsInitialized() const
// vars section. It is implicit that we need to actually reserve it for Vulkan in that case. // vars section. It is implicit that we need to actually reserve it for Vulkan in that case.
GLint reservedVaryingVectorCount = 1; GLint reservedVaryingVectorCount = 1;
// reserve 1 extra for ANGLEPosition when GLLineRasterization is enabled // Reserve 1 extra for ANGLEPosition when GLLineRasterization is enabled
constexpr GLint kRservedVaryingForGLLineRasterization = 1; constexpr GLint kRservedVaryingForGLLineRasterization = 1;
// reserve 2 extra for builtin varables when feedback is enabled // Reserve 1 extra for transform feedback capture of gl_Position.
// possible capturable out varable: gl_Position, gl_PointSize constexpr GLint kReservedVaryingForTransformFeedbackExtension = 1;
// https://www.khronos.org/registry/OpenGL/specs/es/3.1/GLSL_ES_Specification_3.10.withchanges.pdf
// page 105
constexpr GLint kReservedVaryingForTransformFeedbackExtension = 2;
if (getFeatures().basicGLLineRasterization.enabled) if (getFeatures().basicGLLineRasterization.enabled)
{ {
......
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