[spirv] Handle TessFactor size mismatches. (#771)
This commit is contained in:
Родитель
dc3d2c7921
Коммит
7cb1c20853
|
@ -765,12 +765,14 @@ bool DeclResultIdMapper::createStageVars(
|
||||||
uint32_t semanticIndex = {};
|
uint32_t semanticIndex = {};
|
||||||
|
|
||||||
if (getStageVarSemantic(decl, &semanticStr, &semantic, &semanticIndex)) {
|
if (getStageVarSemantic(decl, &semanticStr, &semantic, &semanticIndex)) {
|
||||||
|
const auto semanticKind = semantic->GetKind();
|
||||||
|
|
||||||
// Found semantic attached directly to this Decl. This means we need to
|
// Found semantic attached directly to this Decl. This means we need to
|
||||||
// map this decl to a single stage variable.
|
// map this decl to a single stage variable.
|
||||||
|
|
||||||
// Error out when the given semantic is invalid in this shader model
|
// Error out when the given semantic is invalid in this shader model
|
||||||
if (hlsl::SigPoint::GetInterpretation(
|
if (hlsl::SigPoint::GetInterpretation(semanticKind, sigPoint->GetKind(),
|
||||||
semantic->GetKind(), sigPoint->GetKind(), shaderModel.GetMajor(),
|
shaderModel.GetMajor(),
|
||||||
shaderModel.GetMinor()) ==
|
shaderModel.GetMinor()) ==
|
||||||
hlsl::DXIL::SemanticInterpretationKind::NA) {
|
hlsl::DXIL::SemanticInterpretationKind::NA) {
|
||||||
emitError("invalid semantic %0 for shader model %1")
|
emitError("invalid semantic %0 for shader model %1")
|
||||||
|
@ -785,12 +787,24 @@ bool DeclResultIdMapper::createStageVars(
|
||||||
// * SV_DomainLocation can refer to a float2, whereas TessCoord is a float3.
|
// * SV_DomainLocation can refer to a float2, whereas TessCoord is a float3.
|
||||||
// To ensure SPIR-V validity, we must create a float3 and extract a
|
// To ensure SPIR-V validity, we must create a float3 and extract a
|
||||||
// float2 from it before passing it to the main function.
|
// float2 from it before passing it to the main function.
|
||||||
if (glPerVertex.tryToAccess(semantic->GetKind(), semanticIndex,
|
// * SV_TessFactor is an array of size 2 for isoline patch, array of size 3
|
||||||
invocationId, value, sigPoint->GetKind()))
|
// for tri patch, and array of size 4 for quad patch, but it must always
|
||||||
|
// be an array of size 4 in SPIR-V for Vulkan.
|
||||||
|
// * SV_InsideTessFactor is a single float for tri patch, and an array of
|
||||||
|
// size 2 for a quad patch, but it must always be an array of size 2 in
|
||||||
|
// SPIR-V for Vulkan.
|
||||||
|
if (glPerVertex.tryToAccess(semanticKind, semanticIndex, invocationId,
|
||||||
|
value, sigPoint->GetKind()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (semantic->GetKind() == hlsl::Semantic::Kind::DomainLocation)
|
if (semanticKind == hlsl::Semantic::Kind::DomainLocation)
|
||||||
typeId = theBuilder.getVecType(theBuilder.getFloat32Type(), 3);
|
typeId = theBuilder.getVecType(theBuilder.getFloat32Type(), 3);
|
||||||
|
else if (semanticKind == hlsl::Semantic::Kind::TessFactor)
|
||||||
|
typeId = theBuilder.getArrayType(theBuilder.getFloat32Type(),
|
||||||
|
theBuilder.getConstantUint32(4));
|
||||||
|
else if (semanticKind == hlsl::Semantic::Kind::InsideTessFactor)
|
||||||
|
typeId = theBuilder.getArrayType(theBuilder.getFloat32Type(),
|
||||||
|
theBuilder.getConstantUint32(2));
|
||||||
|
|
||||||
// Handle the extra arrayness
|
// Handle the extra arrayness
|
||||||
const uint32_t elementTypeId = typeId;
|
const uint32_t elementTypeId = typeId;
|
||||||
|
@ -820,18 +834,94 @@ bool DeclResultIdMapper::createStageVars(
|
||||||
|
|
||||||
if (asInput) {
|
if (asInput) {
|
||||||
*value = theBuilder.createLoad(typeId, varId);
|
*value = theBuilder.createLoad(typeId, varId);
|
||||||
|
|
||||||
|
// Fix ups for corner cases
|
||||||
|
|
||||||
|
// Special handling of SV_TessFactor DS patch constant input.
|
||||||
|
// TessLevelOuter is always an array of size 4 in SPIR-V, but
|
||||||
|
// SV_TessFactor could be an array of size 2, 3, or 4 in HLSL. Only the
|
||||||
|
// relevant indexes must be loaded.
|
||||||
|
if (semanticKind == hlsl::Semantic::Kind::TessFactor &&
|
||||||
|
hlsl::GetArraySize(type) != 4) {
|
||||||
|
llvm::SmallVector<uint32_t, 4> components;
|
||||||
|
const auto f32TypeId = theBuilder.getFloat32Type();
|
||||||
|
const auto tessFactorSize = hlsl::GetArraySize(type);
|
||||||
|
const auto arrType = theBuilder.getArrayType(
|
||||||
|
f32TypeId, theBuilder.getConstantUint32(tessFactorSize));
|
||||||
|
for (uint32_t i = 0; i < tessFactorSize; ++i)
|
||||||
|
components.push_back(
|
||||||
|
theBuilder.createCompositeExtract(f32TypeId, *value, {i}));
|
||||||
|
*value = theBuilder.createCompositeConstruct(arrType, components);
|
||||||
|
}
|
||||||
|
// Special handling of SV_InsideTessFactor DS patch constant input.
|
||||||
|
// TessLevelInner is always an array of size 2 in SPIR-V, but
|
||||||
|
// SV_InsideTessFactor could be an array of size 1 (scalar) or size 2 in
|
||||||
|
// HLSL. If SV_InsideTessFactor is a scalar, only extract index 0 of
|
||||||
|
// TessLevelInner.
|
||||||
|
else if (semanticKind == hlsl::Semantic::Kind::InsideTessFactor &&
|
||||||
|
!type->isArrayType()) {
|
||||||
|
*value = theBuilder.createCompositeExtract(theBuilder.getFloat32Type(),
|
||||||
|
*value, {0});
|
||||||
|
}
|
||||||
|
// SV_DomainLocation can refer to a float2 or a float3, whereas TessCoord
|
||||||
|
// is always a float3. To ensure SPIR-V validity, a float3 stage variable
|
||||||
|
// is created, and we must extract a float2 from it before passing it to
|
||||||
|
// the main function.
|
||||||
|
else if (semanticKind == hlsl::Semantic::Kind::DomainLocation &&
|
||||||
|
hlsl::GetHLSLVecSize(type) != 3) {
|
||||||
|
const auto domainLocSize = hlsl::GetHLSLVecSize(type);
|
||||||
|
*value = theBuilder.createVectorShuffle(
|
||||||
|
theBuilder.getVecType(theBuilder.getFloat32Type(), domainLocSize),
|
||||||
|
*value, *value, {0, 1});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uint32_t ptr = varId;
|
uint32_t ptr = varId;
|
||||||
if (invocationId.hasValue()) {
|
|
||||||
// Special handling of HS ouput, for which we write to only one element
|
// Special handling of SV_TessFactor HS patch constant output.
|
||||||
// in the per-vertex data array: the one indexed by SV_ControlPointID.
|
// TessLevelOuter is always an array of size 4 in SPIR-V, but
|
||||||
|
// SV_TessFactor could be an array of size 2, 3, or 4 in HLSL. Only the
|
||||||
|
// relevant indexes must be written to.
|
||||||
|
if (semanticKind == hlsl::Semantic::Kind::TessFactor &&
|
||||||
|
hlsl::GetArraySize(type) != 4) {
|
||||||
|
const auto f32TypeId = theBuilder.getFloat32Type();
|
||||||
|
const auto tessFactorSize = hlsl::GetArraySize(type);
|
||||||
|
for (uint32_t i = 0; i < tessFactorSize; ++i) {
|
||||||
|
const uint32_t ptrType =
|
||||||
|
theBuilder.getPointerType(f32TypeId, spv::StorageClass::Output);
|
||||||
|
ptr = theBuilder.createAccessChain(ptrType, varId,
|
||||||
|
theBuilder.getConstantUint32(i));
|
||||||
|
theBuilder.createStore(
|
||||||
|
ptr, theBuilder.createCompositeExtract(f32TypeId, *value, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Special handling of SV_InsideTessFactor HS patch constant output.
|
||||||
|
// TessLevelInner is always an array of size 2 in SPIR-V, but
|
||||||
|
// SV_InsideTessFactor could be an array of size 1 (scalar) or size 2 in
|
||||||
|
// HLSL. If SV_InsideTessFactor is a scalar, only write to index 0 of
|
||||||
|
// TessLevelInner.
|
||||||
|
else if (semanticKind == hlsl::Semantic::Kind::InsideTessFactor &&
|
||||||
|
!type->isArrayType()) {
|
||||||
|
ptr = theBuilder.createAccessChain(
|
||||||
|
theBuilder.getPointerType(theBuilder.getFloat32Type(),
|
||||||
|
spv::StorageClass::Output),
|
||||||
|
varId, theBuilder.getConstantUint32(0));
|
||||||
|
theBuilder.createStore(ptr, *value);
|
||||||
|
}
|
||||||
|
// Special handling of HS ouput, for which we write to only one
|
||||||
|
// element in the per-vertex data array: the one indexed by
|
||||||
|
// SV_ControlPointID.
|
||||||
|
else if (invocationId.hasValue()) {
|
||||||
const uint32_t ptrType =
|
const uint32_t ptrType =
|
||||||
theBuilder.getPointerType(elementTypeId, spv::StorageClass::Output);
|
theBuilder.getPointerType(elementTypeId, spv::StorageClass::Output);
|
||||||
const uint32_t index = invocationId.getValue();
|
const uint32_t index = invocationId.getValue();
|
||||||
ptr = theBuilder.createAccessChain(ptrType, varId, index);
|
ptr = theBuilder.createAccessChain(ptrType, varId, index);
|
||||||
}
|
|
||||||
theBuilder.createStore(ptr, *value);
|
theBuilder.createStore(ptr, *value);
|
||||||
}
|
}
|
||||||
|
// For all normal cases
|
||||||
|
else {
|
||||||
|
theBuilder.createStore(ptr, *value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5767,15 +5767,6 @@ bool SPIRVEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl,
|
||||||
if (!declIdMapper.createStageInputVar(param, &loadedValue, false))
|
if (!declIdMapper.createStageInputVar(param, &loadedValue, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// SV_DomainLocation can refer to a float2, whereas TessCoord is a float3.
|
|
||||||
// To ensure SPIR-V validity, a float3 stage variable is created, and we
|
|
||||||
// must extract a float2 from it before passing it to the main function.
|
|
||||||
if (hasSemantic(param, hlsl::DXIL::SemanticKind::DomainLocation) &&
|
|
||||||
hlsl::GetHLSLVecSize(param->getType()) == 2) {
|
|
||||||
loadedValue = theBuilder.createVectorShuffle(typeId, loadedValue,
|
|
||||||
loadedValue, {0, 1});
|
|
||||||
}
|
|
||||||
|
|
||||||
theBuilder.createStore(tempVar, loadedValue);
|
theBuilder.createStore(tempVar, loadedValue);
|
||||||
|
|
||||||
// Record the temporary variable holding SV_OutputControlPointID and
|
// Record the temporary variable holding SV_OutputControlPointID and
|
||||||
|
|
|
@ -44,7 +44,7 @@ HS_CONSTANT_DATA_OUTPUT SubDToBezierConstantsHS(InputPatch<VS_CONTROL_POINT_OUTP
|
||||||
return Output;
|
return Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
[domain("tri")]
|
[domain("quad")]
|
||||||
[partitioning("fractional_odd")]
|
[partitioning("fractional_odd")]
|
||||||
[outputtopology("triangle_ccw")]
|
[outputtopology("triangle_ccw")]
|
||||||
[outputcontrolpoints(MAX_POINTS)]
|
[outputcontrolpoints(MAX_POINTS)]
|
||||||
|
@ -60,7 +60,7 @@ BEZIER_CONTROL_POINT SubDToBezierHS(InputPatch<VS_CONTROL_POINT_OUTPUT, MAX_POIN
|
||||||
// OpCapability Tessellation
|
// OpCapability Tessellation
|
||||||
// OpMemoryModel Logical GLSL450
|
// OpMemoryModel Logical GLSL450
|
||||||
// OpEntryPoint TessellationControl %SubDToBezierHS "SubDToBezierHS" %gl_PerVertexIn %gl_PerVertexOut %in_var_WORLDPOS %in_var_TEXCOORD0 %in_var_TANGENT %gl_InvocationID %gl_PrimitiveID %out_var_BEZIERPOS %gl_TessLevelOuter %gl_TessLevelInner %out_var_TANGENT %out_var_TEXCOORD %out_var_TANUCORNER %out_var_TANVCORNER %out_var_TANWEIGHTS
|
// OpEntryPoint TessellationControl %SubDToBezierHS "SubDToBezierHS" %gl_PerVertexIn %gl_PerVertexOut %in_var_WORLDPOS %in_var_TEXCOORD0 %in_var_TANGENT %gl_InvocationID %gl_PrimitiveID %out_var_BEZIERPOS %gl_TessLevelOuter %gl_TessLevelInner %out_var_TANGENT %out_var_TEXCOORD %out_var_TANUCORNER %out_var_TANVCORNER %out_var_TANWEIGHTS
|
||||||
// OpExecutionMode %SubDToBezierHS Triangles
|
// OpExecutionMode %SubDToBezierHS Quads
|
||||||
// OpExecutionMode %SubDToBezierHS SpacingFractionalOdd
|
// OpExecutionMode %SubDToBezierHS SpacingFractionalOdd
|
||||||
// OpExecutionMode %SubDToBezierHS VertexOrderCcw
|
// OpExecutionMode %SubDToBezierHS VertexOrderCcw
|
||||||
// OpExecutionMode %SubDToBezierHS OutputVertices 3
|
// OpExecutionMode %SubDToBezierHS OutputVertices 3
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
// Run: %dxc -T ds_6_0 -E BezierEvalDS
|
||||||
|
|
||||||
|
// Test handling of built-in size mismatch (reading in from the built-ins):
|
||||||
|
// The HLSL SV_TessFactor is a float3, but the SPIR-V equivalent is a float4.
|
||||||
|
// The HLSL SV_InsideTessFactor is a scalar float, but the SPIR-V equivalent is a float2.
|
||||||
|
|
||||||
|
// CHECK: OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
|
||||||
|
// CHECK: OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
|
||||||
|
|
||||||
|
// CHECK: %HS_CONSTANT_DATA_OUTPUT = OpTypeStruct %_arr_float_uint_3 %float
|
||||||
|
|
||||||
|
// CHECK: %gl_TessLevelOuter = OpVariable %_ptr_Input__arr_float_uint_4 Input
|
||||||
|
// CHECK: %gl_TessLevelInner = OpVariable %_ptr_Input__arr_float_uint_2 Input
|
||||||
|
|
||||||
|
// CHECK: [[gl_TessLevelOuter:%\d+]] = OpLoad %_arr_float_uint_4 %gl_TessLevelOuter
|
||||||
|
// CHECK-NEXT: [[gl_TessLevelOuter0:%\d+]] = OpCompositeExtract %float [[gl_TessLevelOuter]] 0
|
||||||
|
// CHECK-NEXT: [[gl_TessLevelOuter1:%\d+]] = OpCompositeExtract %float [[gl_TessLevelOuter]] 1
|
||||||
|
// CHECK-NEXT: [[gl_TessLevelOuter2:%\d+]] = OpCompositeExtract %float [[gl_TessLevelOuter]] 2
|
||||||
|
// CHECK-NEXT: [[tessLevelOuterArr3:%\d+]] = OpCompositeConstruct %_arr_float_uint_3 [[gl_TessLevelOuter0]] [[gl_TessLevelOuter1]] [[gl_TessLevelOuter2]]
|
||||||
|
// CHECK-NEXT: [[gl_TessLevelInner:%\d+]] = OpLoad %_arr_float_uint_2 %gl_TessLevelInner
|
||||||
|
// CHECK-NEXT: [[tessLevelOuterScalar:%\d+]] = OpCompositeExtract %float [[gl_TessLevelInner]] 0
|
||||||
|
// CHECK-NEXT: {{%\d+}} = OpCompositeConstruct %HS_CONSTANT_DATA_OUTPUT [[tessLevelOuterArr3]] [[tessLevelOuterScalar]]
|
||||||
|
|
||||||
|
|
||||||
|
struct HS_CONSTANT_DATA_OUTPUT
|
||||||
|
{
|
||||||
|
float Edges[3] : SV_TessFactor;
|
||||||
|
float Inside : SV_InsideTessFactor;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Output control point (output of hull shader)
|
||||||
|
struct BEZIER_CONTROL_POINT
|
||||||
|
{
|
||||||
|
float3 vPosition : BEZIERPOS;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The domain shader outputs
|
||||||
|
struct DS_OUTPUT
|
||||||
|
{
|
||||||
|
float4 vPosition : SV_POSITION;
|
||||||
|
};
|
||||||
|
|
||||||
|
[domain("tri")]
|
||||||
|
DS_OUTPUT BezierEvalDS( HS_CONSTANT_DATA_OUTPUT input,
|
||||||
|
float2 UV : SV_DomainLocation,
|
||||||
|
const OutputPatch<BEZIER_CONTROL_POINT, 3> bezpatch )
|
||||||
|
{
|
||||||
|
DS_OUTPUT Output;
|
||||||
|
return Output;
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
// Run: %dxc -T hs_6_0 -E SubDToBezierHS
|
||||||
|
|
||||||
|
// Test handling of built-in size mismatch (writing out to the built-ins):
|
||||||
|
// The HLSL SV_TessFactor is a float3, but the SPIR-V equivalent is a float4.
|
||||||
|
// The HLSL SV_InsideTessFactor is a scalar float, but the SPIR-V equivalent is a float2.
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK: OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
|
||||||
|
// CHECK: OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
|
||||||
|
|
||||||
|
// CHECK: %HS_CONSTANT_DATA_OUTPUT = OpTypeStruct %_arr_float_uint_3 %float %_arr_v3float_uint_4 %_arr_v2float_uint_4 %_arr_v3float_uint_4 %_arr_v3float_uint_4 %v4float
|
||||||
|
|
||||||
|
// CHECK: %gl_TessLevelOuter = OpVariable %_ptr_Output__arr_float_uint_4 Output
|
||||||
|
// CHECK: %gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output
|
||||||
|
|
||||||
|
// CHECK: [[pcfRet:%\d+]] = OpFunctionCall %HS_CONSTANT_DATA_OUTPUT %SubDToBezierConstantsHS %param_var_ip %param_var_PatchID
|
||||||
|
|
||||||
|
// CHECK-NEXT: [[pcfRetTessFactor:%\d+]] = OpCompositeExtract %_arr_float_uint_3 [[pcfRet]] 0
|
||||||
|
// CHECK-NEXT: [[gl_TessLevelOuter_loc0:%\d+]] = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_0
|
||||||
|
// CHECK-NEXT: [[pcfRetTessFactor0:%\d+]] = OpCompositeExtract %float [[pcfRetTessFactor]] 0
|
||||||
|
// CHECK-NEXT: OpStore [[gl_TessLevelOuter_loc0]] [[pcfRetTessFactor0]]
|
||||||
|
|
||||||
|
// CHECK-NEXT: [[gl_TessLevelOuter_loc1:%\d+]] = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_1
|
||||||
|
// CHECK-NEXT: [[pcfRetTessFactor1:%\d+]] = OpCompositeExtract %float [[pcfRetTessFactor]] 1
|
||||||
|
// CHECK-NEXT: OpStore [[gl_TessLevelOuter_loc1]] [[pcfRetTessFactor1]]
|
||||||
|
|
||||||
|
// CHECK-NEXT: [[gl_TessLevelOuter_loc2:%\d+]] = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_2
|
||||||
|
// CHECK-NEXT: [[pcfRetTessFactor2:%\d+]] = OpCompositeExtract %float [[pcfRetTessFactor]] 2
|
||||||
|
// CHECK-NEXT: OpStore [[gl_TessLevelOuter_loc2]] [[pcfRetTessFactor2]]
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK-NEXT: [[pcfRetInsideTessFactor:%\d+]] = OpCompositeExtract %float [[pcfRet]] 1
|
||||||
|
// CHECK-NEXT: [[gl_TessLevelInner_loc0:%\d+]] = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %uint_0
|
||||||
|
// CHECK-NEXT: OpStore [[gl_TessLevelInner_loc0]] [[pcfRetInsideTessFactor]]
|
||||||
|
|
||||||
|
#define MAX_POINTS 3
|
||||||
|
|
||||||
|
// Input control point
|
||||||
|
struct VS_CONTROL_POINT_OUTPUT
|
||||||
|
{
|
||||||
|
float3 vPosition : WORLDPOS;
|
||||||
|
float2 vUV : TEXCOORD0;
|
||||||
|
float3 vTangent : TANGENT;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Output control point
|
||||||
|
struct BEZIER_CONTROL_POINT
|
||||||
|
{
|
||||||
|
float3 vPosition : BEZIERPOS;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Output patch constant data.
|
||||||
|
struct HS_CONSTANT_DATA_OUTPUT
|
||||||
|
{
|
||||||
|
float Edges[3] : SV_TessFactor;
|
||||||
|
float Inside : SV_InsideTessFactor;
|
||||||
|
|
||||||
|
float3 vTangent[4] : TANGENT;
|
||||||
|
float2 vUV[4] : TEXCOORD;
|
||||||
|
float3 vTanUCorner[4] : TANUCORNER;
|
||||||
|
float3 vTanVCorner[4] : TANVCORNER;
|
||||||
|
float4 vCWts : TANWEIGHTS;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Patch Constant Function
|
||||||
|
HS_CONSTANT_DATA_OUTPUT SubDToBezierConstantsHS(InputPatch<VS_CONTROL_POINT_OUTPUT, MAX_POINTS> ip, uint PatchID : SV_PrimitiveID) {
|
||||||
|
HS_CONSTANT_DATA_OUTPUT Output;
|
||||||
|
|
||||||
|
// Must initialize Edges and Inside; otherwise HLSL validation will fail.
|
||||||
|
Output.Edges[0] = 1.0;
|
||||||
|
Output.Edges[1] = 2.0;
|
||||||
|
Output.Edges[2] = 3.0;
|
||||||
|
Output.Inside = 4.0;
|
||||||
|
|
||||||
|
return Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
[domain("tri")]
|
||||||
|
[partitioning("fractional_odd")]
|
||||||
|
[outputtopology("triangle_ccw")]
|
||||||
|
[outputcontrolpoints(MAX_POINTS)]
|
||||||
|
[patchconstantfunc("SubDToBezierConstantsHS")]
|
||||||
|
BEZIER_CONTROL_POINT SubDToBezierHS(InputPatch<VS_CONTROL_POINT_OUTPUT, MAX_POINTS> ip, uint cpid : SV_OutputControlPointID, uint PatchID : SV_PrimitiveID) {
|
||||||
|
VS_CONTROL_POINT_OUTPUT vsOutput;
|
||||||
|
BEZIER_CONTROL_POINT result;
|
||||||
|
result.vPosition = vsOutput.vPosition;
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -396,12 +396,18 @@ TEST_F(FileTest, SemanticDomainLocationDS) {
|
||||||
TEST_F(FileTest, SemanticTessFactorDS) {
|
TEST_F(FileTest, SemanticTessFactorDS) {
|
||||||
runFileTest("semantic.tess-factor.ds.hlsl");
|
runFileTest("semantic.tess-factor.ds.hlsl");
|
||||||
}
|
}
|
||||||
|
TEST_F(FileTest, SemanticTessFactorSizeMismatchDS) {
|
||||||
|
runFileTest("semantic.tess-factor.size-mismatch.ds.hlsl");
|
||||||
|
}
|
||||||
TEST_F(FileTest, SemanticInsideTessFactorDS) {
|
TEST_F(FileTest, SemanticInsideTessFactorDS) {
|
||||||
runFileTest("semantic.inside-tess-factor.ds.hlsl");
|
runFileTest("semantic.inside-tess-factor.ds.hlsl");
|
||||||
}
|
}
|
||||||
TEST_F(FileTest, SemanticTessFactorHS) {
|
TEST_F(FileTest, SemanticTessFactorHS) {
|
||||||
runFileTest("semantic.tess-factor.hs.hlsl");
|
runFileTest("semantic.tess-factor.hs.hlsl");
|
||||||
}
|
}
|
||||||
|
TEST_F(FileTest, SemanticTessFactorSizeMismatchHS) {
|
||||||
|
runFileTest("semantic.tess-factor.size-mismatch.hs.hlsl");
|
||||||
|
}
|
||||||
TEST_F(FileTest, SemanticInsideTessFactorHS) {
|
TEST_F(FileTest, SemanticInsideTessFactorHS) {
|
||||||
runFileTest("semantic.inside-tess-factor.hs.hlsl");
|
runFileTest("semantic.inside-tess-factor.hs.hlsl");
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче