summaryrefslogtreecommitdiff
path: root/source/slang/slang-emit-glsl.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2021-03-03 11:45:39 -0800
committerGitHub <noreply@github.com>2021-03-03 11:45:39 -0800
commit13ff0bd345990c0fdfb7b52ebd5339cddb04889e (patch)
treeae3773d4f3475439a55603007b3908e31c6c31fb /source/slang/slang-emit-glsl.cpp
parentd6ae67160c33460bf952c9959077dc481a16eca2 (diff)
Add GLSL/SPIR-V support got GetAttributeAtVertex (#1733)
This change allows varying fragment shader inputs to be declared in a way that allows the `GetAttributeAtVertex` operation to compile to valid code for both D3D and GLSL/SPIR-V/Vulkan. The key is that rather than just use ordinary `nointerpolation`-qualified inputs the code must declare these varying inputs with a new `pervertex` qualifier that marks them as *only* being usable with `GetAttributeAtVertex`. The `pervertex`-tagged inputs then translate to GLSL inputs using the `pervertexNV` qualifier Note that this change does *not* include any enforcement of the requirements around how these qualifiers are used (and the compiler doesn't have enforcement for the existing operations like `EvaluateAttributeAtCentroid`). The underlying problem is that the inerpolation-mode qualifiers and explicit interpolation functions in HLSL constitute a kind of rate-qualified type system, but without any systematic rules. It seems wasteful to encode a bunch of ad hoc rules for this stuff as special cases in the compiler when the clear right answer is to implement a systematic approach to rates.
Diffstat (limited to 'source/slang/slang-emit-glsl.cpp')
-rw-r--r--source/slang/slang-emit-glsl.cpp89
1 files changed, 87 insertions, 2 deletions
diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp
index 53da7da06..7b784de8d 100644
--- a/source/slang/slang-emit-glsl.cpp
+++ b/source/slang/slang-emit-glsl.cpp
@@ -916,6 +916,45 @@ void GLSLSourceEmitter::emitEntryPointAttributesImpl(IRFunc* irFunc, IREntryPoin
}
}
+void GLSLSourceEmitter::_emitGLSLPerVertexVaryingFragmentInput(IRGlobalParam* param, IRType* type)
+{
+ // Note: The logic here is almost identical to the default
+ // emit logic for global shader parameters. The main difference
+ // is that we emit a parameter of type `X` as an array of
+ // type `X[3]` to account for the per-vertex-ness of the
+ // parameter.
+ //
+
+ // Need to emit appropriate modifiers here.
+
+ // We expect/require all shader parameters to
+ // have some kind of layout information associated with them.
+ //
+ auto layout = getVarLayout(param);
+ SLANG_ASSERT(layout);
+
+ emitVarModifiers(layout, param, type);
+
+ emitRateQualifiers(param);
+
+ auto name = getName(param);
+ StringSliceLoc nameAndLoc(name.getUnownedSlice());
+ NameDeclaratorInfo nameDeclarator(&nameAndLoc);
+
+ LiteralSizedArrayDeclaratorInfo arrayDeclarator(&nameDeclarator, 3);
+
+ // Note: We are invoking `_emitType` here directly because there
+ // is no overload of `emitType` that works with a declarator.
+ //
+ _emitType(type, &arrayDeclarator);
+
+ emitSemantics(param);
+
+ emitLayoutSemantics(param);
+
+ m_writer->emit(";\n\n");
+}
+
bool GLSLSourceEmitter::tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* varType)
{
// There are a number of types that are (or can be)
@@ -995,6 +1034,21 @@ bool GLSLSourceEmitter::tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* v
}
}
+ // A varying fragment input parameter with the `pervertex` modifier
+ // needs to be emitted as an array.
+ //
+ if( auto interpolationModeDecor = varDecl->findDecoration<IRInterpolationModeDecoration>() )
+ {
+ if( interpolationModeDecor->getMode() == IRInterpolationMode::PerVertex )
+ {
+ if( m_entryPointStage == Stage::Fragment )
+ {
+ _emitGLSLPerVertexVaryingFragmentInput(varDecl, varType);
+ return true;
+ }
+ }
+ }
+
// Do the default thing
return false;
}
@@ -1789,7 +1843,7 @@ void GLSLSourceEmitter::emitRateQualifiersImpl(IRRate* rate)
}
}
-static UnownedStringSlice _getInterpolationModifierText(IRInterpolationMode mode)
+static UnownedStringSlice _getInterpolationModifierText(IRInterpolationMode mode, Stage stage, bool isInput)
{
switch (mode)
{
@@ -1798,6 +1852,17 @@ static UnownedStringSlice _getInterpolationModifierText(IRInterpolationMode mode
case IRInterpolationMode::Linear: return UnownedStringSlice::fromLiteral("smooth");
case IRInterpolationMode::Sample: return UnownedStringSlice::fromLiteral("sample");
case IRInterpolationMode::Centroid: return UnownedStringSlice::fromLiteral("centroid");
+
+ case IRInterpolationMode::PerVertex:
+ if( stage == Stage::Fragment )
+ {
+ if( isInput )
+ {
+ return UnownedStringSlice::fromLiteral("pervertexNV");
+ }
+ }
+ return UnownedStringSlice::fromLiteral("flat");
+
default: return UnownedStringSlice();
}
}
@@ -1806,13 +1871,16 @@ void GLSLSourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType*
{
bool anyModifiers = false;
+ auto stage = layout->getStage();
+ auto isInput = layout->findOffsetAttr(LayoutResourceKind::VaryingInput) != nullptr;
+
for (auto dd : varInst->getDecorations())
{
if (dd->getOp() != kIROp_InterpolationModeDecoration)
continue;
auto decoration = (IRInterpolationModeDecoration*)dd;
- const UnownedStringSlice slice = _getInterpolationModifierText(decoration->getMode());
+ const UnownedStringSlice slice = _getInterpolationModifierText(decoration->getMode(), stage, isInput);
if (slice.getLength())
{
@@ -1820,6 +1888,23 @@ void GLSLSourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType*
m_writer->emitChar(' ');
anyModifiers = true;
}
+
+ switch( decoration->getMode() )
+ {
+ default:
+ break;
+
+ case IRInterpolationMode::PerVertex:
+ if( stage == Stage::Fragment )
+ {
+ if( isInput )
+ {
+ _requireGLSLVersion(ProfileVersion::GLSL_450);
+ _requireGLSLExtension(UnownedStringSlice::fromLiteral("GL_NV_fragment_shader_barycentric"));
+ }
+ }
+ break;
+ }
}
// If the user didn't explicitly qualify a varying