From f9c052d1b7bd78c27eebcc8a74bf629ec3ca966d Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Sun, 24 Apr 2022 13:21:45 +0530 Subject: [PATCH] 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. --- .../gpu/interconnect/graphics_context.h | 81 +++++++++++++++++++ .../skyline/soc/gm20b/engines/maxwell/types.h | 29 +++++++ .../skyline/soc/gm20b/engines/maxwell_3d.cpp | 8 ++ .../skyline/soc/gm20b/engines/maxwell_3d.h | 14 ++++ 4 files changed, 132 insertions(+) diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index bea77870..37bb9a27 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -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(shaderStages.size()), .pVertexInputState = &vertexState.get(), .pInputAssemblyState = &inputAssemblyState, + .pTessellationState = &tessellationState, .pViewportState = &viewportState, .pRasterizationState = &rasterizerState.get(), .pMultisampleState = &multisampleState, diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h index b2745a73..288e15ac 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h @@ -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, // 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> renderTargets; Register<0x280, std::array> viewportTransforms; @@ -94,6 +106,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d { }; Register<0x36B, PolygonMode> polygonMode; + Register<0x373, u32> tessellationPatchSize; + Register<0x380, std::array> scissors; struct DepthBiasEnable {