Skip to content

Commit 751b453

Browse files
jaebaeksudonatalie
andauthored
[spirv] handle hull shader OutputPatch (#4119) (#4131)
The existing code creates a temporary variable with Output storage class for the parameter with OutputPatch type for the patch constant functions. However, this adds an additional output stage variable and consumes more locations. In addition, it can also change the rendering result depending on the driver. This commit removes the additional output stage variable and use the actual output stage variables for the argument passing for the OutputPatch. This is correctly working because the output stage variable keeps the output value for all invocation id and we can simply reuse it. Co-authored-by: Natalie Chouinard <[email protected]>
1 parent abfaccb commit 751b453

7 files changed

Lines changed: 129 additions & 110 deletions

File tree

docs/SPIR-V.rst

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2986,8 +2986,12 @@ patch constant function. This would include information about each of the ``N``
29862986
vertices that are input to the tessellation control shader.
29872987

29882988
OutputPatch is an array containing ``N`` elements (where ``N`` is the number of
2989-
output vertices). Each element of the array contains information about an
2990-
output vertex. OutputPatch may also be passed to the patch constant function.
2989+
output vertices). Each element of the array is the hull shader output for each
2990+
output vertex. For example, each element of ``OutputPatch<HSOutput, 3>`` is each
2991+
output value of the hull shader function for each ``SV_OutputControlPointID``.
2992+
It is shared between threads i.e., in the patch constant function, threads for
2993+
the same patch must see the same values for the elements of
2994+
``OutputPatch<HSOutput, 3>``.
29912995

29922996
The SPIR-V ``InvocationID`` (``SV_OutputControlPointID`` in HLSL) is used to index
29932997
into the InputPatch and OutputPatch arrays to read/write information for the given
@@ -3009,7 +3013,11 @@ As mentioned above, the patch constant function is to be invoked only once per p
30093013
As a result, in the SPIR-V module, the `entry function wrapper`_ will first invoke the
30103014
main entry function, and then use an ``OpControlBarrier`` to wait for all vertex
30113015
processing to finish. After the barrier, *only* the first thread (with InvocationID of 0)
3012-
will invoke the patch constant function.
3016+
will invoke the patch constant function. Since the first thread has to see the
3017+
OutputPatch that contains output of the hull shader function for other threads,
3018+
we have to use the output stage variable (with Output storage class) of the
3019+
hull shader function for OutputPatch that can be an input to the patch constant
3020+
function.
30133021

30143022
The information resulting from the patch constant function will also be returned
30153023
as stage output variables. The output struct of the patch constant function must include

tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

Lines changed: 48 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3234,43 +3234,6 @@ SpirvVariable *DeclResultIdMapper::getBuiltinVar(spv::BuiltIn builtIn,
32343234
return var;
32353235
}
32363236

