From 6865f0bdafdfb4efd08fa6842a952aee36e2e476 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Tue, 6 Sep 2022 21:14:40 +0100 Subject: [PATCH] Transition color blend state to packed pipeline state --- .../maxwell_3d/pipeline_state.cpp | 253 +++++++++--------- .../interconnect/maxwell_3d/pipeline_state.h | 37 ++- 2 files changed, 156 insertions(+), 134 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 75bee6bc..4c16a07c 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 @@ -83,6 +83,14 @@ namespace skyline::gpu::interconnect::maxwell3d { 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: @@ -128,6 +136,118 @@ namespace skyline::gpu::interconnect::maxwell3d { 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); @@ -618,134 +738,19 @@ namespace skyline::gpu::interconnect::maxwell3d { ColorBlendState::ColorBlendState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine) : engine{manager, dirtyHandle, engine} {} - static vk::ColorComponentFlags ConvertColorWriteMask(engine::CtWrite write) { - return vk::ColorComponentFlags{ - write.rEnable ? vk::ColorComponentFlagBits::eR : vk::ColorComponentFlags{} | - write.gEnable ? vk::ColorComponentFlagBits::eG : vk::ColorComponentFlags{} | - write.bEnable ? vk::ColorComponentFlagBits::eB : vk::ColorComponentFlags{} | - write.aEnable ? vk::ColorComponentFlagBits::eA : vk::ColorComponentFlags{} - }; - } + void ColorBlendState::Flush(PackedPipelineState &packedState) { + packedState.logicOpEnable = engine->logicOp.enable; + packedState.SetLogicOp(engine->logicOp.func); - 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)); - } - } + for (u32 i{}; i < engine::ColorTargetCount; i++) { + auto ctWrite{engine->singleCtWriteControl ? engine->ctWrites[0] : engine->ctWrites[i]}; + bool enable{engine->blend.enable[i] != 0}; - 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)); - } - } - - void ColorBlendState::Flush(InterconnectContext &ctx, size_t attachmentCount) { - if (engine->logicOp.enable) { - if (ctx.gpu.traits.supportsLogicOp) { - colorBlendState.logicOpEnable = true; - colorBlendState.logicOp = ConvertLogicOpFunc(engine->logicOp.func); - } else { - Logger::Warn("Cannot enable framebuffer logical operation without host GPU support!"); - } - } - - auto convertBlendState{[](vk::PipelineColorBlendAttachmentState &attachmentBlendState, const auto &blend) { - attachmentBlendState.colorBlendOp = ConvertBlendOp(blend.colorOp); - attachmentBlendState.srcColorBlendFactor = ConvertBlendFactor(blend.colorSourceCoeff); - attachmentBlendState.dstColorBlendFactor = ConvertBlendFactor(blend.colorDestCoeff); - attachmentBlendState.alphaBlendOp = ConvertBlendOp(blend.alphaOp); - attachmentBlendState.srcAlphaBlendFactor = ConvertBlendFactor(blend.alphaSourceCoeff); - attachmentBlendState.dstAlphaBlendFactor = ConvertBlendFactor(blend.alphaDestCoeff); - }}; - - for (size_t i{}; i < engine::ColorTargetCount; i++) { - auto &attachmentBlendState{attachmentBlendStates[i]}; - attachmentBlendState.blendEnable = engine->blend.enable[i]; - attachmentBlendState.colorWriteMask = ConvertColorWriteMask(engine->singleCtWriteControl ? engine->ctWrites[0] : engine->ctWrites[i]); if (engine->blendStatePerTargetEnable) - convertBlendState(attachmentBlendState, engine->blendPerTargets[i]); + packedState.SetAttachmentBlendState(i, enable, ctWrite, engine->blendPerTargets[i]); else - convertBlendState(attachmentBlendState, engine->blend); + packedState.SetAttachmentBlendState(i, enable, ctWrite, engine->blend); } - - colorBlendState.attachmentCount = static_cast(attachmentCount); - colorBlendState.pAttachments = attachmentBlendStates.data(); - } - - void ColorBlendState::Refresh(InterconnectContext &ctx, size_t attachmentCount) { - colorBlendState.attachmentCount = static_cast(attachmentCount); } /* Pipeline State */ @@ -784,7 +789,7 @@ namespace skyline::gpu::interconnect::maxwell3d { .rasterizationSamples = vk::SampleCountFlagBits::e1 }; */ depthStencil.Update(packedState); - const auto &colorBlendState{colorBlend.UpdateGet(ctx, colorAttachments.size()).colorBlendState}; + colorBlend.Update(packedState); constexpr std::array dynamicStates{ vk::DynamicState::eViewport, 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 46f7212d..32c580ce 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 @@ -45,8 +45,14 @@ namespace skyline::gpu::interconnect::maxwell3d { 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 }; + u32 patchSize; + std::array vertexAttributes; + std::array colorRenderTargetFormats; //!< Use {Set, Get}ColorRenderTargetFormat + struct VertexBinding { u16 stride : 12; vk::VertexInputRate inputRate : 1; @@ -55,10 +61,20 @@ namespace skyline::gpu::interconnect::maxwell3d { u32 divisor; }; - u32 patchSize; - std::array colorRenderTargetFormats; //!< Use {Set, Get}ColorRenderTargetFormat std::array vertexBindings; //!< Use {Set, Get}VertexBinding - std::array vertexAttributes; + + 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); @@ -75,6 +91,12 @@ namespace skyline::gpu::interconnect::maxwell3d { 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 { @@ -243,7 +265,7 @@ namespace skyline::gpu::interconnect::maxwell3d { void Flush(PackedPipelineState &packedState); }; - class ColorBlendState : dirty::RefreshableManualDirty { + class ColorBlendState : dirty::ManualDirty { public: struct EngineRegisters { const engine::LogicOp &logicOp; @@ -258,16 +280,11 @@ namespace skyline::gpu::interconnect::maxwell3d { private: dirty::BoundSubresource engine; - std::array attachmentBlendStates; public: - vk::PipelineColorBlendStateCreateInfo colorBlendState{}; - ColorBlendState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); - void Flush(InterconnectContext &ctx, size_t attachmentCount); - - void Refresh(InterconnectContext &ctx, size_t attachmentCount); + void Flush(PackedPipelineState &packedState); }; /**