diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp index 0f02782b..a7ac9af9 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp @@ -434,6 +434,48 @@ namespace skyline::gpu::interconnect::maxwell3d { inputAssemblyState.primitiveRestartEnable = enabled; } + /* Tessellation State */ + void TessellationState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const { + manager.Bind(handle, patchControlPoints, tessellationParameters); + } + + const vk::PipelineTessellationStateCreateInfo &TessellationState::Build() { + return tessellationState; + } + + void TessellationState::SetPatchControlPoints(u32 patchControlPoints) { + tessellationState.patchControlPoints = patchControlPoints; + } + + Shader::TessPrimitive ConvertShaderTessPrimitive(engine::TessellationParameters::DomainType domainType) { + switch (domainType) { + case engine::TessellationParameters::DomainType::Isoline: + return Shader::TessPrimitive::Isolines; + case engine::TessellationParameters::DomainType::Triangle: + return Shader::TessPrimitive::Triangles; + case engine::TessellationParameters::DomainType::Quad: + return Shader::TessPrimitive::Quads; + } + } + + Shader::TessSpacing ConvertShaderTessSpacing(engine::TessellationParameters::Spacing spacing) { + switch (spacing) { + case engine::TessellationParameters::Spacing::Integer: + return Shader::TessSpacing::Equal; + case engine::TessellationParameters::Spacing::FractionalEven: + return Shader::TessSpacing::FractionalEven; + case engine::TessellationParameters::Spacing::FractionalOdd: + return Shader::TessSpacing::FractionalOdd; + } + } + + void TessellationState::SetParameters(engine::TessellationParameters params) { + // UpdateRuntimeInformation(runtimeInfo.tess_primitive, ConvertShaderTessPrimitive(params.domainType), maxwell3d::PipelineStage::TessellationEvaluation); + // UpdateRuntimeInformation(runtimeInfo.tess_spacing, ConvertShaderTessSpacing(params.spacing), maxwell3d::PipelineStage::TessellationEvaluation); + // UpdateRuntimeInformation(runtimeInfo.tess_clockwise, params.outputPrimitive == engine::TessellationParameters::OutputPrimitives::TrianglesCW, + // maxwell3d::PipelineStage::TessellationEvaluation); + } + /* Pipeline State */ void PipelineState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const { auto bindFunc{[&](auto ®s) { regs.DirtyBind(manager, handle); }}; @@ -455,6 +497,7 @@ namespace skyline::gpu::interconnect::maxwell3d { auto vertexState{directState.vertexInput.Build(ctx, engine->vertexInputRegisters)}; auto inputAssemblyState{directState.inputAssembly.Build()}; + auto tessellationState{directState.tessellationState.Build()}; } diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h index 7e672ad3..255f6502 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h @@ -114,12 +114,32 @@ namespace skyline::gpu::interconnect::maxwell3d { void SetPrimitiveRestart(bool enable); }; + struct TessellationState { + private: + vk::PipelineTessellationStateCreateInfo tessellationState{}; + + public: + struct EngineRegisters { + const u32 &patchControlPoints; + const engine::TessellationParameters &tessellationParameters; + + void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; + }; + + const vk::PipelineTessellationStateCreateInfo &Build(); + + void SetPatchControlPoints(u32 controlPoints); + + void SetParameters(engine::TessellationParameters parameters); + }; + /** * @brief Holds pipeline state that is directly written by the engine code, without using dirty tracking */ struct DirectPipelineState { VertexInputState vertexInput; InputAssemblyState inputAssembly; + TessellationState tessellation; }; /** @@ -132,6 +152,7 @@ namespace skyline::gpu::interconnect::maxwell3d { DepthRenderTargetState::EngineRegisters depthRenderTargetRegisters; VertexInputState::EngineRegisters vertexInputRegisters; InputAssemblyState::EngineRegisters inputAssemblyRegisters; + TessellationState::EngineRegisters tessellationRegisters; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; 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 88a980b9..0dc9fc86 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 @@ -1045,5 +1045,35 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { throw exception("Unsupported primitive topology 0x{:X}", static_cast(topology)); } } + + struct TessellationParameters { + enum class DomainType : u8 { + Isoline = 0, + Triangle = 1, + Quad = 2 + }; + + enum class Spacing : u8 { + Integer = 0, + FractionalOdd = 1, + FractionalEven = 2 + }; + + enum class OutputPrimitives : u8 { + Points = 0, + Lines = 1, + TrianglesCW = 2, + TrianglesCCW = 3 + }; + + DomainType domainType : 2; + u8 _pad0_ : 2; + Spacing spacing : 2; + u8 _pad1_ : 2; + OutputPrimitives outputPrimitives : 2; + u32 _pad2_ : 22; + }; + static_assert(sizeof(TessellationParameters) == sizeof(u32)); + #pragma pack(pop) } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index a97c062d..73f843f8 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -17,7 +17,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d { .colorRenderTargetsRegisters = util::MergeInto(*registers.colorTargets), .depthRenderTargetRegisters = {*registers.ztSize, *registers.ztOffset, *registers.ztFormat, *registers.ztBlockSize, *registers.ztArrayPitch, *registers.ztSelect, *registers.ztLayer}, .vertexInputRegisters = {*registers.vertexStreams, *registers.vertexStreamInstance, *registers.vertexAttributes}, - .inputAssemblyRegisters = {*registers.primitiveRestartEnable} + .inputAssemblyRegisters = {*registers.primitiveRestartEnable}, + .tessellationRegisters = {*registers.patchSize, *registers.tessellationParameters}, }; } @@ -174,9 +175,20 @@ namespace skyline::soc::gm20b::engine::maxwell3d { static_assert(type::VertexAttributeCount == 32 && type::VertexAttributeCount < BOOST_PP_LIMIT_REPEAT); #undef VERTEX_ATTRIBUTE_CALLBACKS + ENGINE_CASE(primitiveRestartEnable, { interconnect.directState.inputAssembly.SetPrimitiveRestart(primitiveRestartEnable != 0); }) + + + ENGINE_CASE(tessellationParameters, { + interconnect.directState.tessellation.SetParameters(tessellationParameters); + }) + + ENGINE_CASE(patchSize, { + interconnect.directState.tessellation.SetPatchControlPoints(patchSize); + }) + default: break; } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index 7c519de6..1ce24596 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -113,17 +113,7 @@ 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<0xC8, type::TessellationParameters> tessellationParameters; Register<0xDF, u32> rasterizerEnable; @@ -158,7 +148,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { }; Register<0x36B, PolygonMode> polygonMode; - Register<0x373, u32> tessellationPatchSize; + Register<0x373, u32> patchSize; Register<0x380, std::array> scissors;