From 4cc2220f2f0a048020f3970bf46e393a3f58ad56 Mon Sep 17 00:00:00 2001 From: IndecisiveTurtle <47210458+raphaelthegreat@users.noreply.github.com> Date: Mon, 14 Jul 2025 01:34:01 +0300 Subject: [PATCH] renderer_vulkan: Implement logic ops --- src/video_core/amdgpu/liverpool.h | 20 +++++++++- .../renderer_vulkan/liverpool_to_vk.cpp | 40 +++++++++++++++++++ .../renderer_vulkan/liverpool_to_vk.h | 2 + .../renderer_vulkan/vk_graphics_pipeline.cpp | 5 ++- .../renderer_vulkan/vk_graphics_pipeline.h | 1 + src/video_core/renderer_vulkan/vk_instance.h | 5 +++ .../renderer_vulkan/vk_pipeline_cache.cpp | 1 + 7 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 68209bbb6..e0c35fc33 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -791,11 +791,29 @@ struct Liverpool { Err = 4u, FmaskDecompress = 5u, }; + enum class LogicOp : u32 { + Clear = 0x00, + Nor = 0x11, + AndInverted = 0x22, + CopyInverted = 0x33, + AndReverse = 0x44, + Invert = 0x55, + Xor = 0x66, + Nand = 0x77, + And = 0x88, + Equiv = 0x99, + Noop = 0xAA, + OrInverted = 0xBB, + Copy = 0xCC, + OrReverse = 0xDD, + Or = 0xEE, + Set = 0xFF, + }; BitField<0, 1, u32> disable_dual_quad; BitField<3, 1, u32> degamma_enable; BitField<4, 3, OperationMode> mode; - BitField<16, 8, u32> rop3; + BitField<16, 8, LogicOp> rop3; }; struct ColorBuffer { diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp index 5972296c0..fd1a91260 100644 --- a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp +++ b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp @@ -245,6 +245,46 @@ vk::BlendOp BlendOp(Liverpool::BlendControl::BlendFunc func) { } } +vk::LogicOp LogicOp(Liverpool::ColorControl::LogicOp logic_op) { + using LogicOp = Liverpool::ColorControl::LogicOp; + switch (logic_op) { + case LogicOp::Clear: + return vk::LogicOp::eClear; + case LogicOp::Nor: + return vk::LogicOp::eNor; + case LogicOp::AndInverted: + return vk::LogicOp::eAndInverted; + case LogicOp::CopyInverted: + return vk::LogicOp::eCopyInverted; + case LogicOp::AndReverse: + return vk::LogicOp::eAndReverse; + case LogicOp::Invert: + return vk::LogicOp::eInvert; + case LogicOp::Xor: + return vk::LogicOp::eXor; + case LogicOp::Nand: + return vk::LogicOp::eNand; + case LogicOp::And: + return vk::LogicOp::eAnd; + case LogicOp::Equiv: + return vk::LogicOp::eEquivalent; + case LogicOp::Noop: + return vk::LogicOp::eNoOp; + case LogicOp::OrInverted: + return vk::LogicOp::eOrInverted; + case LogicOp::Copy: + return vk::LogicOp::eCopy; + case LogicOp::OrReverse: + return vk::LogicOp::eOrReverse; + case LogicOp::Or: + return vk::LogicOp::eOr; + case LogicOp::Set: + return vk::LogicOp::eSet; + default: + UNREACHABLE_MSG("Unknown logic op {}", u32(logic_op)); + } +} + // https://github.com/chaotic-cx/mesa-mirror/blob/0954afff5/src/amd/vulkan/radv_sampler.c#L21 vk::SamplerAddressMode ClampMode(AmdGpu::ClampMode mode) { switch (mode) { diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.h b/src/video_core/renderer_vulkan/liverpool_to_vk.h index 61fd4a8c1..61b7ea0a9 100644 --- a/src/video_core/renderer_vulkan/liverpool_to_vk.h +++ b/src/video_core/renderer_vulkan/liverpool_to_vk.h @@ -34,6 +34,8 @@ bool IsDualSourceBlendFactor(Liverpool::BlendControl::BlendFactor factor); vk::BlendOp BlendOp(Liverpool::BlendControl::BlendFunc func); +vk::LogicOp LogicOp(Liverpool::ColorControl::LogicOp logic_op); + vk::SamplerAddressMode ClampMode(AmdGpu::ClampMode mode); vk::CompareOp DepthCompare(AmdGpu::DepthCompare comp); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 8be221697..91d0de4b9 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -286,8 +286,9 @@ GraphicsPipeline::GraphicsPipeline( } const vk::PipelineColorBlendStateCreateInfo color_blending = { - .logicOpEnable = false, - .logicOp = vk::LogicOp::eCopy, + .logicOpEnable = + instance.IsLogicOpSupported() && key.logic_op != Liverpool::ColorControl::LogicOp::Copy, + .logicOp = LiverpoolToVK::LogicOp(key.logic_op), .attachmentCount = key.num_color_attachments, .pAttachments = attachments.data(), .blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f}, diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 30b73f698..340383d91 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -41,6 +41,7 @@ struct GraphicsPipelineKey { std::array blend_controls; std::array write_masks; Liverpool::ColorBufferMask cb_shader_mask; + Liverpool::ColorControl::LogicOp logic_op; u32 num_samples; u32 mrt_mask; vk::Format depth_format; diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index 19ab563e5..40a9133ab 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -356,6 +356,11 @@ public: return driver_id != vk::DriverId::eMoltenvk; } + /// Returns true if logic ops are supported by the device. + bool IsLogicOpSupported() const { + return features.logicOp; + } + /// Determines if a format is supported for a set of feature flags. [[nodiscard]] bool IsFormatSupported(vk::Format format, vk::FormatFeatureFlags2 flags) const; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 06526477a..69f040bf8 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -304,6 +304,7 @@ bool PipelineCache::RefreshGraphicsKey() { key.polygon_mode = regs.polygon_control.PolyMode(); key.clip_space = regs.clipper_control.clip_space; key.provoking_vtx_last = regs.polygon_control.provoking_vtx_last; + key.logic_op = regs.color_control.rop3; key.num_samples = regs.NumSamples(); const bool skip_cb_binding =