shader: preserve counterclockwise tessellation output

This commit is contained in:
Çağatay Güçlü
2026-10-28 23:49:51 +01:00
committed by nmzik
parent 54b937c85f
commit 143f640706
2 changed files with 13 additions and 6 deletions
@@ -130,10 +130,10 @@ void DefineTessellationInterfaces(EmitterState& state) {
void DefineTessellationExecutionModes(EmitterState& state) { void DefineTessellationExecutionModes(EmitterState& state) {
const auto& tess = state.input_info.vertex->tess; const auto& tess = state.input_info.vertex->tess;
// Triangle or quad domain, integer or fractional-odd partitioning, clockwise output. // Triangle or quad domain, integer or fractional-odd partitioning, triangle output.
EXIT_NOT_IMPLEMENTED((tess.domain != 1u && tess.domain != 2u) || EXIT_NOT_IMPLEMENTED((tess.domain != 1u && tess.domain != 2u) ||
(tess.partitioning != 0u && tess.partitioning != 2u) || (tess.partitioning != 0u && tess.partitioning != 2u) ||
tess.output_topology != 2u); (tess.output_topology != 2u && tess.output_topology != 3u));
state.builder.RequireCapability(spv::CapabilityTessellation); state.builder.RequireCapability(spv::CapabilityTessellation);
if (state.program.stage == ShaderType::TessellationControl) { if (state.program.stage == ShaderType::TessellationControl) {
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeOutputVertices, state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeOutputVertices,
@@ -145,7 +145,9 @@ void DefineTessellationExecutionModes(EmitterState& state) {
state.builder.AddExecutionMode( state.builder.AddExecutionMode(
state.main_func, tess.partitioning == 0u ? spv::ExecutionModeSpacingEqual state.main_func, tess.partitioning == 0u ? spv::ExecutionModeSpacingEqual
: spv::ExecutionModeSpacingFractionalOdd); : spv::ExecutionModeSpacingFractionalOdd);
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeVertexOrderCw); state.builder.AddExecutionMode(state.main_func, tess.output_topology == 2u
? spv::ExecutionModeVertexOrderCw
: spv::ExecutionModeVertexOrderCcw);
} }
} }
+8 -3
View File
@@ -47480,7 +47480,8 @@ bool HasPatchInterface(const std::string &assembly, const std::string &storage,
std::string::npos; std::string::npos;
} }
void CheckTessellationProgram(const char *name, u32 ls_stride, u32 hs_stride, u32 domain = 1) { void CheckTessellationProgram(const char *name, u32 ls_stride, u32 hs_stride, u32 domain = 1,
u32 output_topology = 2) {
using namespace ShaderRecompiler; using namespace ShaderRecompiler;
const bool quad = domain == 2; const bool quad = domain == 2;
const u32 control_points = quad ? 4 : 3; const u32 control_points = quad ? 4 : 3;
@@ -47584,7 +47585,7 @@ void CheckTessellationProgram(const char *name, u32 ls_stride, u32 hs_stride, u3
.output_control_points = control_points, .output_control_points = control_points,
.domain = domain, .domain = domain,
.partitioning = 2, .partitioning = 2,
.output_topology = 2}; .output_topology = output_topology};
AnalyzeTessellationPrograms(local, control, tess); AnalyzeTessellationPrograms(local, control, tess);
Require(name, "decoded interface", Require(name, "decoded interface",
tess.ls_stride == ls_stride && tess.hs_stride == hs_stride, tess.ls_stride == ls_stride && tess.hs_stride == hs_stride,
@@ -47639,7 +47640,10 @@ void CheckTessellationProgram(const char *name, u32 ls_stride, u32 hs_stride, u3
ds.assembly.find("TessCoord") != std::string::npos && ds.assembly.find("TessCoord") != std::string::npos &&
ds.assembly.find(quad ? "Quads" : "Triangles") != std::string::npos && ds.assembly.find(quad ? "Quads" : "Triangles") != std::string::npos &&
ds.assembly.find("SpacingFractionalOdd") != std::string::npos && ds.assembly.find("SpacingFractionalOdd") != std::string::npos &&
ds.assembly.find("VertexOrderCw") != std::string::npos, ds.assembly.find(output_topology == 2 ? "VertexOrderCw" : "VertexOrderCcw") !=
std::string::npos &&
ds.assembly.find(output_topology == 2 ? "VertexOrderCcw" : "VertexOrderCw") ==
std::string::npos,
"TES must preserve guest domain, partitioning, and winding"); "TES must preserve guest domain, partitioning, and winding");
std::printf("[host] %-32s ok\n", name); std::printf("[host] %-32s ok\n", name);
} }
@@ -47816,6 +47820,7 @@ void CheckTessellationPrograms() {
CheckTessellationProgram("TessellationShiftedStride", 124, 128); CheckTessellationProgram("TessellationShiftedStride", 124, 128);
CheckTessellationProgram("TessellationMultipliedStride", 108, 112); CheckTessellationProgram("TessellationMultipliedStride", 108, 112);
CheckTessellationProgram("TessellationQuadFactors", 36, 128, 2); CheckTessellationProgram("TessellationQuadFactors", 36, 128, 2);
CheckTessellationProgram("TessellationCounterclockwiseQuads", 36, 128, 2, 3);
CheckTessellationProgram("TessellationMaskedControlPoint", 32, 256, 2); CheckTessellationProgram("TessellationMaskedControlPoint", 32, 256, 2);
CheckTessellationPatchConstants(); CheckTessellationPatchConstants();
} }