diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index a00409b8..4e93a6a2 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -183,6 +183,7 @@ add_library(skyline SHARED ${source_DIR}/skyline/gpu/interconnect/maxwell_3d/common.cpp ${source_DIR}/skyline/gpu/interconnect/maxwell_3d/active_state.cpp ${source_DIR}/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp + ${source_DIR}/skyline/gpu/interconnect/maxwell_3d/packed_pipeline_state.cpp ${source_DIR}/skyline/gpu/interconnect/maxwell_3d/constant_buffers.cpp ${source_DIR}/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.cpp ${source_DIR}/skyline/gpu/interconnect/command_executor.cpp diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/packed_pipeline_state.cpp b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/packed_pipeline_state.cpp new file mode 100644 index 00000000..ad8d3805 --- /dev/null +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/packed_pipeline_state.cpp @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Ryujinx Team and Contributors (https://github.com/Ryujinx/) +// Copyright © 2022 yuzu Team and Contributors (https://github.com/yuzu-emu/) +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "packed_pipeline_state.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wbitfield-enum-conversion" + +namespace skyline::gpu::interconnect::maxwell3d { + void PackedPipelineState::SetColorRenderTargetFormat(size_t index, engine::ColorTarget::Format format) { + colorRenderTargetFormats[index] = static_cast(format); + } + + void PackedPipelineState::SetDepthRenderTargetFormat(engine::ZtFormat format) { + depthRenderTargetFormat = static_cast(format) - static_cast(engine::ZtFormat::ZF32); + } + + void PackedPipelineState::SetVertexBinding(u32 index, engine::VertexStream stream, engine::VertexStreamInstance instance) { + vertexBindings[index].stride = stream.format.stride; + vertexBindings[index].inputRate = instance.isInstanced ? vk::VertexInputRate::eInstance : vk::VertexInputRate::eVertex; + vertexBindings[index].enable = stream.format.enable; + vertexBindings[index].divisor = stream.frequency; + } + + void PackedPipelineState::SetTessellationParameters(engine::TessellationParameters parameters) { + domainType = parameters.domainType; + spacing = parameters.spacing; + outputPrimitives = parameters.outputPrimitives; + } + + void PackedPipelineState::SetPolygonMode(engine::PolygonMode mode) { + switch (mode) { + case engine::PolygonMode::Fill: + polygonMode = vk::PolygonMode::eFill; + case engine::PolygonMode::Line: + polygonMode = vk::PolygonMode::eLine; + case engine::PolygonMode::Point: + polygonMode = vk::PolygonMode::ePoint; + default: + throw exception("Invalid polygon mode: 0x{:X}", static_cast(mode)); + } + } + + void PackedPipelineState::SetCullMode(bool enable, engine::CullFace mode) { + if (!enable) { + cullMode = {}; + return; + } + + switch (mode) { + case engine::CullFace::Front: + cullMode = VK_CULL_MODE_FRONT_BIT; + case engine::CullFace::Back: + cullMode = VK_CULL_MODE_BACK_BIT; + case engine::CullFace::FrontAndBack: + cullMode = VK_CULL_MODE_FRONT_BIT | VK_CULL_MODE_BACK_BIT; + default: + throw exception("Invalid cull mode: 0x{:X}", static_cast(mode)); + } + } + + + static vk::CompareOp ConvertCompareFunc(engine::CompareFunc func) { + if (func < engine::CompareFunc::D3DNever || func > engine::CompareFunc::OglAlways || (func > engine::CompareFunc::D3DAlways && func < engine::CompareFunc::OglNever)) + throw exception("Invalid comparision function: 0x{:X}", static_cast(func)); + + u32 val{static_cast(func)}; + + // VK CompareOp values match 1:1 with Maxwell with some small maths + return static_cast(func >= engine::CompareFunc::OglNever ? val - 0x200 : val - 1); + } + + void PackedPipelineState::SetDepthFunc(engine::CompareFunc func) { + depthFunc = ConvertCompareFunc(func); + } + + void PackedPipelineState::SetLogicOp(engine::LogicOp::Func op) { + if (op < engine::LogicOp::Func::Clear || op > engine::LogicOp::Func::Set) + throw exception("Invalid logical operation: 0x{:X}", static_cast(op)); + + // VK LogicOp values match 1:1 with Maxwell + logicOp = static_cast(static_cast(op) - static_cast(engine::LogicOp::Func::Clear)); + } + + static vk::StencilOp ConvertStencilOp(engine::StencilOps::Op op) { + switch (op) { + case engine::StencilOps::Op::OglZero: + case engine::StencilOps::Op::D3DZero: + return vk::StencilOp::eZero; + case engine::StencilOps::Op::D3DKeep: + case engine::StencilOps::Op::OglKeep: + return vk::StencilOp::eKeep; + case engine::StencilOps::Op::D3DReplace: + case engine::StencilOps::Op::OglReplace: + return vk::StencilOp::eReplace; + case engine::StencilOps::Op::D3DIncrSat: + case engine::StencilOps::Op::OglIncrSat: + return vk::StencilOp::eIncrementAndClamp; + case engine::StencilOps::Op::D3DDecrSat: + case engine::StencilOps::Op::OglDecrSat: + return vk::StencilOp::eDecrementAndClamp; + case engine::StencilOps::Op::D3DInvert: + case engine::StencilOps::Op::OglInvert: + return vk::StencilOp::eInvert; + case engine::StencilOps::Op::D3DIncr: + case engine::StencilOps::Op::OglIncr: + return vk::StencilOp::eIncrementAndWrap; + case engine::StencilOps::Op::D3DDecr: + case engine::StencilOps::Op::OglDecr: + return vk::StencilOp::eDecrementAndWrap; + default: + throw exception("Invalid stencil operation: 0x{:X}", static_cast(op)); + } + } + + static PackedPipelineState::StencilOps PackStencilOps(engine::StencilOps ops) { + return { + .zPass = ConvertStencilOp(ops.zPass), + .fail = ConvertStencilOp(ops.fail), + .zFail = ConvertStencilOp(ops.zFail), + .func = ConvertCompareFunc(ops.func), + }; + } + + void PackedPipelineState::SetStencilOps(engine::StencilOps front, engine::StencilOps back) { + stencilFront = PackStencilOps(front); + stencilBack = PackStencilOps(back); + } + + static VkColorComponentFlags ConvertColorWriteMask(engine::CtWrite write) { + return (write.rEnable ? VK_COLOR_COMPONENT_R_BIT : 0) | + (write.gEnable ? VK_COLOR_COMPONENT_G_BIT : 0) | + (write.bEnable ? VK_COLOR_COMPONENT_B_BIT : 0) | + (write.aEnable ? VK_COLOR_COMPONENT_A_BIT : 0); + }; + + static vk::BlendOp ConvertBlendOp(engine::BlendOp op) { + switch (op) { + case engine::BlendOp::D3DAdd: + case engine::BlendOp::OglFuncAdd: + return vk::BlendOp::eAdd; + case engine::BlendOp::D3DSubtract: + case engine::BlendOp::OglFuncSubtract: + return vk::BlendOp::eSubtract; + case engine::BlendOp::D3DRevSubtract: + case engine::BlendOp::OglFuncReverseSubtract: + return vk::BlendOp::eReverseSubtract; + case engine::BlendOp::D3DMin: + case engine::BlendOp::OglMin: + return vk::BlendOp::eMin; + case engine::BlendOp::D3DMax: + case engine::BlendOp::OglMax: + return vk::BlendOp::eMax; + default: + throw exception("Invalid blend operation: 0x{:X}", static_cast(op)); + } + } + + static vk::BlendFactor ConvertBlendFactor(engine::BlendCoeff coeff) { + switch (coeff) { + case engine::BlendCoeff::OglZero: + case engine::BlendCoeff::D3DZero: + return vk::BlendFactor::eZero; + case engine::BlendCoeff::OglOne: + case engine::BlendCoeff::D3DOne: + return vk::BlendFactor::eOne; + case engine::BlendCoeff::OglSrcColor: + case engine::BlendCoeff::D3DSrcColor: + return vk::BlendFactor::eSrcColor; + case engine::BlendCoeff::OglOneMinusSrcColor: + case engine::BlendCoeff::D3DInvSrcColor: + return vk::BlendFactor::eOneMinusSrcColor; + case engine::BlendCoeff::OglSrcAlpha: + case engine::BlendCoeff::D3DSrcAlpha: + return vk::BlendFactor::eSrcAlpha; + case engine::BlendCoeff::OglOneMinusSrcAlpha: + case engine::BlendCoeff::D3DInvSrcAlpha: + return vk::BlendFactor::eOneMinusSrcAlpha; + case engine::BlendCoeff::OglDstAlpha: + case engine::BlendCoeff::D3DDstAlpha: + return vk::BlendFactor::eDstAlpha; + case engine::BlendCoeff::OglOneMinusDstAlpha: + case engine::BlendCoeff::D3DInvDstAlpha: + return vk::BlendFactor::eOneMinusDstAlpha; + case engine::BlendCoeff::OglDstColor: + case engine::BlendCoeff::D3DDstColor: + return vk::BlendFactor::eDstColor; + case engine::BlendCoeff::OglOneMinusDstColor: + case engine::BlendCoeff::D3DInvDstColor: + return vk::BlendFactor::eOneMinusDstColor; + case engine::BlendCoeff::OglSrcAlphaSaturate: + case engine::BlendCoeff::D3DSrcAlphaSaturate: + return vk::BlendFactor::eSrcAlphaSaturate; + case engine::BlendCoeff::OglConstantColor: + case engine::BlendCoeff::D3DBlendCoeff: + return vk::BlendFactor::eConstantColor; + case engine::BlendCoeff::OglOneMinusConstantColor: + case engine::BlendCoeff::D3DInvBlendCoeff: + return vk::BlendFactor::eOneMinusConstantColor; + case engine::BlendCoeff::OglConstantAlpha: + return vk::BlendFactor::eConstantAlpha; + case engine::BlendCoeff::OglOneMinusConstantAlpha: + return vk::BlendFactor::eOneMinusConstantAlpha; + case engine::BlendCoeff::OglSrc1Color: + case engine::BlendCoeff::D3DSrc1Color: + return vk::BlendFactor::eSrc1Color; + case engine::BlendCoeff::OglInvSrc1Color: + case engine::BlendCoeff::D3DInvSrc1Color: + return vk::BlendFactor::eOneMinusSrc1Color; + case engine::BlendCoeff::OglSrc1Alpha: + case engine::BlendCoeff::D3DSrc1Alpha: + return vk::BlendFactor::eSrc1Alpha; + case engine::BlendCoeff::OglInvSrc1Alpha: + case engine::BlendCoeff::D3DInvSrc1Alpha: + return vk::BlendFactor::eOneMinusSrc1Alpha; + default: + throw exception("Invalid blend coefficient type: 0x{:X}", static_cast(coeff)); + } + } + + static PackedPipelineState::AttachmentBlendState PackAttachmentBlendState(bool enable, engine::CtWrite writeMask, auto blend) { + return { + .colorWriteMask = ConvertColorWriteMask(writeMask), + .colorBlendOp = ConvertBlendOp(blend.colorOp), + .srcColorBlendFactor = ConvertBlendFactor(blend.colorSourceCoeff), + .dstColorBlendFactor = ConvertBlendFactor(blend.colorDestCoeff), + .alphaBlendOp = ConvertBlendOp(blend.alphaOp), + .srcAlphaBlendFactor = ConvertBlendFactor(blend.alphaSourceCoeff), + .dstAlphaBlendFactor = ConvertBlendFactor(blend.alphaDestCoeff), + .blendEnable = enable + }; + } + + void PackedPipelineState::SetAttachmentBlendState(u32 index, bool enable, engine::CtWrite writeMask, engine::Blend blend) { + attachmentBlendStates[index] = PackAttachmentBlendState(enable, writeMask, blend); + } + + void PackedPipelineState::SetAttachmentBlendState(u32 index, bool enable, engine::CtWrite writeMask, engine::BlendPerTarget blend) { + attachmentBlendStates[index] = PackAttachmentBlendState(enable, writeMask, blend); + } + + std::array PackedPipelineState::GetStencilOpsState() const { + auto convertFaceOps{[](StencilOps ops) { + return vk::StencilOpState{ + .failOp = ops.fail, + .passOp = ops.zPass, + .depthFailOp = ops.zFail, + .compareOp = ops.func, + }; + }}; + + return { + convertFaceOps(stencilFront), + convertFaceOps(stencilBack) + }; + } + + vk::PipelineColorBlendAttachmentState PackedPipelineState::GetAttachmentBlendState(u32 index) const { + const auto &state{attachmentBlendStates[index]}; + + return { + .colorWriteMask = vk::ColorComponentFlags{state.colorWriteMask}, + .colorBlendOp = state.colorBlendOp, + .srcColorBlendFactor = state.srcColorBlendFactor, + .dstColorBlendFactor = state.dstColorBlendFactor, + .alphaBlendOp = state.alphaBlendOp, + .srcAlphaBlendFactor = state.srcAlphaBlendFactor, + .dstAlphaBlendFactor = state.dstAlphaBlendFactor, + .blendEnable = state.blendEnable + }; + } +} + +#pragma clang diagnostic pop \ No newline at end of file diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/packed_pipeline_state.h b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/packed_pipeline_state.h new file mode 100644 index 00000000..6a0ce1f3 --- /dev/null +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/packed_pipeline_state.h @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include "common.h" +#include + +namespace skyline::gpu::interconnect::maxwell3d { + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wbitfield-enum-conversion" + + /** + * @brief Packed struct of pipeline state suitable for use as a map key + * @note This is heavily based around yuzu's pipeline key with some packing modifications + * @url https://github.com/yuzu-emu/yuzu/blob/9c701774562ea490296b9cbea3dbd8c096bc4483/src/video_core/renderer_vulkan/fixed_pipeline_state.h#L20 + */ + struct PackedPipelineState { + std::array shaderHashes; + + struct StencilOps { + vk::StencilOp zPass : 3; + vk::StencilOp fail : 3; + vk::StencilOp zFail : 3; + vk::CompareOp func : 3; + // 4 bits left for each stencil side + }; + + StencilOps stencilFront; //!< Use {Set, Get}StencilOps + StencilOps stencilBack; //!< Use {Set, Get}StencilOps + + struct { + u8 depthRenderTargetFormat : 5; //!< Use {Set, Get}DepthRenderTargetFormat + engine::DrawTopology topology : 4; + bool primitiveRestartEnabled : 1; + engine::TessellationParameters::DomainType domainType : 2; //!< Use SetTessellationParameters + engine::TessellationParameters::Spacing spacing : 2; //!< Use SetTessellationParameters + engine::TessellationParameters::OutputPrimitives outputPrimitives : 2; //!< Use SetTessellationParameters + bool rasterizerDiscardEnable : 1; + vk::PolygonMode polygonMode : 2; //!< Use SetPolygonMode + VkCullModeFlags cullMode : 2; //!< Use SetCullMode + bool flipYEnable : 1; + bool frontFaceClockwise : 1; //!< With Y flip transformation already applied + bool depthBiasEnable : 1; + engine::ProvokingVertex::Value provokingVertex : 1; + bool depthTestEnable : 1; + bool depthWriteEnable : 1; + vk::CompareOp depthFunc : 3; //!< Use SetDepthFunc + bool depthBoundsTestEnable : 1; + bool stencilTestEnable : 1; + bool logicOpEnable : 1; + vk::LogicOp logicOp : 4; //!< Use SetLogicOp + u8 bindlessTextureConstantBufferSlotSelect : 5; + bool apiMandatedEarlyZ : 1; + bool openGlNdc : 1; + }; + + u32 patchSize; + float pointSize; + std::array vertexAttributes; + std::array colorRenderTargetFormats; //!< Use {Set, Get}ColorRenderTargetFormat + std::array postVtgShaderAttributeSkipMask; + + struct VertexBinding { + u16 stride : 12; + vk::VertexInputRate inputRate : 1; + bool enable : 1; + u8 _pad_ : 2; + u32 divisor; + }; + + std::array vertexBindings; //!< Use {Set, Get}VertexBinding + + struct AttachmentBlendState { + VkColorComponentFlags colorWriteMask : 4; + vk::BlendOp colorBlendOp : 3; + vk::BlendFactor srcColorBlendFactor : 5; + vk::BlendFactor dstColorBlendFactor : 5; + vk::BlendOp alphaBlendOp : 3; + vk::BlendFactor srcAlphaBlendFactor : 5; + vk::BlendFactor dstAlphaBlendFactor : 5; + bool blendEnable : 1; + }; + + std::array attachmentBlendStates; + + void SetColorRenderTargetFormat(size_t index, engine::ColorTarget::Format format); + + void SetDepthRenderTargetFormat(engine::ZtFormat format); + + void SetVertexBinding(u32 index, engine::VertexStream stream, engine::VertexStreamInstance instance); + + void SetTessellationParameters(engine::TessellationParameters parameters); + + void SetPolygonMode(engine::PolygonMode mode); + + void SetCullMode(bool enable, engine::CullFace mode); + + void SetDepthFunc(engine::CompareFunc func); + + void SetStencilOps(engine::StencilOps front, engine::StencilOps back); + + void SetLogicOp(engine::LogicOp::Func op); + + void SetAttachmentBlendState(u32 index, bool enable, engine::CtWrite writeMask, engine::Blend blend); + + void SetAttachmentBlendState(u32 index, bool enable, engine::CtWrite writeMask, engine::BlendPerTarget blend); + + std::array GetStencilOpsState() const; + + vk::PipelineColorBlendAttachmentState GetAttachmentBlendState(u32 index) const; + + bool operator==(const PackedPipelineState &other) const { + return std::memcmp(this, &other, sizeof(PackedPipelineState)) == 0; + } + }; + + #pragma clang diagnostic pop +} 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 5de5e3c9..ea33a2b9 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 @@ -3,252 +3,15 @@ // Copyright © 2022 yuzu Team and Contributors (https://github.com/yuzu-emu/) // Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) -#include #include #include #include -#include #include #include -#include #include "pipeline_state.h" #include "shader_state.h" -#include "soc/gm20b/engines/maxwell/types.h" namespace skyline::gpu::interconnect::maxwell3d { - /* Packed State */ - void PackedPipelineState::SetColorRenderTargetFormat(size_t index, engine::ColorTarget::Format format) { - colorRenderTargetFormats[index] = static_cast(format); - } - - void PackedPipelineState::SetDepthRenderTargetFormat(engine::ZtFormat format) { - depthRenderTargetFormat = static_cast(format) - static_cast(engine::ZtFormat::ZF32); - } - - void PackedPipelineState::SetVertexBinding(u32 index, engine::VertexStream stream, engine::VertexStreamInstance instance) { - vertexBindings[index].stride = stream.format.stride; - vertexBindings[index].inputRate = instance.isInstanced ? vk::VertexInputRate::eInstance : vk::VertexInputRate::eVertex; - vertexBindings[index].enable = stream.format.enable; - vertexBindings[index].divisor = stream.frequency; - } - - void PackedPipelineState::SetTessellationParameters(engine::TessellationParameters parameters) { - domainType = parameters.domainType; - spacing = parameters.spacing; - outputPrimitives = parameters.outputPrimitives; - } - - void PackedPipelineState::SetPolygonMode(engine::PolygonMode mode) { - switch (mode) { - case engine::PolygonMode::Fill: - polygonMode = vk::PolygonMode::eFill; - case engine::PolygonMode::Line: - polygonMode = vk::PolygonMode::eLine; - case engine::PolygonMode::Point: - polygonMode = vk::PolygonMode::ePoint; - default: - throw exception("Invalid polygon mode: 0x{:X}", static_cast(mode)); - } - } - - void PackedPipelineState::SetCullMode(bool enable, engine::CullFace mode) { - if (!enable) { - cullMode = {}; - return; - } - - switch (mode) { - case engine::CullFace::Front: - cullMode = VK_CULL_MODE_FRONT_BIT; - case engine::CullFace::Back: - cullMode = VK_CULL_MODE_BACK_BIT; - case engine::CullFace::FrontAndBack: - cullMode = VK_CULL_MODE_FRONT_BIT | VK_CULL_MODE_BACK_BIT; - default: - throw exception("Invalid cull mode: 0x{:X}", static_cast(mode)); - } - } - - - static vk::CompareOp ConvertCompareFunc(engine::CompareFunc func) { - if (func < engine::CompareFunc::D3DNever || func > engine::CompareFunc::OglAlways || (func > engine::CompareFunc::D3DAlways && func < engine::CompareFunc::OglNever)) - throw exception("Invalid comparision function: 0x{:X}", static_cast(func)); - - u32 val{static_cast(func)}; - - // VK CompareOp values match 1:1 with Maxwell with some small maths - return static_cast(func >= engine::CompareFunc::OglNever ? val - 0x200 : val - 1); - } - - void PackedPipelineState::SetDepthFunc(engine::CompareFunc func) { - depthFunc = ConvertCompareFunc(func); - } - - void PackedPipelineState::SetLogicOp(engine::LogicOp::Func op) { - if (op < engine::LogicOp::Func::Clear || op > engine::LogicOp::Func::Set) - throw exception("Invalid logical operation: 0x{:X}", val); - - // VK LogicOp values match 1:1 with Maxwell - logicOp = static_cast(static_cast(op) - static_cast(engine::LogicOp::Func::Clear)); - } - - static vk::StencilOp ConvertStencilOp(engine::StencilOps::Op op) { - switch (op) { - case engine::StencilOps::Op::OglZero: - case engine::StencilOps::Op::D3DZero: - return vk::StencilOp::eZero; - case engine::StencilOps::Op::D3DKeep: - case engine::StencilOps::Op::OglKeep: - return vk::StencilOp::eKeep; - case engine::StencilOps::Op::D3DReplace: - case engine::StencilOps::Op::OglReplace: - return vk::StencilOp::eReplace; - case engine::StencilOps::Op::D3DIncrSat: - case engine::StencilOps::Op::OglIncrSat: - return vk::StencilOp::eIncrementAndClamp; - case engine::StencilOps::Op::D3DDecrSat: - case engine::StencilOps::Op::OglDecrSat: - return vk::StencilOp::eDecrementAndClamp; - case engine::StencilOps::Op::D3DInvert: - case engine::StencilOps::Op::OglInvert: - return vk::StencilOp::eInvert; - case engine::StencilOps::Op::D3DIncr: - case engine::StencilOps::Op::OglIncr: - return vk::StencilOp::eIncrementAndWrap; - case engine::StencilOps::Op::D3DDecr: - case engine::StencilOps::Op::OglDecr: - return vk::StencilOp::eDecrementAndWrap; - default: - throw exception("Invalid stencil operation: 0x{:X}", static_cast(op)); - } - } - - static PackedPipelineState::StencilOps PackStencilOps(engine::StencilOps ops) { - return { - .zPass = ConvertStencilOp(ops.zPass), - .fail = ConvertStencilOp(ops.fail), - .zFail = ConvertStencilOp(ops.zFail), - .func = ConvertCompareFunc(ops.func), - }; - } - - void PackedPipelineState::SetStencilOps(engine::StencilOps front, engine::StencilOps back) { - stencilFront = PackStencilOps(front); - stencilBack = PackStencilOps(back); - } - - static VkColorComponentFlags ConvertColorWriteMask(engine::CtWrite write) { - return (write.rEnable ? VK_COLOR_COMPONENT_R_BIT : 0) | - (write.gEnable ? VK_COLOR_COMPONENT_G_BIT : 0) | - (write.bEnable ? VK_COLOR_COMPONENT_B_BIT : 0) | - (write.aEnable ? VK_COLOR_COMPONENT_A_BIT : 0); - }; - - static vk::BlendOp ConvertBlendOp(engine::BlendOp op) { - switch (op) { - case engine::BlendOp::D3DAdd: - case engine::BlendOp::OglFuncAdd: - return vk::BlendOp::eAdd; - case engine::BlendOp::D3DSubtract: - case engine::BlendOp::OglFuncSubtract: - return vk::BlendOp::eSubtract; - case engine::BlendOp::D3DRevSubtract: - case engine::BlendOp::OglFuncReverseSubtract: - return vk::BlendOp::eReverseSubtract; - case engine::BlendOp::D3DMin: - case engine::BlendOp::OglMin: - return vk::BlendOp::eMin; - case engine::BlendOp::D3DMax: - case engine::BlendOp::OglMax: - return vk::BlendOp::eMax; - default: - throw exception("Invalid blend operation: 0x{:X}", static_cast(op)); - } - } - - static vk::BlendFactor ConvertBlendFactor(engine::BlendCoeff coeff) { - switch (coeff) { - case engine::BlendCoeff::OglZero: - case engine::BlendCoeff::D3DZero: - return vk::BlendFactor::eZero; - case engine::BlendCoeff::OglOne: - case engine::BlendCoeff::D3DOne: - return vk::BlendFactor::eOne; - case engine::BlendCoeff::OglSrcColor: - case engine::BlendCoeff::D3DSrcColor: - return vk::BlendFactor::eSrcColor; - case engine::BlendCoeff::OglOneMinusSrcColor: - case engine::BlendCoeff::D3DInvSrcColor: - return vk::BlendFactor::eOneMinusSrcColor; - case engine::BlendCoeff::OglSrcAlpha: - case engine::BlendCoeff::D3DSrcAlpha: - return vk::BlendFactor::eSrcAlpha; - case engine::BlendCoeff::OglOneMinusSrcAlpha: - case engine::BlendCoeff::D3DInvSrcAlpha: - return vk::BlendFactor::eOneMinusSrcAlpha; - case engine::BlendCoeff::OglDstAlpha: - case engine::BlendCoeff::D3DDstAlpha: - return vk::BlendFactor::eDstAlpha; - case engine::BlendCoeff::OglOneMinusDstAlpha: - case engine::BlendCoeff::D3DInvDstAlpha: - return vk::BlendFactor::eOneMinusDstAlpha; - case engine::BlendCoeff::OglDstColor: - case engine::BlendCoeff::D3DDstColor: - return vk::BlendFactor::eDstColor; - case engine::BlendCoeff::OglOneMinusDstColor: - case engine::BlendCoeff::D3DInvDstColor: - return vk::BlendFactor::eOneMinusDstColor; - case engine::BlendCoeff::OglSrcAlphaSaturate: - case engine::BlendCoeff::D3DSrcAlphaSaturate: - return vk::BlendFactor::eSrcAlphaSaturate; - case engine::BlendCoeff::OglConstantColor: - case engine::BlendCoeff::D3DBlendCoeff: - return vk::BlendFactor::eConstantColor; - case engine::BlendCoeff::OglOneMinusConstantColor: - case engine::BlendCoeff::D3DInvBlendCoeff: - return vk::BlendFactor::eOneMinusConstantColor; - case engine::BlendCoeff::OglConstantAlpha: - return vk::BlendFactor::eConstantAlpha; - case engine::BlendCoeff::OglOneMinusConstantAlpha: - return vk::BlendFactor::eOneMinusConstantAlpha; - case engine::BlendCoeff::OglSrc1Color: - case engine::BlendCoeff::D3DSrc1Color: - return vk::BlendFactor::eSrc1Color; - case engine::BlendCoeff::OglInvSrc1Color: - case engine::BlendCoeff::D3DInvSrc1Color: - return vk::BlendFactor::eOneMinusSrc1Color; - case engine::BlendCoeff::OglSrc1Alpha: - case engine::BlendCoeff::D3DSrc1Alpha: - return vk::BlendFactor::eSrc1Alpha; - case engine::BlendCoeff::OglInvSrc1Alpha: - case engine::BlendCoeff::D3DInvSrc1Alpha: - return vk::BlendFactor::eOneMinusSrc1Alpha; - default: - throw exception("Invalid blend coefficient type: 0x{:X}", static_cast(coeff)); - } - } - - static PackedPipelineState::AttachmentBlendState PackAttachmentBlendState(bool enable, engine::CtWrite writeMask, auto blend) { - return { - .colorWriteMask = ConvertColorWriteMask(writeMask), - .colorBlendOp = ConvertBlendOp(blend.colorOp), - .srcColorBlendFactor = ConvertBlendFactor(blend.colorSourceCoeff), - .dstColorBlendFactor = ConvertBlendFactor(blend.colorDestCoeff), - .alphaBlendOp = ConvertBlendOp(blend.alphaOp), - .srcAlphaBlendFactor = ConvertBlendFactor(blend.alphaSourceCoeff), - .dstAlphaBlendFactor = ConvertBlendFactor(blend.alphaDestCoeff), - .blendEnable = enable - }; - } - - void PackedPipelineState::SetAttachmentBlendState(u32 index, bool enable, engine::CtWrite writeMask, engine::Blend blend) { - attachmentBlendStates[index] = PackAttachmentBlendState(enable, writeMask, blend); - } - - void PackedPipelineState::SetAttachmentBlendState(u32 index, bool enable, engine::CtWrite writeMask, engine::BlendPerTarget blend) { - attachmentBlendStates[index] = PackAttachmentBlendState(enable, writeMask, blend); - } - /* Colour Render Target */ void ColorRenderTargetState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const { manager.Bind(handle, colorTarget); @@ -629,28 +392,6 @@ namespace skyline::gpu::interconnect::maxwell3d { packedState.SetTessellationParameters(engine.tessellationParameters); } - 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); @@ -678,14 +419,7 @@ namespace skyline::gpu::interconnect::maxwell3d { } } - 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(PackedPipelineState &packedState) { packedState.rasterizerDiscardEnable = !engine->rasterEnable; @@ -712,15 +446,6 @@ namespace skyline::gpu::interconnect::maxwell3d { DepthStencilState::DepthStencilState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine) : engine{manager, dirtyHandle, engine} {} - static vk::StencilOpState ConvertStencilOpsState(engine::StencilOps ops) { - return { - .passOp = ConvertStencilOp(ops.zPass), - .depthFailOp = ConvertStencilOp(ops.zFail), - .failOp = ConvertStencilOp(ops.fail), - .compareOp = ConvertCompareFunc(ops.func), - }; - } - void DepthStencilState::Flush(PackedPipelineState &packedState) { packedState.depthTestEnable = engine->depthTestEnable; packedState.depthWriteEnable = engine->depthWriteEnable; 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 0df876c0..c861f98b 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 @@ -6,101 +6,11 @@ #include #include #include "common.h" +#include "packed_pipeline_state.h" #include "shader_state.h" +#include "pipeline_manager.h" namespace skyline::gpu::interconnect::maxwell3d { - /** - * @brief Packed struct of pipeline state suitable for use as a map key - * @note This is heavily based around yuzu's pipeline key with some packing modifications - * @url https://github.com/yuzu-emu/yuzu/blob/9c701774562ea490296b9cbea3dbd8c096bc4483/src/video_core/renderer_vulkan/fixed_pipeline_state.h#L20 - */ - struct PackedPipelineState { - struct StencilOps { - vk::StencilOp zPass : 3; - vk::StencilOp fail : 3; - vk::StencilOp zFail : 3; - vk::CompareOp func : 3; - // 4 bits left for each stencil side - }; - - StencilOps stencilFront; //!< Use {Set, Get}StencilOps - StencilOps stencilBack; //!< Use {Set, Get}StencilOps - - struct { - u8 depthRenderTargetFormat : 5; //!< Use {Set, Get}DepthRenderTargetFormat - engine::DrawTopology topology : 4; - bool primitiveRestartEnabled : 1; - engine::TessellationParameters::DomainType domainType : 2; //!< Use SetTessellationParameters - engine::TessellationParameters::Spacing spacing : 2; //!< Use SetTessellationParameters - engine::TessellationParameters::OutputPrimitives outputPrimitives : 2; //!< Use SetTessellationParameters - bool rasterizerDiscardEnable : 1; - vk::PolygonMode polygonMode : 2; //!< Use {Set, Get}PolygonMode - VkCullModeFlags cullMode : 2; //!< Use {Set, Get}CullMode - bool flipYEnable : 1; - bool frontFaceClockwise : 1; //!< With Y flip transformation already applied - bool depthBiasEnable : 1; - engine::ProvokingVertex::Value provokingVertex : 1; - bool depthTestEnable : 1; - bool depthWriteEnable : 1; - vk::CompareOp depthFunc : 3; //!< Use {Set, Get}DepthFunc - bool depthBoundsTestEnable : 1; - bool stencilTestEnable : 1; - bool logicOpEnable : 1; - vk::LogicOp logicOp : 4; //!< Use {Set, Get}LogicOp - u8 bindlessTextureConstantBufferSlotSelect : 5; - }; - - u32 patchSize; - std::array vertexAttributes; - std::array colorRenderTargetFormats; //!< Use {Set, Get}ColorRenderTargetFormat - std::array postVtgShaderAttributeSkipMask; - - struct VertexBinding { - u16 stride : 12; - vk::VertexInputRate inputRate : 1; - bool enable : 1; - u8 _pad_ : 2; - u32 divisor; - }; - - std::array vertexBindings; //!< Use {Set, Get}VertexBinding - - struct AttachmentBlendState { - VkColorComponentFlags colorWriteMask : 4; - vk::BlendOp colorBlendOp : 3; - vk::BlendFactor srcColorBlendFactor : 5; - vk::BlendFactor dstColorBlendFactor : 5; - vk::BlendOp alphaBlendOp : 3; - vk::BlendFactor srcAlphaBlendFactor : 5; - vk::BlendFactor dstAlphaBlendFactor : 5; - bool blendEnable : 1; - }; - - std::array attachmentBlendStates; - - void SetColorRenderTargetFormat(size_t index, engine::ColorTarget::Format format); - - void SetDepthRenderTargetFormat(engine::ZtFormat format); - - void SetVertexBinding(u32 index, engine::VertexStream stream, engine::VertexStreamInstance instance); - - void SetTessellationParameters(engine::TessellationParameters parameters); - - void SetPolygonMode(engine::PolygonMode mode); - - void SetCullMode(bool enable, engine::CullFace mode); - - void SetDepthFunc(engine::CompareFunc func); - - void SetStencilOps(engine::StencilOps front, engine::StencilOps back); - - void SetLogicOp(engine::LogicOp::Func op); - - void SetAttachmentBlendState(u32 index, bool enable, engine::CtWrite writeMask, engine::Blend blend); - - void SetAttachmentBlendState(u32 index, bool enable, engine::CtWrite writeMask, engine::BlendPerTarget blend); - }; - class ColorRenderTargetState : dirty::ManualDirty { public: struct EngineRegisters {