Implement Maxwell3D Tessellation State

This implements all Maxwell3D registers and HLE Vulkan state for Tessellation including invalidation of the TCS (Tessellation Control Shader) state during state changes.
This commit is contained in:
PixelyIon 2022-04-24 13:21:45 +05:30
parent de796cd2cd
commit f9c052d1b7
4 changed files with 132 additions and 0 deletions

View File

@ -1868,6 +1868,86 @@ namespace skyline::gpu::interconnect {
inputAssemblyState.primitiveRestartEnable = enable;
}
/* Tessellation */
private:
vk::PipelineTessellationStateCreateInfo tessellationState{};
maxwell3d::TessellationPrimitive tessellationPrimitive{};
maxwell3d::TessellationSpacing tessellationSpacing{};
bool isTessellationWindingClockwise{};
bool IsTessellationModeClockwise(maxwell3d::TessellationPrimitive primitive, maxwell3d::TessellationWinding winding) {
if (primitive == maxwell3d::TessellationPrimitive::Isoline)
return false;
switch (winding) {
case maxwell3d::TessellationWinding::CounterClockwiseAndNotConnected:
case maxwell3d::TessellationWinding::ConnectedTriangle:
return false;
case maxwell3d::TessellationWinding::ClockwiseTriangle:
case maxwell3d::TessellationWinding::ClockwiseConnectedTriangle:
return true;
default:
throw exception("Unimplemented Maxwell3D Tessellation Winding: {}", winding);
}
}
public:
void SetTessellationPatchSize(u32 patchControlPoints) {
tessellationState.patchControlPoints = patchControlPoints;
}
void SetTessellationMode(maxwell3d::TessellationPrimitive primitive, maxwell3d::TessellationSpacing spacing, maxwell3d::TessellationWinding winding) {
if (tessellationPrimitive != primitive) {
auto shaderPrimitive{[](maxwell3d::TessellationPrimitive primitive) -> ShaderCompiler::TessPrimitive {
using Primitive = maxwell3d::TessellationPrimitive;
using ShaderPrimitive = ShaderCompiler::TessPrimitive;
switch (primitive) {
case Primitive::Isoline:
return ShaderPrimitive::Isolines;
case Primitive::Triangle:
return ShaderPrimitive::Triangles;
case Primitive::Quad:
return ShaderPrimitive::Quads;
default:
throw exception("Unimplemented Maxwell3D Tessellation Primitive: {}", primitive);
}
}(primitive)};
UpdateRuntimeInformation(runtimeInfo.tess_primitive, shaderPrimitive, maxwell3d::PipelineStage::TessellationEvaluation);
tessellationPrimitive = primitive;
}
if (tessellationSpacing != spacing) {
auto shaderTessellationSpacing{[](maxwell3d::TessellationSpacing spacing) -> ShaderCompiler::TessSpacing {
using Spacing = maxwell3d::TessellationSpacing;
using ShaderSpacing = ShaderCompiler::TessSpacing;
switch (spacing) {
case Spacing::Equal:
return ShaderSpacing::Equal;
case Spacing::FractionalEven:
return ShaderSpacing::FractionalEven;
case Spacing::FractionalOdd:
return ShaderSpacing::FractionalOdd;
default:
throw exception("Unimplemented Maxwell3D Tessellation Spacing: {}", spacing);
}
}(spacing)};
UpdateRuntimeInformation(runtimeInfo.tess_spacing, shaderTessellationSpacing, maxwell3d::PipelineStage::TessellationEvaluation);
tessellationSpacing = spacing;
}
bool isClockwise{IsTessellationModeClockwise(primitive, winding)};
if (isTessellationWindingClockwise != isClockwise) {
UpdateRuntimeInformation(runtimeInfo.tess_clockwise, isClockwise, maxwell3d::PipelineStage::TessellationEvaluation);
isTessellationWindingClockwise = isClockwise;
}
}
/* Index Buffer */
private:
struct IndexBuffer {
@ -2798,6 +2878,7 @@ namespace skyline::gpu::interconnect {
.stageCount = static_cast<u32>(shaderStages.size()),
.pVertexInputState = &vertexState.get<vk::PipelineVertexInputStateCreateInfo>(),
.pInputAssemblyState = &inputAssemblyState,
.pTessellationState = &tessellationState,
.pViewportState = &viewportState,
.pRasterizationState = &rasterizerState.get<vk::PipelineRasterizationStateCreateInfo>(),
.pMultisampleState = &multisampleState,

View File

@ -27,6 +27,35 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
};
static_assert(sizeof(SyncpointAction) == sizeof(u32));
/**
* @brief The input primitive for a tessellated surface
*/
enum class TessellationPrimitive : u8 {
Isoline = 0,
Triangle = 1,
Quad = 2,
};
/**
* @brief The spacing between tessellated vertices during primitive generation
*/
enum class TessellationSpacing : u8 {
Equal = 0,
FractionalOdd = 1,
FractionalEven = 2,
};
/**
* @brief The winding order and connectivity of tessellated primitives during primitive generation
*/
enum class TessellationWinding : u8 {
CounterClockwiseAndNotConnected = 0, //!< Counter-clockwise, not connected
ConnectedIsoline = 1, //!< Counter-clockwise, connected (Only for Isolines)
ClockwiseTriangle = 1, //<! Clockwise, not connected (Only for Triangles)
ConnectedTriangle = 2, //!< Counter-clockwise, connected (Only for Triangles)
ClockwiseConnectedTriangle = 3, //!< Clockwise, connected (Only for Triangles)
};
constexpr static size_t RenderTargetCount{8}; //!< Maximum amount of render targets that can be bound at once on Maxwell 3D
struct RenderTargetTileMode {

View File

@ -177,6 +177,14 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
context.SetPolygonModeFront(front);
})
ENGINE_CASE(tessellationPatchSize, {
context.SetTessellationPatchSize(tessellationPatchSize);
})
ENGINE_CASE(tessellationMode, {
context.SetTessellationMode(tessellationMode.primitive, tessellationMode.spacing, tessellationMode.winding);
})
ENGINE_STRUCT_CASE(depthBiasEnable, point, {
context.SetDepthBiasPointEnabled(point);
})

View File

@ -74,6 +74,18 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
Register<0xB2, type::SyncpointAction> syncpointAction;
union TessellationMode {
struct {
type::TessellationPrimitive primitive : 2;
u8 _pad0_ : 2;
type::TessellationSpacing spacing : 2;
u8 _pad1_ : 2;
type::TessellationWinding winding : 2;
};
u32 raw;
};
Register<0xC8, TessellationMode> tessellationMode;
Register<0xDF, u32> rasterizerEnable;
Register<0x200, std::array<type::ColorRenderTarget, type::RenderTargetCount>> renderTargets;
Register<0x280, std::array<type::ViewportTransform, type::ViewportCount>> viewportTransforms;
@ -94,6 +106,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
};
Register<0x36B, PolygonMode> polygonMode;
Register<0x373, u32> tessellationPatchSize;
Register<0x380, std::array<type::Scissor, type::ViewportCount>> scissors;
struct DepthBiasEnable {