3237-
SpirvVariable *DeclResultIdMapper::createSpirvIntermediateOutputStageVar(
3238-
const NamedDecl *decl, const llvm::StringRef name, QualType type) {
3239-
const auto *semantic = hlsl::Semantic::GetByName(name);
3240-
SemanticInfo thisSemantic{name, semantic, name, 0, decl->getLocation()};
3241-
3242-
const auto *sigPoint =
3243-
deduceSigPoint(cast<DeclaratorDecl>(decl), /*asInput=*/false,
3244-
spvContext.getCurrentShaderModelKind(), /*forPCF=*/false);
3245-
3246-
StageVar stageVar(sigPoint, thisSemantic, decl->getAttr<VKBuiltInAttr>(),
3247-
type, /*locCount=*/1);
3248-
SpirvVariable *varInstr =
3249-
createSpirvStageVar(&stageVar, decl, name, thisSemantic.loc);
3250-
3251-
if (!varInstr)
3252-
return nullptr;
3253-
3254-
stageVar.setSpirvInstr(varInstr);
3255-
stageVar.setLocationAttr(decl->getAttr<VKLocationAttr>());
3256-
stageVar.setIndexAttr(decl->getAttr<VKIndexAttr>());
3257-
if (stageVar.getStorageClass() == spv::StorageClass::Input ||
3258-
stageVar.getStorageClass() == spv::StorageClass::Output) {
3259-
stageVar.setEntryPoint(entryFunction);
3260-
}
3261-
stageVars.push_back(stageVar);
3262-
3263-
// Emit OpDecorate* instructions to link this stage variable with the HLSL
3264-
// semantic it is created for.
3265-
spvBuilder.decorateHlslSemantic(varInstr, stageVar.getSemanticStr());
3266-
3267-
// We have semantics attached to this decl, which means it must be a
3268-
// function/parameter/variable. All are DeclaratorDecls.
3269-
stageVarInstructions[cast<DeclaratorDecl>(decl)] = varInstr;
3270-
3271-
return varInstr;
3272-
}
3273-
32743237
SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
32753238
StageVar *stageVar, const NamedDecl *decl, const llvm::StringRef name,
32763239
SourceLocation srcLoc) {
@@ -4008,21 +3971,6 @@ void DeclResultIdMapper::tryToCreateImplicitConstVar(const ValueDecl *decl) {
40083971
astDecls[varDecl].instr = constVal;
40093972
}
40103973

4011-
SpirvInstruction *
4012-
DeclResultIdMapper::createHullMainOutputPatch(const ParmVarDecl *param,
4013-
const QualType retType,
4014-
uint32_t numOutputControlPoints) {
4015-
const QualType hullMainRetType = astContext.getConstantArrayType(
4016-
retType, llvm::APInt(32, numOutputControlPoints),
4017-
clang::ArrayType::Normal, 0);
4018-
SpirvInstruction *hullMainOutputPatch = createSpirvIntermediateOutputStageVar(
4019-
param, "temp.var.hullMainRetVal", hullMainRetType);
4020-
assert(astDecls[param].instr == nullptr);
4021-
astDecls[param].instr = hullMainOutputPatch;
4022-
return hullMainOutputPatch;
4023-
}
4024-
4025-
40263974
template <typename Functor>
40273975
void DeclResultIdMapper::decorateWithIntrinsicAttrs(const NamedDecl *decl,
40283976
SpirvVariable *varInst,
@@ -4048,5 +3996,53 @@ void DeclResultIdMapper::decorateVariableWithIntrinsicAttrs(
40483996
decorateWithIntrinsicAttrs(decl, varInst, [](VKDecorateExtAttr *) {});
40493997
}
40503998

3999+
void DeclResultIdMapper::copyHullOutStageVarsToOutputPatch(
4000+
SpirvInstruction *hullMainOutputPatch, const ParmVarDecl *outputPatchDecl,
4001+
QualType outputControlPointType, uint32_t numOutputControlPoints) {
4002+
for (uint32_t outputCtrlPoint = 0; outputCtrlPoint < numOutputControlPoints;
4003+
++outputCtrlPoint) {
4004+
SpirvConstant *index = spvBuilder.getConstantInt(
4005+
astContext.UnsignedIntTy, llvm::APInt(32, outputCtrlPoint));
4006+
auto *tempLocation = spvBuilder.createAccessChain(
4007+
outputControlPointType, hullMainOutputPatch, {index}, /*loc=*/{});
4008+
storeOutStageVarsToStorage(cast<DeclaratorDecl>(outputPatchDecl), index,
4009+
outputControlPointType, tempLocation);
4010+
}
4011+
}
4012+
4013+
void DeclResultIdMapper::storeOutStageVarsToStorage(
4014+
const DeclaratorDecl *outputPatchDecl, SpirvConstant *ctrlPointID,
4015+
QualType outputControlPointType, SpirvInstruction *ptr) {
4016+
if (!outputControlPointType->isStructureType()) {
4017+
const auto found = stageVarInstructions.find(outputPatchDecl);
4018+
if (found == stageVarInstructions.end()) {
4019+
emitError("Shader output variable '%0' was not created", {})
4020+
<< outputPatchDecl->getName();
4021+
}
4022+
auto *ptrToOutputStageVar = spvBuilder.createAccessChain(
4023+
outputControlPointType, found->second, {ctrlPointID}, /*loc=*/{});
4024+
auto *load = spvBuilder.createLoad(outputControlPointType,
4025+
ptrToOutputStageVar, /*loc=*/{});
4026+
spvBuilder.createStore(ptr, load, /*loc=*/{});
4027+
return;
4028+
}
4029+
4030+
const auto *recordType = outputControlPointType->getAs<RecordType>();
4031+
assert(recordType != nullptr);
4032+
const auto *structDecl = recordType->getDecl();
4033+
assert(structDecl != nullptr);
4034+
4035+
uint32_t index = 0;
4036+
for (const auto *field : structDecl->fields()) {
4037+
SpirvConstant *indexInst = spvBuilder.getConstantInt(
4038+
astContext.UnsignedIntTy, llvm::APInt(32, index));
4039+
auto *tempLocation = spvBuilder.createAccessChain(field->getType(), ptr,
4040+
{indexInst}, /*loc=*/{});
4041+
storeOutStageVarsToStorage(cast<DeclaratorDecl>(field), ctrlPointID,
4042+
field->getType(), tempLocation);
4043+
++index;
4044+
}
4045+
}
4046+
40514047
} // end namespace spirv
40524048
} // end namespace clang

