From 690e96bce09a587aeff7584e0e656e0d23a9627d Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Fri, 2 Sep 2022 15:29:18 +0100 Subject: [PATCH] Implement rasterization pipeline state --- .../maxwell_3d/pipeline_state.cpp | 72 ++++++++++++++++++- .../interconnect/maxwell_3d/pipeline_state.h | 30 ++++++++ .../skyline/soc/gm20b/engines/maxwell/types.h | 66 ++++++++++++++--- .../skyline/soc/gm20b/engines/maxwell_3d.cpp | 1 + .../skyline/soc/gm20b/engines/maxwell_3d.h | 22 +++--- 5 files changed, 167 insertions(+), 24 deletions(-) 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 a7ac9af9..181bdfbb 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 @@ -476,6 +476,72 @@ namespace skyline::gpu::interconnect::maxwell3d { // maxwell3d::PipelineStage::TessellationEvaluation); } + /* Rasterizer State */ + void RasterizationState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const { + manager.Bind(handle, rasterEnable, frontPolygonMode, backPolygonMode, viewportClipControl, oglCullEnable, oglFrontFace, oglCullFace, windowOrigin, provokingVertex, polyOffset); + } + + RasterizationState::RasterizationState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine) : engine{manager, dirtyHandle, engine} {} + + static vk::PolygonMode ConvertPolygonMode(engine::PolygonMode mode) { + switch (mode) { + case engine::PolygonMode::Fill: + return vk::PolygonMode::eFill; + case engine::PolygonMode::Line: + return vk::PolygonMode::eLine; + case engine::PolygonMode::Point: + return vk::PolygonMode::ePoint; + } + } + + static vk::CullModeFlags ConvertCullMode(engine::CullFace cullMode) { + switch (cullMode) { + case engine::CullFace::Front: + return vk::CullModeFlagBits::eFront; + case engine::CullFace::Back: + return vk::CullModeFlagBits::eBack; + case engine::CullFace::FrontAndBack: + return vk::CullModeFlagBits::eFrontAndBack; + } + } + + + bool ConvertDepthBiasEnable(engine::PolyOffset polyOffset, engine::PolygonMode polygonMode) { + switch (polygonMode) { + case engine::PolygonMode::Point: + return polyOffset.pointEnable; + case engine::PolygonMode::Line: + return polyOffset.lineEnable; + case engine::PolygonMode::Fill: + return polyOffset.fillEnable; + } + } + + static vk::ProvokingVertexModeEXT ConvertProvokingVertex(engine::ProvokingVertex::Value provokingVertex) { + switch (provokingVertex) { + case engine::ProvokingVertex::Value::First: + return vk::ProvokingVertexModeEXT::eFirstVertex; + case engine::ProvokingVertex::Value::Last: + return vk::ProvokingVertexModeEXT::eLastVertex; + } + } + + void RasterizationState::Flush() { + auto &rasterizationCreateInfo{rasterizationState.get()}; + rasterizationCreateInfo.rasterizerDiscardEnable = !engine->rasterEnable; + rasterizationCreateInfo.polygonMode = ConvertPolygonMode(engine->frontPolygonMode); + if (engine->backPolygonMode != engine->frontPolygonMode) + Logger::Warn("Non-matching polygon modes!"); + + rasterizationCreateInfo.cullMode = engine->oglCullEnable ? ConvertCullMode(engine->oglCullFace) : vk::CullModeFlagBits::eNone; + // UpdateRuntimeInformation(runtimeInfo.y_negate, enabled, maxwell3d::PipelineStage::Vertex, maxwell3d::PipelineStage::Fragment); + + bool origFrontFaceClockwise{engine->oglFrontFace == engine::FrontFace::CW}; + rasterizationCreateInfo.frontFace = (engine->windowOrigin.flipY != origFrontFaceClockwise) ? vk::FrontFace::eClockwise : vk::FrontFace::eCounterClockwise; + rasterizationCreateInfo.depthBiasEnable = ConvertDepthBiasEnable(engine->polyOffset, engine->frontPolygonMode); + rasterizationState.get().provokingVertexMode = ConvertProvokingVertex(engine->provokingVertex.value); + } + /* Pipeline State */ void PipelineState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const { auto bindFunc{[&](auto ®s) { regs.DirtyBind(manager, handle); }}; @@ -488,7 +554,8 @@ namespace skyline::gpu::interconnect::maxwell3d { PipelineState::PipelineState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine) : engine{manager, dirtyHandle, engine}, colorRenderTargets{util::MergeInto, engine::ColorTargetCount>(manager, engine.colorRenderTargetsRegisters)}, - depthRenderTarget{manager, engine.depthRenderTargetRegisters} {} + depthRenderTarget{manager, engine.depthRenderTargetRegisters}, + rasterization{manager, engine.rasterizationRegisters} {} void PipelineState::Flush(InterconnectContext &ctx, StateUpdateBuilder &builder) { auto updateFunc{[&](auto &stateElem, auto &&... args) { stateElem.Update(ctx, args...); }}; @@ -497,7 +564,8 @@ namespace skyline::gpu::interconnect::maxwell3d { auto vertexState{directState.vertexInput.Build(ctx, engine->vertexInputRegisters)}; auto inputAssemblyState{directState.inputAssembly.Build()}; - auto tessellationState{directState.tessellationState.Build()}; + auto tessellationState{directState.tessellation.Build()}; + const auto &rasterizationState{rasterization.UpdateGet().rasterizationState}; } 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 255f6502..06fc0ca7 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 @@ -142,6 +142,34 @@ namespace skyline::gpu::interconnect::maxwell3d { TessellationState tessellation; }; + class RasterizationState : dirty::ManualDirty { + public: + struct EngineRegisters { + const u32 &rasterEnable; + const engine::PolygonMode &frontPolygonMode; + const engine::PolygonMode &backPolygonMode; + const u32 &oglCullEnable; + const engine::CullFace &oglCullFace; + const engine::WindowOrigin &windowOrigin; + const engine::FrontFace &oglFrontFace; + const engine::ViewportClipControl &viewportClipControl; + const engine::PolyOffset &polyOffset; + const engine::ProvokingVertex &provokingVertex; + + void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; + }; + + private: + dirty::BoundSubresource engine; + + public: + vk::StructureChain rasterizationState; + + RasterizationState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); + + void Flush(); + }; + /** * @brief Holds all GPU state for a pipeline, any changes to this will result in a pipeline cache lookup */ @@ -153,6 +181,7 @@ namespace skyline::gpu::interconnect::maxwell3d { VertexInputState::EngineRegisters vertexInputRegisters; InputAssemblyState::EngineRegisters inputAssemblyRegisters; TessellationState::EngineRegisters tessellationRegisters; + RasterizationState::EngineRegisters rasterizationRegisters; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; @@ -162,6 +191,7 @@ namespace skyline::gpu::interconnect::maxwell3d { std::array, engine::ColorTargetCount> colorRenderTargets; dirty::ManualDirtyState depthRenderTarget; + dirty::ManualDirtyState rasterization; public: DirectPipelineState directState; 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 0dc9fc86..727e61ae 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 @@ -351,6 +351,13 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { Fill = 0x1B02, //!< Fill the area bounded by the vertices }; + struct PolyOffset { + u32 pointEnable; + u32 lineEnable; + u32 fillEnable; + }; + static_assert(sizeof(PolyOffset) == (0x3 * sizeof(u32))); + /** * @brief A scissor which is used to reject all writes to non-masked regions * @note All coordinates are in screen-space as defined by the viewport @@ -652,8 +659,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { }) enum class FrontFace : u32 { - Clockwise = 0x900, - CounterClockwise = 0x901, + CW = 0x900, + CCW = 0x901, }; enum class CullFace : u32 { @@ -662,18 +669,48 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { FrontAndBack = 0x408, }; - union ViewVolumeClipControl { + union ViewportClipControl { u32 raw; + enum class PixelZ : u8 { + Clip = 0, + Clamp = 1 + }; + + enum class GuardbandScale : u8 { + Scale256, + Scale1 + }; + + enum class GeometryClip : u8 { + WZeroClip = 0, + Passthru = 1, + FrustrumXYClip = 2, + FrustrumXYZClip = 3, + WZeroClipNoZCull = 4, + FrustrumZClip = 5, + WZeroTriFillOrClip = 6 + }; + + enum class GuardbandZScale : u8 { + SameAsXYGuardband = 0, + Scale256 = 1, + Scale1 = 2 + }; + struct { - bool forceDepthRangeZeroToOne : 1; - u8 _unk0_ : 2; - bool depthClampNear : 1; - bool depthClampFar : 1; - u8 _unk1_ : 6; - bool depthClampDisable : 1; + bool minZZeroMaxZOne : 1; + GuardbandZScale guardbandZScale : 2; + PixelZ pixelMinZ : 1; + PixelZ pixelMaxZ : 1; + u8 _pad1_ : 2; + GuardbandScale geometryGuardbandScale : 1; + u8 _pad2_ : 2; + GuardbandScale linePointCullGuardbandScale : 1; + GeometryClip geometryClip : 3; + u32 _pad3_ : 18; }; }; - static_assert(sizeof(ViewVolumeClipControl) == sizeof(u32)); + static_assert(sizeof(ViewportClipControl) == sizeof(u32)); union ColorWriteMask { u32 raw; @@ -880,6 +917,15 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { }; static_assert(sizeof(SetProgramInfo) == (sizeof(u32) * 0x10)); + struct ProvokingVertex { + enum class Value : u8 { + First = 0, + Last = 1, + } value : 1; + u32 _pad_ : 31; + }; + static_assert(sizeof(ProvokingVertex) == sizeof(u32)); + struct ZtLayer { u16 offset; u16 _pad_; 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 73f843f8..98d8ac3c 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 @@ -19,6 +19,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { .vertexInputRegisters = {*registers.vertexStreams, *registers.vertexStreamInstance, *registers.vertexAttributes}, .inputAssemblyRegisters = {*registers.primitiveRestartEnable}, .tessellationRegisters = {*registers.patchSize, *registers.tessellationParameters}, + .rasterizationRegisters = {*registers.rasterEnable, *registers.frontPolygonMode, *registers.backPolygonMode, *registers.oglCullEnable, *registers.oglCullFace, *registers.windowOrigin, *registers.oglFrontFace, *registers.viewportClipControl, *registers.polyOffset, *registers.provokingVertex}, }; } 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 1ce24596..493d2f69 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 @@ -115,7 +115,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0xC8, type::TessellationParameters> tessellationParameters; - Register<0xDF, u32> rasterizerEnable; + Register<0xDF, u32> rasterEnable; Register<0xE0, std::array> streamOutBuffers; Register<0x1C0, std::array> transformFeedbackBufferStates; @@ -127,7 +127,6 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0x35B, type::ClearRect> clearRect; - Register<0x35D, u32> vertexArrayStart; //!< The first vertex to draw struct DrawVertexArray { @@ -142,11 +141,10 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0x364, float> zClearValue; Register<0x368, u32> stencilClearValue; - struct PolygonMode { - type::PolygonMode front; // 0x36B - type::PolygonMode back; // 0x36C - }; - Register<0x36B, PolygonMode> polygonMode; + Register<0x36B, type::PolygonMode> frontPolygonMode; + Register<0x36C, type::PolygonMode> backPolygonMode; + + Register<0x370, type::PolyOffset> polyOffset; Register<0x373, u32> patchSize; @@ -310,7 +308,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0x591, u32> primitiveRestartEnable; Register<0x592, u32> primitiveRestartIndex; - Register<0x5A1, u32> provokingVertexIsLast; + Register<0x5A1, type::ProvokingVertex> provokingVertex; Register<0x5E7, type::ZtLayer> ztLayer; @@ -325,13 +323,13 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0x620, std::array> vertexStreamInstance; //!< A per-VBO boolean denoting if the vertex input rate should be per vertex or per instance - Register<0x646, u32> cullFaceEnable; - Register<0x647, type::FrontFace> frontFace; - Register<0x648, type::CullFace> cullFace; + Register<0x646, u32> oglCullEnable; + Register<0x647, type::FrontFace> oglFrontFace; + Register<0x648, type::CullFace> oglCullFace; Register<0x649, u32> pixelCentreImage; Register<0x64B, u32> viewportScaleOffsetEnable; - Register<0x64F, type::ViewVolumeClipControl> viewVolumeClipControl; + Register<0x64F, type::ViewportClipControl> viewportClipControl; Register<0x652, type::PrimitiveTopologyControl> primitiveTopologyControl; Register<0x65C, type::PrimitiveTopology> primitiveTopology;