diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2021-03-03 11:45:39 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-03 11:45:39 -0800 |
| commit | 13ff0bd345990c0fdfb7b52ebd5339cddb04889e (patch) | |
| tree | ae3773d4f3475439a55603007b3908e31c6c31fb /source/slang/slang-emit-glsl.cpp | |
| parent | d6ae67160c33460bf952c9959077dc481a16eca2 (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.cpp | 89 |
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 |