tools/clang/lib/SPIRV/DeclResultIdMapper.h

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,15 @@ class DeclResultIdMapper {
447447
/// VarDecls (such as some ray tracing enums).
448448
void tryToCreateImplicitConstVar(const ValueDecl *);
449449

450-
/// \brief Creates a variable for hull shader output patch with Output
451-
/// storage class, and registers the SPIR-V variable for the given decl.
452-
SpirvInstruction *createHullMainOutputPatch(const ParmVarDecl *param,
453-
const QualType retType,
454-
uint32_t numOutputControlPoints);
450+
/// \brief Creates instructions to copy output stage variables defined by
451+
/// outputPatchDecl to hullMainOutputPatch that is a variable for the
452+
/// OutputPatch argument passing. outputControlPointType is the template
453+
/// parameter type of OutputPatch and numOutputControlPoints is the number of
454+
/// output control points.
455+
void copyHullOutStageVarsToOutputPatch(SpirvInstruction *hullMainOutputPatch,
456+
const ParmVarDecl *outputPatchDecl,
457+
QualType outputControlPointType,
458+
uint32_t numOutputControlPoints);
455459

456460
/// \brief An enum class for representing what the DeclContext is used for
457461
enum class ContextUsageKind {
@@ -612,6 +616,17 @@ class DeclResultIdMapper {
612616
void decorateVariableWithIntrinsicAttrs(const NamedDecl *decl,
613617
SpirvVariable *varInst);
614618

619+
/// \brief Creates instructions to load the value of output stage variable
620+
/// defined by outputPatchDecl and store it to ptr. Since the output stage
621+
/// variable for OutputPatch is an array whose number of elements is the
622+
/// number of output control points, we need ctrlPointID to indicate which
623+
/// output control point is the target for copy. outputControlPointType is the
624+
/// template parameter type of OutputPatch.
625+
void storeOutStageVarsToStorage(const DeclaratorDecl *outputPatchDecl,
626+
SpirvConstant *ctrlPointID,
627+
QualType outputControlPointType,
628+
SpirvInstruction *ptr);
629+
615630
private:
616631
/// \brief Wrapper method to create a fatal error message and report it
617632
/// in the diagnostic engine associated with this consumer.
@@ -726,11 +741,6 @@ class DeclResultIdMapper {
726741
const llvm::StringRef name,
727742
SourceLocation);
728743

729-
// Create intermediate output variable to communicate patch constant
730-
// data in hull shader since workgroup memory is not allowed there.
731-
SpirvVariable *createSpirvIntermediateOutputStageVar(
732-
const NamedDecl *decl, const llvm::StringRef name, QualType asType);
733-
734744
/// Returns true if all vk:: attributes usages are valid.
735745
bool validateVKAttributes(const NamedDecl *decl);
736746

tools/clang/lib/SPIRV/SpirvEmitter.cpp

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,13 +1263,6 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
12631263
// Create all parameters.
12641264
for (uint32_t i = 0; i < decl->getNumParams(); ++i) {
12651265
const ParmVarDecl *paramDecl = decl->getParamDecl(i);
1266-
if (spvContext.isHS() && decl == patchConstFunc &&
1267-
hlsl::IsHLSLOutputPatchType(paramDecl->getType())) {
1268-
// Since the output patch used in hull shaders is translated to
1269-
// a variable with Output storage class, there is no need
1270-
// to pass the variable as function parameter in SPIR-V.
1271-
continue;
1272-
}
12731266
(void)declIdMapper.createFnParam(paramDecl, i + 1 + isNonStaticMemberFn);
12741267
}
12751268

@@ -11803,18 +11796,6 @@ bool SpirvEmitter::processHSEntryPointOutputAndPCF(
1180311796
return false;
1180411797
}
1180511798

11806-
SpirvInstruction *hullMainOutputPatch = nullptr;
11807-
// If the patch constant function (PCF) takes the result of the Hull main
11808-
// entry point, create a temporary function-scope variable and write the
11809-
// results to it, so it can be passed to the PCF.
11810-
if (const auto *param = patchConstFuncTakesHullOutputPatch(patchConstFunc)) {
11811-
hullMainOutputPatch = declIdMapper.createHullMainOutputPatch(
11812-
param, retType, numOutputControlPoints);
11813-
auto *tempLocation = spvBuilder.createAccessChain(
11814-
retType, hullMainOutputPatch, {outputControlPointId}, locEnd);
11815-
spvBuilder.createStore(tempLocation, retVal, locEnd);
11816-
}
11817-
1181811799
// Now create a barrier before calling the Patch Constant Function (PCF).
1181911800
// Flags are:
1182011801
// Execution Barrier scope = Workgroup (2)
@@ -11824,6 +11805,21 @@ bool SpirvEmitter::processHSEntryPointOutputAndPCF(
1182411805
spv::MemorySemanticsMask::MaskNone,
1182511806
spv::Scope::Workgroup, {});
1182611807

11808+
SpirvInstruction *hullMainOutputPatch = nullptr;
11809+
// If the patch constant function (PCF) takes the result of the Hull main
11810+
// entry point, create a temporary function-scope variable and write the
11811+
// results to it, so it can be passed to the PCF.
11812+
if (const ParmVarDecl *outputPatchDecl =
11813+
patchConstFuncTakesHullOutputPatch(patchConstFunc)) {
11814+
const QualType hullMainRetType = astContext.getConstantArrayType(
11815+
retType, llvm::APInt(32, numOutputControlPoints),
11816+
clang::ArrayType::Normal, 0);
11817+
hullMainOutputPatch =
11818+
spvBuilder.addFnVar(hullMainRetType, locEnd, "temp.var.hullMainRetVal");
11819+
declIdMapper.copyHullOutStageVarsToOutputPatch(
11820+
hullMainOutputPatch, outputPatchDecl, retType, numOutputControlPoints);
11821+
}
11822+
1182711823
// The PCF should be called only once. Therefore, we check the invocationID,
1182811824
// and we only allow ID 0 to call the PCF.
1182911825
auto *condition = spvBuilder.createBinaryOp(
@@ -11871,10 +11867,7 @@ bool SpirvEmitter::processHSEntryPointOutputAndPCF(
1187111867
if (hlsl::IsHLSLInputPatchType(param->getType())) {
1187211868
pcfParams.push_back(hullMainInputPatch);
1187311869
} else if (hlsl::IsHLSLOutputPatchType(param->getType())) {
11874-
// Since the output patch used in hull shaders is translated to
11875-
// a variable with Workgroup storage class, there is no need
11876-
// to pass the variable as function parameter in SPIR-V.
11877-
continue;
11870+
pcfParams.push_back(hullMainOutputPatch);
1187811871
} else if (hasSemantic(param, hlsl::DXIL::SemanticKind::PrimitiveID)) {
1187911872
if (!primitiveId) {
1188011873
primitiveId = createParmVarAndInitFromStageInputVar(param);

tools/clang/test/CodeGenSPIRV/hs.const.output-patch.hlsl

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,19 @@ struct HSPatchConstData {
1010
float4 constData : CONSTANTDATA;
1111
};
1212

13-
// CHECK: OpDecorate %temp_var_hullMainRetVal Location 2
14-
15-
// CHECK: %temp_var_hullMainRetVal = OpVariable %_ptr_Output__arr_HSCtrlPt_uint_3 Output
16-
// CHECK: [[invoc_id:%\d+]] = OpLoad %uint %gl_InvocationID
17-
// CHECK: [[HSResult:%\d+]] = OpFunctionCall %HSCtrlPt %src_main
18-
// CHECK: [[OutCtrl:%\d+]] = OpAccessChain %_ptr_Output_HSCtrlPt %temp_var_hullMainRetVal [[invoc_id]]
19-
// CHECK: OpStore [[OutCtrl]] [[HSResult]]
13+
// CHECK: OpFunctionCall %HSPatchConstData %HSPatchConstantFunc %temp_var_hullMainRetVal
2014

2115
HSPatchConstData HSPatchConstantFunc(const OutputPatch<HSCtrlPt, 3> input) {
2216
HSPatchConstData data;
2317

24-
// CHECK: [[OutCtrl0:%\d+]] = OpAccessChain %_ptr_Output_v4float %temp_var_hullMainRetVal %uint_0 %int_0
18+
// CHECK: %input = OpFunctionParameter %_ptr_Function__arr_HSCtrlPt_uint_3
19+
20+
// CHECK: [[OutCtrl0:%\d+]] = OpAccessChain %_ptr_Function_v4float %input %uint_0 %int_0
2521
// CHECK: [[input0:%\d+]] = OpLoad %v4float [[OutCtrl0]]
26-
// CHECK: [[OutCtrl1:%\d+]] = OpAccessChain %_ptr_Output_v4float %temp_var_hullMainRetVal %uint_1 %int_0
22+
// CHECK: [[OutCtrl1:%\d+]] = OpAccessChain %_ptr_Function_v4float %input %uint_1 %int_0
2723
// CHECK: [[input1:%\d+]] = OpLoad %v4float [[OutCtrl1]]
2824
// CHECK: [[add:%\d+]] = OpFAdd %v4float [[input0]] [[input1]]
29-
// CHECK: [[OutCtrl2:%\d+]] = OpAccessChain %_ptr_Output_v4float %temp_var_hullMainRetVal %uint_2 %int_0
25+
// CHECK: [[OutCtrl2:%\d+]] = OpAccessChain %_ptr_Function_v4float %input %uint_2 %int_0
3026
// CHECK: [[input2:%\d+]] = OpLoad %v4float [[OutCtrl2]]
3127
// CHECK: OpFAdd %v4float [[add]] [[input2]]
3228
data.constData = input[0].ctrlPt + input[1].ctrlPt + input[2].ctrlPt;

tools/clang/test/CodeGenSPIRV/hs.pcf.output-patch.hlsl

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,38 @@
55
// Test: PCF takes the output (OutputPatch) of the main entry point function.
66

77

8-
// CHECK: %_arr_BEZIER_CONTROL_POINT_uint_16 = OpTypeArray %BEZIER_CONTROL_POINT %uint_16
9-
// CHECK: %_ptr_Output__arr_BEZIER_CONTROL_POINT_uint_16 = OpTypePointer Output %_arr_BEZIER_CONTROL_POINT_uint_16
8+
// CHECK: %_arr_BEZIER_CONTROL_POINT_uint_3 = OpTypeArray %BEZIER_CONTROL_POINT %uint_3
9+
// CHECK: %_ptr_Function__arr_BEZIER_CONTROL_POINT_uint_3 = OpTypePointer Function %_arr_BEZIER_CONTROL_POINT_uint_3
1010
// CHECK: [[fType:%\d+]] = OpTypeFunction %HS_CONSTANT_DATA_OUTPUT
11-
// CHECK: %temp_var_hullMainRetVal = OpVariable %_ptr_Output__arr_BEZIER_CONTROL_POINT_uint_16 Output
1211

1312
// CHECK: %main = OpFunction %void None {{%\d+}}
13+
// CHECK: %temp_var_hullMainRetVal = OpVariable %_ptr_Function__arr_BEZIER_CONTROL_POINT_uint_3 Function
1414

15-
// CHECK: [[id:%\d+]] = OpLoad %uint %gl_InvocationID
1615
// CHECK: [[mainResult:%\d+]] = OpFunctionCall %BEZIER_CONTROL_POINT %src_main %param_var_ip %param_var_i %param_var_PatchID
17-
// CHECK: [[loc:%\d+]] = OpAccessChain %_ptr_Output_BEZIER_CONTROL_POINT %temp_var_hullMainRetVal [[id]]
18-
// CHECK: OpStore [[loc]] [[mainResult]]
1916

20-
// CHECK: {{%\d+}} = OpFunctionCall %HS_CONSTANT_DATA_OUTPUT %PCF
17+
// CHECK: [[output_patch_0:%\d+]] = OpAccessChain %_ptr_Function_BEZIER_CONTROL_POINT %temp_var_hullMainRetVal %uint_0
18+
// CHECK: [[output_patch_0_0:%\d+]] = OpAccessChain %_ptr_Function_v3float [[output_patch_0]] %uint_0
19+
// CHECK: [[out_var_BEZIERPOS_0:%\d+]] = OpAccessChain %_ptr_Output_v3float %out_var_BEZIERPOS %uint_0
20+
// CHECK: [[BEZIERPOS_0:%\d+]] = OpLoad %v3float [[out_var_BEZIERPOS_0]]
21+
// CHECK: OpStore [[output_patch_0_0]] [[BEZIERPOS_0]]
22+
23+
// CHECK: [[output_patch_1:%\d+]] = OpAccessChain %_ptr_Function_BEZIER_CONTROL_POINT %temp_var_hullMainRetVal %uint_1
24+
// CHECK: [[output_patch_1_0:%\d+]] = OpAccessChain %_ptr_Function_v3float [[output_patch_1]] %uint_0
25+
// CHECK: [[out_var_BEZIERPOS_1:%\d+]] = OpAccessChain %_ptr_Output_v3float %out_var_BEZIERPOS %uint_1
26+
// CHECK: [[BEZIERPOS_1:%\d+]] = OpLoad %v3float [[out_var_BEZIERPOS_1]]
27+
// CHECK: OpStore [[output_patch_1_0]] [[BEZIERPOS_1]]
28+
29+
// CHECK: [[output_patch_2:%\d+]] = OpAccessChain %_ptr_Function_BEZIER_CONTROL_POINT %temp_var_hullMainRetVal %uint_2
30+
// CHECK: [[output_patch_2_0:%\d+]] = OpAccessChain %_ptr_Function_v3float [[output_patch_2]] %uint_0
31+
// CHECK: [[out_var_BEZIERPOS_2:%\d+]] = OpAccessChain %_ptr_Output_v3float %out_var_BEZIERPOS %uint_2
32+
// CHECK: [[BEZIERPOS_2:%\d+]] = OpLoad %v3float [[out_var_BEZIERPOS_2]]
33+
// CHECK: OpStore [[output_patch_2_0]] [[BEZIERPOS_2]]
34+
35+
// CHECK: {{%\d+}} = OpFunctionCall %HS_CONSTANT_DATA_OUTPUT %PCF %temp_var_hullMainRetVal
2136

2237
// CHECK: %PCF = OpFunction %HS_CONSTANT_DATA_OUTPUT None [[fType]]
2338

24-
HS_CONSTANT_DATA_OUTPUT PCF(OutputPatch<BEZIER_CONTROL_POINT, MAX_POINTS> op) {
39+
HS_CONSTANT_DATA_OUTPUT PCF(OutputPatch<BEZIER_CONTROL_POINT, 3> op) {
2540
HS_CONSTANT_DATA_OUTPUT Output;
2641
// Must initialize Edges and Inside; otherwise HLSL validation will fail.
2742
Output.Edges[0] = 1.0;
@@ -36,9 +51,9 @@ HS_CONSTANT_DATA_OUTPUT PCF(OutputPatch<BEZIER_CONTROL_POINT, MAX_POINTS> op) {
3651
[domain("isoline")]
3752
[partitioning("fractional_odd")]
3853
[outputtopology("line")]
39-
[outputcontrolpoints(16)]
54+
[outputcontrolpoints(3)]
4055
[patchconstantfunc("PCF")]
41-
BEZIER_CONTROL_POINT main(InputPatch<VS_CONTROL_POINT_OUTPUT, MAX_POINTS> ip, uint i : SV_OutputControlPointID, uint PatchID : SV_PrimitiveID) {
56+
BEZIER_CONTROL_POINT main(InputPatch<VS_CONTROL_POINT_OUTPUT, 3> ip, uint i : SV_OutputControlPointID, uint PatchID : SV_PrimitiveID) {
4257
VS_CONTROL_POINT_OUTPUT vsOutput;
4358
BEZIER_CONTROL_POINT result;
4459
result.vPosition = vsOutput.vPosition;

tools/clang/test/CodeGenSPIRV/method.input-output-patch.access.hlsl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct HS_CONSTANT_DATA_OUTPUT
3131
};
3232

3333
HS_CONSTANT_DATA_OUTPUT PCF(OutputPatch<BEZIER_CONTROL_POINT, MAX_POINTS> op) {
34+
// CHECK: %op = OpFunctionParameter %_ptr_Function__arr_BEZIER_CONTROL_POINT_uint_16
3435
HS_CONSTANT_DATA_OUTPUT Output;
3536
// Must initialize Edges and Inside; otherwise HLSL validation will fail.
3637
Output.Edges[0] = 1.0;
@@ -42,12 +43,12 @@ HS_CONSTANT_DATA_OUTPUT PCF(OutputPatch<BEZIER_CONTROL_POINT, MAX_POINTS> op) {
4243

4344
uint x = 5;
4445

45-
// CHECK: [[op_1_loc:%\d+]] = OpAccessChain %_ptr_Output_v3float %temp_var_hullMainRetVal %uint_1 %int_0
46+
// CHECK: [[op_1_loc:%\d+]] = OpAccessChain %_ptr_Function_v3float %op %uint_1 %int_0
4647
// CHECK-NEXT: {{%\d+}} = OpLoad %v3float [[op_1_loc]]
4748
float3 out1pos = op[1].vPosition;
4849

4950
// CHECK: [[x:%\d+]] = OpLoad %uint %x
50-
// CHECK-NEXT: [[op_x_loc:%\d+]] = OpAccessChain %_ptr_Output_uint %temp_var_hullMainRetVal [[x]] %int_1
51+
// CHECK-NEXT: [[op_x_loc:%\d+]] = OpAccessChain %_ptr_Function_uint %op [[x]] %int_1
5152
// CHECK-NEXT: {{%\d+}} = OpLoad %uint [[op_x_loc]]
5253
uint out5id = op[x].pointID;
5354

0 commit comments

Comments
 (0)