Commit f6df8692 by Jamie Madill Committed by Commit Bot

Vulkan: Support XFB in non-Vertex stages.

This updates the code in several places to support Geometry and Tessellation Evaluation shaders to output transform feedback. Does not turn on any new tests but enables support for XFB when we turn on GS/TS. Bug: angleproject:3571 Bug: angleproject:3572 Change-Id: I6dcb768f2df4eeee81a4a500e999fcf16716f58f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2581941Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 8707811d
...@@ -1150,6 +1150,19 @@ ShaderType GetShaderTypeFromBitfield(size_t singleShaderType) ...@@ -1150,6 +1150,19 @@ ShaderType GetShaderTypeFromBitfield(size_t singleShaderType)
return ShaderType::InvalidEnum; return ShaderType::InvalidEnum;
} }
} }
bool ShaderTypeSupportsTransformFeedback(ShaderType shaderType)
{
switch (shaderType)
{
case ShaderType::Vertex:
case ShaderType::Geometry:
case ShaderType::TessEvaluation:
return true;
default:
return false;
}
}
} // namespace gl } // namespace gl
namespace egl namespace egl
......
...@@ -246,6 +246,7 @@ enum class SrgbOverride ...@@ -246,6 +246,7 @@ enum class SrgbOverride
}; };
ShaderType GetShaderTypeFromBitfield(size_t singleShaderType); ShaderType GetShaderTypeFromBitfield(size_t singleShaderType);
bool ShaderTypeSupportsTransformFeedback(ShaderType shaderType);
} // namespace gl } // namespace gl
......
...@@ -341,9 +341,9 @@ ANGLE_NO_DISCARD bool AppendPreRotation(TCompiler *compiler, ...@@ -341,9 +341,9 @@ ANGLE_NO_DISCARD bool AppendPreRotation(TCompiler *compiler,
return RunAtTheEndOfShader(compiler, root, assignment, symbolTable); return RunAtTheEndOfShader(compiler, root, assignment, symbolTable);
} }
ANGLE_NO_DISCARD bool AppendVertexShaderTransformFeedbackOutputToMain(TCompiler *compiler, ANGLE_NO_DISCARD bool AppendTransformFeedbackOutputToMain(TCompiler *compiler,
TIntermBlock *root, TIntermBlock *root,
TSymbolTable *symbolTable) TSymbolTable *symbolTable)
{ {
TVariable *xfbPlaceholder = new TVariable(symbolTable, ImmutableString("@@ XFB-OUT @@"), TVariable *xfbPlaceholder = new TVariable(symbolTable, ImmutableString("@@ XFB-OUT @@"),
new TType(), SymbolType::AngleInternal); new TType(), SymbolType::AngleInternal);
...@@ -745,11 +745,12 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -745,11 +745,12 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
return false; return false;
} }
gl::ShaderType packedShaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
if (defaultUniformCount > 0) if (defaultUniformCount > 0)
{ {
gl::ShaderType shaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
sink << "\nlayout(set=0, binding=" << outputGLSL->nextUnusedBinding() sink << "\nlayout(set=0, binding=" << outputGLSL->nextUnusedBinding()
<< ", std140) uniform " << kDefaultUniformNames[shaderType] << "\n{\n"; << ", std140) uniform " << kDefaultUniformNames[packedShaderType] << "\n{\n";
DeclareDefaultUniformsTraverser defaultTraverser(&sink, getHashFunction(), &getNameMap()); DeclareDefaultUniformsTraverser defaultTraverser(&sink, getHashFunction(), &getNameMap());
root->traverse(&defaultTraverser); root->traverse(&defaultTraverser);
...@@ -797,7 +798,7 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -797,7 +798,7 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
} }
} }
if (getShaderType() != GL_COMPUTE_SHADER) if (packedShaderType != gl::ShaderType::Compute)
{ {
if (!ReplaceGLDepthRangeWithDriverUniform(this, root, driverUniforms, &getSymbolTable())) if (!ReplaceGLDepthRangeWithDriverUniform(this, root, driverUniforms, &getSymbolTable()))
{ {
...@@ -814,229 +815,249 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -814,229 +815,249 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
} }
} }
// Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData if (gl::ShaderTypeSupportsTransformFeedback(packedShaderType))
// if it's core profile shaders and they are used.
if (getShaderType() == GL_FRAGMENT_SHADER)
{ {
bool usesPointCoord = false; // Add a macro to declare transform feedback buffers.
bool usesFragCoord = false; sink << "@@ XFB-DECL @@\n\n";
bool usesSampleMaskIn = false;
// Search for the gl_PointCoord usage, if its used, we need to flip the y coordinate. // Append a macro for transform feedback substitution prior to modifying depth.
for (const ShaderVariable &inputVarying : mInputVaryings) if (!AppendTransformFeedbackOutputToMain(this, root, &getSymbolTable()))
{ {
if (!inputVarying.isBuiltIn()) return false;
{ }
continue; }
}
if (inputVarying.name == "gl_SampleMaskIn") switch (packedShaderType)
{ {
usesSampleMaskIn = true; case gl::ShaderType::Fragment:
continue; {
} bool usesPointCoord = false;
bool usesFragCoord = false;
bool usesSampleMaskIn = false;
if (inputVarying.name == "gl_PointCoord") // Search for the gl_PointCoord usage, if its used, we need to flip the y coordinate.
for (const ShaderVariable &inputVarying : mInputVaryings)
{ {
usesPointCoord = true; if (!inputVarying.isBuiltIn())
break; {
} continue;
}
if (inputVarying.name == "gl_FragCoord") if (inputVarying.name == "gl_SampleMaskIn")
{ {
usesFragCoord = true; usesSampleMaskIn = true;
break; continue;
}
if (inputVarying.name == "gl_PointCoord")
{
usesPointCoord = true;
break;
}
if (inputVarying.name == "gl_FragCoord")
{
usesFragCoord = true;
break;
}
} }
}
if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION) if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
{
if (!AddBresenhamEmulationFS(this, compileOptions, sink, root, &getSymbolTable(),
&surfaceRotationSpecConst, driverUniforms, usesFragCoord))
{ {
return false; if (!AddBresenhamEmulationFS(this, compileOptions, sink, root, &getSymbolTable(),
&surfaceRotationSpecConst, driverUniforms,
usesFragCoord))
{
return false;
}
mSpecConstUsageBits.set(vk::SpecConstUsage::LineRasterEmulation);
} }
mSpecConstUsageBits.set(vk::SpecConstUsage::LineRasterEmulation);
}
bool hasGLFragColor = false; bool hasGLFragColor = false;
bool hasGLFragData = false; bool hasGLFragData = false;
bool usePreRotation = compileOptions & SH_ADD_PRE_ROTATION; bool usePreRotation = compileOptions & SH_ADD_PRE_ROTATION;
bool hasGLSampleMask = false; bool hasGLSampleMask = false;
for (const ShaderVariable &outputVar : mOutputVariables) for (const ShaderVariable &outputVar : mOutputVariables)
{
if (outputVar.name == "gl_FragColor")
{ {
ASSERT(!hasGLFragColor); if (outputVar.name == "gl_FragColor")
hasGLFragColor = true; {
continue; ASSERT(!hasGLFragColor);
hasGLFragColor = true;
continue;
}
else if (outputVar.name == "gl_FragData")
{
ASSERT(!hasGLFragData);
hasGLFragData = true;
continue;
}
else if (outputVar.name == "gl_SampleMask")
{
ASSERT(!hasGLSampleMask);
hasGLSampleMask = true;
continue;
}
} }
else if (outputVar.name == "gl_FragData")
// Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
// if it's core profile shaders and they are used.
ASSERT(!(hasGLFragColor && hasGLFragData));
if (hasGLFragColor)
{ {
ASSERT(!hasGLFragData); sink << "layout(location = 0) out vec4 webgl_FragColor;\n";
hasGLFragData = true;
continue;
} }
else if (outputVar.name == "gl_SampleMask") if (hasGLFragData)
{ {
ASSERT(!hasGLSampleMask); sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
hasGLSampleMask = true;
continue;
} }
}
ASSERT(!(hasGLFragColor && hasGLFragData));
if (hasGLFragColor)
{
sink << "layout(location = 0) out vec4 webgl_FragColor;\n";
}
if (hasGLFragData)
{
sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
}
if (usesPointCoord) if (usesPointCoord)
{
TIntermTyped *flipNegXY = surfaceRotationSpecConst.getNegFlipXY();
if (!flipNegXY)
{ {
flipNegXY = driverUniforms->getNegFlipXYRef(); TIntermTyped *flipNegXY = surfaceRotationSpecConst.getNegFlipXY();
if (!flipNegXY)
{
flipNegXY = driverUniforms->getNegFlipXYRef();
}
TIntermConstantUnion *pivot = CreateFloatNode(0.5f);
TIntermTyped *fragRotation = nullptr;
if (usePreRotation)
{
fragRotation = surfaceRotationSpecConst.getFragRotationMatrix();
if (!fragRotation)
{
fragRotation = driverUniforms->getFragRotationMatrixRef();
}
}
if (!RotateAndFlipBuiltinVariable(this, root, GetMainSequence(root), flipNegXY,
&getSymbolTable(),
BuiltInVariable::gl_PointCoord(),
kFlippedPointCoordName, pivot, fragRotation))
{
return false;
}
} }
TIntermConstantUnion *pivot = CreateFloatNode(0.5f);
TIntermTyped *fragRotation = nullptr; if (usesFragCoord)
if (usePreRotation)
{ {
fragRotation = surfaceRotationSpecConst.getFragRotationMatrix(); if (!InsertFragCoordCorrection(this, compileOptions, root, GetMainSequence(root),
if (!fragRotation) &getSymbolTable(), &surfaceRotationSpecConst,
driverUniforms))
{ {
fragRotation = driverUniforms->getFragRotationMatrixRef(); return false;
} }
} }
if (!RotateAndFlipBuiltinVariable(this, root, GetMainSequence(root), flipNegXY,
&getSymbolTable(), BuiltInVariable::gl_PointCoord(), if (!RewriteDfdy(this, compileOptions, root, getSymbolTable(), getShaderVersion(),
kFlippedPointCoordName, pivot, fragRotation)) &surfaceRotationSpecConst, driverUniforms))
{ {
return false; return false;
} }
}
if (usesFragCoord) if (!RewriteInterpolateAtOffset(this, compileOptions, root, getSymbolTable(),
{ getShaderVersion(), &surfaceRotationSpecConst,
if (!InsertFragCoordCorrection(this, compileOptions, root, GetMainSequence(root), driverUniforms))
&getSymbolTable(), &surfaceRotationSpecConst,
driverUniforms))
{ {
return false; return false;
} }
}
if (!RewriteDfdy(this, compileOptions, root, getSymbolTable(), getShaderVersion(), if (usesSampleMaskIn && !RewriteSampleMaskIn(this, root, &getSymbolTable()))
&surfaceRotationSpecConst, driverUniforms)) {
{ return false;
return false; }
}
if (!RewriteInterpolateAtOffset(this, compileOptions, root, getSymbolTable(), if (hasGLSampleMask)
getShaderVersion(), &surfaceRotationSpecConst, {
driverUniforms)) TIntermBinary *numSamples = driverUniforms->getNumSamplesRef();
{ if (!RewriteSampleMask(this, root, &getSymbolTable(), numSamples))
return false; {
} return false;
}
}
if (usesSampleMaskIn && !RewriteSampleMaskIn(this, root, &getSymbolTable())) {
{ const TVariable *numSamplesVar =
return false; static_cast<const TVariable *>(getSymbolTable().findBuiltIn(
ImmutableString("gl_NumSamples"), getShaderVersion()));
TIntermBinary *numSamples = driverUniforms->getNumSamplesRef();
if (!ReplaceVariableWithTyped(this, root, numSamplesVar, numSamples))
{
return false;
}
}
EmitEarlyFragmentTestsGLSL(*this, sink);
break;
} }
if (hasGLSampleMask) case gl::ShaderType::Vertex:
{ {
TIntermBinary *numSamples = driverUniforms->getNumSamplesRef(); if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
if (!RewriteSampleMask(this, root, &getSymbolTable(), numSamples))
{ {
return false; if (!AddBresenhamEmulationVS(this, root, &getSymbolTable(), driverUniforms))
{
return false;
}
mSpecConstUsageBits.set(vk::SpecConstUsage::LineRasterEmulation);
} }
}
{ // Search for the gl_ClipDistance usage, if its used, we need to do some replacements.
const TVariable *numSamplesVar = static_cast<const TVariable *>( bool useClipDistance = false;
getSymbolTable().findBuiltIn(ImmutableString("gl_NumSamples"), getShaderVersion())); for (const ShaderVariable &outputVarying : mOutputVaryings)
TIntermBinary *numSamples = driverUniforms->getNumSamplesRef(); {
if (!ReplaceVariableWithTyped(this, root, numSamplesVar, numSamples)) if (outputVarying.name == "gl_ClipDistance")
{
useClipDistance = true;
break;
}
}
if (useClipDistance &&
!ReplaceClipDistanceAssignments(this, root, &getSymbolTable(),
driverUniforms->getClipDistancesEnabled()))
{ {
return false; return false;
} }
}
EmitEarlyFragmentTestsGLSL(*this, sink); // Append depth range translation to main.
} if (!transformDepthBeforeCorrection(root, driverUniforms))
else if (getShaderType() == GL_VERTEX_SHADER)
{
if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
{
if (!AddBresenhamEmulationVS(this, root, &getSymbolTable(), driverUniforms))
{ {
return false; return false;
} }
mSpecConstUsageBits.set(vk::SpecConstUsage::LineRasterEmulation); if (!AppendVertexShaderDepthCorrectionToMain(this, root, &getSymbolTable()))
}
// Add a macro to declare transform feedback buffers.
sink << "@@ XFB-DECL @@\n\n";
// Append a macro for transform feedback substitution prior to modifying depth.
if (!AppendVertexShaderTransformFeedbackOutputToMain(this, root, &getSymbolTable()))
{
return false;
}
// Search for the gl_ClipDistance usage, if its used, we need to do some replacements.
bool useClipDistance = false;
for (const ShaderVariable &outputVarying : mOutputVaryings)
{
if (outputVarying.name == "gl_ClipDistance")
{ {
useClipDistance = true; return false;
break;
} }
} if ((compileOptions & SH_ADD_PRE_ROTATION) != 0 &&
if (useClipDistance && !AppendPreRotation(this, root, &getSymbolTable(), &surfaceRotationSpecConst,
!ReplaceClipDistanceAssignments(this, root, &getSymbolTable(), driverUniforms))
driverUniforms->getClipDistancesEnabled())) {
{ return false;
return false; }
break;
} }
// Append depth range translation to main. case gl::ShaderType::Geometry:
if (!transformDepthBeforeCorrection(root, driverUniforms))
{ {
return false; int maxVertices = getGeometryShaderMaxVertices();
// max_vertices=0 is not valid in Vulkan
maxVertices = std::max(1, maxVertices);
WriteGeometryShaderLayoutQualifiers(
sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
getGeometryShaderOutputPrimitiveType(), maxVertices);
break;
} }
if (!AppendVertexShaderDepthCorrectionToMain(this, root, &getSymbolTable()))
case gl::ShaderType::Compute:
{ {
return false; EmitWorkGroupSizeGLSL(*this, sink);
break;
} }
if ((compileOptions & SH_ADD_PRE_ROTATION) != 0 &&
!AppendPreRotation(this, root, &getSymbolTable(), &surfaceRotationSpecConst,
driverUniforms))
{
return false;
}
}
else if (getShaderType() == GL_GEOMETRY_SHADER)
{
int maxVertices = getGeometryShaderMaxVertices();
// max_vertices=0 is not valid in Vulkan
maxVertices = std::max(1, maxVertices);
WriteGeometryShaderLayoutQualifiers(sink, getGeometryShaderInputPrimitiveType(), default:
getGeometryShaderInvocations(), UNREACHABLE();
getGeometryShaderOutputPrimitiveType(), maxVertices); break;
}
else
{
ASSERT(getShaderType() == GL_COMPUTE_SHADER);
EmitWorkGroupSizeGLSL(*this, sink);
} }
surfaceRotationSpecConst.outputLayoutString(sink); surfaceRotationSpecConst.outputLayoutString(sink);
......
...@@ -1276,6 +1276,19 @@ ShaderType ProgramState::getLastAttachedShaderStageType() const ...@@ -1276,6 +1276,19 @@ ShaderType ProgramState::getLastAttachedShaderStageType() const
return ShaderType::InvalidEnum; return ShaderType::InvalidEnum;
} }
ShaderType ProgramState::getAttachedTransformFeedbackStage() const
{
if (mAttachedShaders[ShaderType::Geometry])
{
return ShaderType::Geometry;
}
if (mAttachedShaders[ShaderType::TessEvaluation])
{
return ShaderType::TessEvaluation;
}
return ShaderType::Vertex;
}
Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, ShaderProgramID handle) Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, ShaderProgramID handle)
: mSerial(factory->generateSerial()), : mSerial(factory->generateSerial()),
mProgram(factory->createProgram(mState)), mProgram(factory->createProgram(mState)),
......
...@@ -372,6 +372,8 @@ class ProgramState final : angle::NonCopyable ...@@ -372,6 +372,8 @@ class ProgramState final : angle::NonCopyable
int getBaseInstanceLocation() const { return mBaseInstanceLocation; } int getBaseInstanceLocation() const { return mBaseInstanceLocation; }
ShaderType getAttachedTransformFeedbackStage() const;
private: private:
friend class MemoryProgramCache; friend class MemoryProgramCache;
friend class Program; friend class Program;
......
...@@ -538,4 +538,17 @@ bool ProgramExecutable::isYUVOutput() const ...@@ -538,4 +538,17 @@ bool ProgramExecutable::isYUVOutput() const
{ {
return !isCompute() && mYUVOutput; return !isCompute() && mYUVOutput;
} }
ShaderType ProgramExecutable::getLinkedTransformFeedbackStage() const
{
if (mLinkedGraphicsShaderStages[ShaderType::Geometry])
{
return ShaderType::Geometry;
}
if (mLinkedGraphicsShaderStages[ShaderType::TessEvaluation])
{
return ShaderType::TessEvaluation;
}
return ShaderType::Vertex;
}
} // namespace gl } // namespace gl
...@@ -152,6 +152,8 @@ class ProgramExecutable final : public angle::Subject ...@@ -152,6 +152,8 @@ class ProgramExecutable final : public angle::Subject
: mLinkedGraphicsShaderStages.count(); : mLinkedGraphicsShaderStages.count();
} }
ShaderType getLinkedTransformFeedbackStage() const;
// A PPO can have both graphics and compute programs attached, so // A PPO can have both graphics and compute programs attached, so
// we don't know if the PPO is a 'graphics' or 'compute' PPO until the // we don't know if the PPO is a 'graphics' or 'compute' PPO until the
// actual draw/dispatch call. // actual draw/dispatch call.
......
...@@ -466,7 +466,7 @@ bool IsFirstRegisterOfVarying(const gl::PackedVaryingRegister &varyingReg) ...@@ -466,7 +466,7 @@ bool IsFirstRegisterOfVarying(const gl::PackedVaryingRegister &varyingReg)
// values for the SPIR-V transformation. // values for the SPIR-V transformation.
void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programState, void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
std::string *vertexShader, std::string *xfbShaderSource,
uint32_t *locationsUsedForXfbExtensionOut) uint32_t *locationsUsedForXfbExtensionOut)
{ {
const std::vector<gl::TransformFeedbackVarying> &tfVaryings = const std::vector<gl::TransformFeedbackVarying> &tfVaryings =
...@@ -502,7 +502,7 @@ void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programSt ...@@ -502,7 +502,7 @@ void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programSt
} }
} }
*vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, xfbDecl, xfbOut); *xfbShaderSource = SubstituteTransformFeedbackMarkers(*xfbShaderSource, xfbDecl, xfbOut);
} }
void AssignAttributeLocations(const gl::ProgramExecutable &programExecutable, void AssignAttributeLocations(const gl::ProgramExecutable &programExecutable,
...@@ -3664,11 +3664,12 @@ void GlslangAssignLocations(const GlslangSourceOptions &options, ...@@ -3664,11 +3664,12 @@ void GlslangAssignLocations(const GlslangSourceOptions &options,
programInterfaceInfo, variableInfoMapOut); programInterfaceInfo, variableInfoMapOut);
if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() && if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() &&
options.supportsTransformFeedbackExtension && (shaderType == gl::ShaderType::Vertex)) options.supportsTransformFeedbackExtension &&
(shaderType == programExecutable.getLinkedTransformFeedbackStage()))
{ {
AssignTransformFeedbackExtensionQualifiers( AssignTransformFeedbackExtensionQualifiers(
programExecutable, programInterfaceInfo->locationsUsedForXfbExtension, programExecutable, programInterfaceInfo->locationsUsedForXfbExtension, shaderType,
gl::ShaderType::Vertex, &(*variableInfoMapOut)[gl::ShaderType::Vertex]); &(*variableInfoMapOut)[shaderType]);
} }
} }
...@@ -3693,34 +3694,48 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options, ...@@ -3693,34 +3694,48 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options,
(*shaderSourcesOut)[shaderType] = glShader ? glShader->getTranslatedSource() : ""; (*shaderSourcesOut)[shaderType] = glShader ? glShader->getTranslatedSource() : "";
} }
std::string *vertexSource = &(*shaderSourcesOut)[gl::ShaderType::Vertex]; gl::ShaderType xfbStage = programState.getAttachedTransformFeedbackStage();
std::string *xfbSource = &(*shaderSourcesOut)[xfbStage];
// Write transform feedback output code. // Write transform feedback output code.
if (!vertexSource->empty()) if (!xfbSource->empty())
{ {
if (programState.getLinkedTransformFeedbackVaryings().empty()) if (!programState.getLinkedTransformFeedbackVaryings().empty())
{
*vertexSource = SubstituteTransformFeedbackMarkers(*vertexSource, "", "");
}
else
{ {
if (options.supportsTransformFeedbackExtension) if (options.supportsTransformFeedbackExtension)
{ {
GenerateTransformFeedbackExtensionOutputs( GenerateTransformFeedbackExtensionOutputs(
programState, resources, vertexSource, programState, resources, xfbSource,
&programInterfaceInfo->locationsUsedForXfbExtension); &programInterfaceInfo->locationsUsedForXfbExtension);
} }
else if (options.emulateTransformFeedback) else if (options.emulateTransformFeedback)
{ {
GenerateTransformFeedbackEmulationOutputs( ASSERT(xfbStage == gl::ShaderType::Vertex);
options, programState, programInterfaceInfo, vertexSource, GenerateTransformFeedbackEmulationOutputs(options, programState,
&(*variableInfoMapOut)[gl::ShaderType::Vertex]); programInterfaceInfo, xfbSource,
&(*variableInfoMapOut)[xfbStage]);
} }
else else
{ {
*vertexSource = SubstituteTransformFeedbackMarkers(*vertexSource, "", ""); *xfbSource = SubstituteTransformFeedbackMarkers(*xfbSource, "", "");
} }
} }
else
{
*xfbSource = SubstituteTransformFeedbackMarkers(*xfbSource, "", "");
}
}
std::string *tessEvalSources = &(*shaderSourcesOut)[gl::ShaderType::TessEvaluation];
if (xfbStage > gl::ShaderType::TessEvaluation && !tessEvalSources->empty())
{
*tessEvalSources = SubstituteTransformFeedbackMarkers(*tessEvalSources, "", "");
}
std::string *vertexSource = &(*shaderSourcesOut)[gl::ShaderType::Vertex];
if (xfbStage > gl::ShaderType::Vertex && !vertexSource->empty())
{
*vertexSource = SubstituteTransformFeedbackMarkers(*vertexSource, "", "");
} }
gl::ShaderType frontShaderType = gl::ShaderType::InvalidEnum; gl::ShaderType frontShaderType = gl::ShaderType::InvalidEnum;
......
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