diff --git a/include/dxc/Support/HLSLOptions.td b/include/dxc/Support/HLSLOptions.td index d07752602f..0b3620a0dc 100644 --- a/include/dxc/Support/HLSLOptions.td +++ b/include/dxc/Support/HLSLOptions.td @@ -370,6 +370,8 @@ def fvk_use_dx_position_w: Flag<["-"], "fvk-use-dx-position-w">, Group; def fvk_support_nonzero_base_instance: Flag<["-"], "fvk-support-nonzero-base-instance">, Group, Flags<[CoreOption, DriverOption]>, HelpText<"Follow Vulkan spec to use gl_BaseInstance as the first vertex instance, which makes SV_InstanceID = gl_InstanceIndex - gl_BaseInstance (without this option, SV_InstanceID = gl_InstanceIndex)">; +def fvk_support_nonzero_base_vertex: Flag<["-"], "fvk-support-nonzero-base-vertex">, Group, Flags<[CoreOption, DriverOption]>, + HelpText<"Follow Vulkan spec to use gl_BaseVertex as the first vertex, which makes SV_VertexID = gl_VertexIndex - gl_BaseVertex (without this option, SV_VertexID = gl_VertexIndex)">; def fvk_use_gl_layout: Flag<["-"], "fvk-use-gl-layout">, Group, Flags<[CoreOption, DriverOption]>, HelpText<"Use strict OpenGL std140/std430 memory layout for Vulkan resources">; def fvk_use_dx_layout: Flag<["-"], "fvk-use-dx-layout">, Group, Flags<[CoreOption, DriverOption]>, diff --git a/include/dxc/Support/SPIRVOptions.h b/include/dxc/Support/SPIRVOptions.h index c0ccf22d57..8260945c40 100644 --- a/include/dxc/Support/SPIRVOptions.h +++ b/include/dxc/Support/SPIRVOptions.h @@ -65,6 +65,7 @@ struct SpirvCodeGenOptions { bool reduceLoadSize; bool autoShiftBindings; bool supportNonzeroBaseInstance; + bool supportNonzeroBaseVertex; bool fixFuncCallArguments; bool allowRWStructuredBufferArrays; bool enableMaximalReconvergence; diff --git a/lib/DxcSupport/HLSLOptions.cpp b/lib/DxcSupport/HLSLOptions.cpp index 7576d735b9..326a217388 100644 --- a/lib/DxcSupport/HLSLOptions.cpp +++ b/lib/DxcSupport/HLSLOptions.cpp @@ -1053,6 +1053,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude, Args.hasFlag(OPT_fvk_use_dx_position_w, OPT_INVALID, false); opts.SpirvOptions.supportNonzeroBaseInstance = Args.hasFlag(OPT_fvk_support_nonzero_base_instance, OPT_INVALID, false); + opts.SpirvOptions.supportNonzeroBaseVertex = + Args.hasFlag(OPT_fvk_support_nonzero_base_vertex, OPT_INVALID, false); opts.SpirvOptions.useGlLayout = Args.hasFlag(OPT_fvk_use_gl_layout, OPT_INVALID, false); opts.SpirvOptions.useDxLayout = diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index a007ffd286..673aa5cec4 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -3392,14 +3392,32 @@ SpirvVariable *DeclResultIdMapper::getInstanceIdFromIndexAndBase( return instanceIdVar; } -SpirvVariable *DeclResultIdMapper::getBaseInstanceVariable( - SemanticInfo *semantic, const hlsl::SigPoint *sigPoint, QualType type) { +SpirvVariable * +DeclResultIdMapper::getVertexIdFromIndexAndBase(SpirvVariable *vertexIndexVar, + SpirvVariable *baseVertexVar) { + QualType type = vertexIndexVar->getAstResultType(); + auto *vertexIdVar = spvBuilder.addFnVar( + type, vertexIndexVar->getSourceLocation(), "SV_VertexID"); + auto *vertexIndexValue = spvBuilder.createLoad( + type, vertexIndexVar, vertexIndexVar->getSourceLocation()); + auto *baseVertexValue = spvBuilder.createLoad( + type, baseVertexVar, vertexIndexVar->getSourceLocation()); + auto *vertexIdValue = spvBuilder.createBinaryOp( + spv::Op::OpISub, type, vertexIndexValue, baseVertexValue, + vertexIndexVar->getSourceLocation()); + spvBuilder.createStore(vertexIdVar, vertexIdValue, + vertexIndexVar->getSourceLocation()); + return vertexIdVar; +} + +SpirvVariable * +DeclResultIdMapper::getBaseInstanceVariable(const hlsl::SigPoint *sigPoint, + QualType type) { assert(type->isSpecificBuiltinType(BuiltinType::Kind::Int) || type->isSpecificBuiltinType(BuiltinType::Kind::UInt)); auto *baseInstanceVar = spvBuilder.addStageBuiltinVar( - type, spv::StorageClass::Input, spv::BuiltIn::BaseInstance, false, - semantic->loc); - StageVar var(sigPoint, *semantic, nullptr, type, + type, spv::StorageClass::Input, spv::BuiltIn::BaseInstance, false, {}); + StageVar var(sigPoint, {}, nullptr, type, getLocationAndComponentCount(astContext, type)); var.setSpirvInstr(baseInstanceVar); var.setIsSpirvBuiltin(); @@ -3407,6 +3425,21 @@ SpirvVariable *DeclResultIdMapper::getBaseInstanceVariable( return baseInstanceVar; } +SpirvVariable * +DeclResultIdMapper::getBaseVertexVariable(const hlsl::SigPoint *sigPoint, + QualType type) { + assert(type->isSpecificBuiltinType(BuiltinType::Kind::Int) || + type->isSpecificBuiltinType(BuiltinType::Kind::UInt)); + auto *baseVertexVar = spvBuilder.addStageBuiltinVar( + type, spv::StorageClass::Input, spv::BuiltIn::BaseVertex, false, {}); + StageVar var(sigPoint, {}, nullptr, type, + getLocationAndComponentCount(astContext, type)); + var.setSpirvInstr(baseVertexVar); + var.setIsSpirvBuiltin(); + stageVars.push_back(var); + return baseVertexVar; +} + SpirvVariable *DeclResultIdMapper::createSpirvInterfaceVariable( const StageVarDataBundle &stageVarData) { // The evalType will be the type of the interface variable in SPIR-V. @@ -3493,13 +3526,24 @@ SpirvVariable *DeclResultIdMapper::createSpirvInterfaceVariable( // The above call to createSpirvStageVar creates the gl_InstanceIndex. // We should now manually create the gl_BaseInstance variable and do the // subtraction. - auto *baseInstanceVar = getBaseInstanceVariable( - stageVarData.semantic, stageVarData.sigPoint, stageVarData.type); + auto *baseInstanceVar = + getBaseInstanceVariable(stageVarData.sigPoint, stageVarData.type); // SPIR-V code for 'SV_InstanceID = gl_InstanceIndex - gl_BaseInstance' varInstr = getInstanceIdFromIndexAndBase(varInstr, baseInstanceVar); } + if (spirvOptions.supportNonzeroBaseVertex && + stageVarData.semantic->getKind() == hlsl::Semantic::Kind::VertexID && + stageVarData.sigPoint->GetKind() == hlsl::SigPoint::Kind::VSIn) { + + auto *baseVertexVar = + getBaseVertexVariable(stageVarData.sigPoint, stageVarData.type); + + // SPIR-V code for 'SV_VertexID = gl_VertexIndex - gl_BaseVertex' + varInstr = getVertexIdFromIndexAndBase(varInstr, baseVertexVar); + } + // We have semantics attached to this decl, which means it must be a // function/parameter/variable. All are DeclaratorDecls. stageVarInstructions[cast(stageVarData.decl)] = varInstr; diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.h b/tools/clang/lib/SPIRV/DeclResultIdMapper.h index 41781c18da..07b9c983cc 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.h +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.h @@ -791,24 +791,40 @@ class DeclResultIdMapper { SpirvVariable *getInstanceIdFromIndexAndBase(SpirvVariable *instanceIndexVar, SpirvVariable *baseInstanceVar); + // Creates a function scope variable to represent the "SV_VertexID" + // semantic, which is not immediately available in SPIR-V. Its value will be + // set by subtracting the values of the given InstanceIndex and base instance + // variables. + // + // vertexIndexVar: The SPIR-V input variable decorated with + // vertexIndex. + // + // baseVertexVar: The SPIR-V input variable decorated with + // BaseVertex. + SpirvVariable *getVertexIdFromIndexAndBase(SpirvVariable *vertexIndexVar, + SpirvVariable *baseVertexVar); + // Creates and returns a variable that is the BaseInstance builtin input. The // variable is also added to the list of stage variable `this->stageVars`. Its // type will be a 32-bit integer. // - // The semantic is a lie. We currently give it the semantic for the - // InstanceID. I'm not sure what would happen if we did not use a semantic, or - // tried to generate the correct one. I'm guessing there would be some issue - // with reflection. + // sigPoint: the signature point identifying which shader stage the variable + // will be used in. // - // semantic: the semantic to attach to this variable + // type: The type to use for the new variable. Must be int or unsigned int. + SpirvVariable *getBaseInstanceVariable(const hlsl::SigPoint *sigPoint, + QualType type); + + // Creates and returns a variable that is the BaseVertex builtin input. The + // variable is also added to the list of stage variable `this->stageVars`. Its + // type will be a 32-bit integer. // // sigPoint: the signature point identifying which shader stage the variable // will be used in. // // type: The type to use for the new variable. Must be int or unsigned int. - SpirvVariable *getBaseInstanceVariable(SemanticInfo *semantic, - const hlsl::SigPoint *sigPoint, - QualType type); + SpirvVariable *getBaseVertexVariable(const hlsl::SigPoint *sigPoint, + QualType type); // Creates and return a new interface variable from the information provided. // The new variable with be add to `this->StageVars`. diff --git a/tools/clang/test/CodeGenSPIRV/semantic.nonzero-base-vertex.vs.hlsl b/tools/clang/test/CodeGenSPIRV/semantic.nonzero-base-vertex.vs.hlsl new file mode 100644 index 0000000000..1dfe948bc9 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/semantic.nonzero-base-vertex.vs.hlsl @@ -0,0 +1,29 @@ +// RUN: %dxc -T vs_6_0 -E main -fvk-support-nonzero-base-vertex -fcgl %s -spirv | FileCheck %s + +// CHECK: OpEntryPoint Vertex %main "main" +// CHECK-SAME: %gl_VertexIndex +// CHECK-SAME: [[gl_BaseVertex:%[0-9]+]] +// CHECK-SAME: %out_var_A + +// CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex +// CHECK: OpDecorate [[gl_BaseVertex]] BuiltIn BaseVertex +// CHECK: OpDecorate %out_var_A Location 0 + +// CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_int Input +// CHECK: [[gl_BaseVertex]] = OpVariable %_ptr_Input_int Input +// CHECK: %out_var_A = OpVariable %_ptr_Output_int Output + +// CHECK: %main = OpFunction +// CHECK: %SV_VertexID = OpVariable %_ptr_Function_int Function +// CHECK: [[gl_VertexIndex:%[0-9]+]] = OpLoad %int %gl_VertexIndex +// CHECK: [[base_vertex:%[0-9]+]] = OpLoad %int [[gl_BaseVertex]] +// CHECK: [[vertex_id:%[0-9]+]] = OpISub %int [[gl_VertexIndex]] [[base_vertex]] +// CHECK: OpStore %SV_VertexID [[vertex_id]] +// CHECK: [[vertex_id_0:%[0-9]+]] = OpLoad %int %SV_VertexID +// CHECK: OpStore %param_var_input [[vertex_id_0]] +// CHECK: {{%[0-9]+}} = OpFunctionCall %int %src_main %param_var_input + +int main(int input: SV_VertexID) : A { + return input; +} + diff --git a/tools/clang/test/CodeGenSPIRV/semantic.unsigned-nonzero-base-vertex.vs.hlsl b/tools/clang/test/CodeGenSPIRV/semantic.unsigned-nonzero-base-vertex.vs.hlsl new file mode 100644 index 0000000000..e08370e4aa --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/semantic.unsigned-nonzero-base-vertex.vs.hlsl @@ -0,0 +1,29 @@ +// RUN: %dxc -T vs_6_0 -E main -fvk-support-nonzero-base-vertex -fcgl %s -spirv | FileCheck %s + +// CHECK: OpEntryPoint Vertex %main "main" +// CHECK-SAME: %gl_VertexIndex +// CHECK-SAME: [[gl_BaseVertex:%[0-9]+]] +// CHECK-SAME: %out_var_A + +// CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex +// CHECK: OpDecorate [[gl_BaseVertex]] BuiltIn BaseVertex +// CHECK: OpDecorate %out_var_A Location 0 + +// CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input +// CHECK: [[gl_BaseVertex]] = OpVariable %_ptr_Input_uint Input +// CHECK: %out_var_A = OpVariable %_ptr_Output_uint Output + +// CHECK: %main = OpFunction +// CHECK: %SV_VertexID = OpVariable %_ptr_Function_uint Function +// CHECK: [[gl_VertexIndex:%[0-9]+]] = OpLoad %uint %gl_VertexIndex +// CHECK: [[base_vertex:%[0-9]+]] = OpLoad %uint [[gl_BaseVertex]] +// CHECK: [[vertex_id:%[0-9]+]] = OpISub %uint [[gl_VertexIndex]] [[base_vertex]] +// CHECK: OpStore %SV_VertexID [[vertex_id]] +// CHECK: [[vertex_id_0:%[0-9]+]] = OpLoad %uint %SV_VertexID +// CHECK: OpStore %param_var_input [[vertex_id_0]] +// CHECK: {{%[0-9]+}} = OpFunctionCall %uint %src_main %param_var_input + +unsigned int main(unsigned int input: SV_VertexID) : A { + return input; +} +