From 13b291f998a03546837bcc828f5490b65f730368 Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 21 Oct 2026 18:22:09 +0200 Subject: [PATCH] gpu: honour DB_ALPHA_TO_MASK as alpha-to-coverage and keep its depth writes behind the shader --- .../guest_gpu/command_processor/pm4Dispatch.cpp | 1 - .../guest_gpu/command_processor/pm4Dispatch.h | 1 - .../guest_gpu/command_processor/pm4Handlers.cpp | 15 ++------------- src/graphics/guest_gpu/hardwareContext.h | 7 +++++++ src/graphics/guest_gpu/pm4.h | 2 ++ .../host_gpu/renderer/pipeline/pipelineCache.cpp | 1 + .../host_gpu/renderer/pipeline/pipelineCache.h | 3 ++- .../host_gpu/renderer/pipeline/shaders.cpp | 2 ++ src/graphics/host_gpu/renderer/renderDraw.cpp | 2 +- src/graphics/shader/shader.cpp | 3 ++- 10 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp b/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp index 12a7a6050..7d09ce240 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp @@ -73,7 +73,6 @@ constexpr auto MakeContextDispatchTable() { g_hw_ctx_func[Pm4::PA_SC_BINNER_CNTL_0] = HwCtxSetPaScExtendedControl; g_hw_ctx_func[Pm4::PA_SC_BINNER_CNTL_1] = HwCtxSetPaScExtendedControl; g_hw_ctx_func[Pm4::PA_SC_CONSERVATIVE_RASTERIZATION_CNTL] = HwCtxSetPaScExtendedControl; - g_hw_ctx_func[Pm4::DB_ALPHA_TO_MASK] = HwCtxSetAlphaToMask; g_hw_ctx_func[Pm4::VGT_DRAW_PAYLOAD_CNTL] = HwCtxSetDrawPayloadControl; g_hw_ctx_func[Pm4::VGT_PRIMITIVEID_RESET] = HwCtxSetPrimitiveIdReset; g_hw_ctx_func[Pm4::PA_CL_OBJPRIM_ID_CNTL] = HwCtxSetObjprimIdControl; diff --git a/src/graphics/guest_gpu/command_processor/pm4Dispatch.h b/src/graphics/guest_gpu/command_processor/pm4Dispatch.h index 419c74905..7979ebcd6 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Dispatch.h +++ b/src/graphics/guest_gpu/command_processor/pm4Dispatch.h @@ -79,7 +79,6 @@ uint32_t HwCtxSetAaMask(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t HwCtxSetVtxControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); uint32_t HwCtxSetPaScExtendedControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetAlphaToMask(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); uint32_t HwCtxSetDrawPayloadControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); uint32_t HwCtxSetPrimitiveIdReset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); diff --git a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp index 736e77d7f..62e95890a 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp @@ -283,8 +283,6 @@ KYTY_HW_CTX_PARSER(HwCtxSetCentroidPriority) { static void HwCtxIgnoreAaMaskRegister([[maybe_unused]] uint32_t cmd_offset, [[maybe_unused]] uint32_t value) {} -static void HwCtxIgnoreAlphaToMaskRegister([[maybe_unused]] uint32_t value) {} - static void HwCtxIgnorePrimitiveIdReset([[maybe_unused]] uint32_t value) {} static void HwCtxIgnoreVtxControl([[maybe_unused]] uint32_t value) {} @@ -429,16 +427,6 @@ KYTY_HW_CTX_PARSER(HwCtxSetPointState) { return num_values; } -KYTY_HW_CTX_PARSER(HwCtxSetAlphaToMask) { - auto num_values = KYTY_PM4_LEN(cmd_id) - 2u; - - for (uint32_t i = 0; i < num_values; i++) { - HwCtxIgnoreAlphaToMaskRegister(buffer[i]); - } - - return num_values; -} - KYTY_HW_CTX_PARSER(HwCtxSetDrawPayloadControl) { cp.GetCtx().SetDrawPayloadControl(buffer[0]); return KYTY_PM4_LEN(cmd_id) - 2u; @@ -3465,7 +3453,8 @@ void GraphicsInitJmpTablesCxIndirect() { g_hw_ctx_indirect_func[Pm4::PA_SC_CONSERVATIVE_RASTERIZATION_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { HwCtxIgnorePaScExtendedControl(cmd_offset, value); }; g_hw_ctx_indirect_func[Pm4::DB_ALPHA_TO_MASK] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - HwCtxIgnoreAlphaToMaskRegister(value); + cp.GetCtx().SetAlphaToMaskEnable( + KYTY_PM4_GET(value, DB_ALPHA_TO_MASK, ALPHA_TO_MASK_ENABLE) != 0); }; g_hw_ctx_indirect_func[Pm4::CB_COLOR_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { cp.GetCtx().SetColorControl(DecodeColorControl(value)); diff --git a/src/graphics/guest_gpu/hardwareContext.h b/src/graphics/guest_gpu/hardwareContext.h index cb0be0958..97977fe2c 100644 --- a/src/graphics/guest_gpu/hardwareContext.h +++ b/src/graphics/guest_gpu/hardwareContext.h @@ -576,6 +576,12 @@ struct ShaderRegisters { uint32_t m_paScShaderControl = 0; DepthShaderControl db_shader_control; + bool alpha_to_mask_enable = false; + + // DB_SHADER_CONTROL.ALPHA_TO_MASK_DISABLE overrides DB_ALPHA_TO_MASK per shader. + [[nodiscard]] bool AlphaToMask() const { + return alpha_to_mask_enable && !db_shader_control.alpha_to_mask_disable; + } [[nodiscard]] uint32_t GetExportCount() const { return 1u + ((m_spiVsOutConfig >> 1u) & 0x1Fu); @@ -915,6 +921,7 @@ public: void SetDepthShaderControl(const DepthShaderControl& value) { m_sh_regs.db_shader_control = value; } + void SetAlphaToMaskEnable(bool value) { m_sh_regs.alpha_to_mask_enable = value; } void SetScShaderControl(uint32_t value) { m_sh_regs.m_paScShaderControl = value; } diff --git a/src/graphics/guest_gpu/pm4.h b/src/graphics/guest_gpu/pm4.h index 186c8844c..74dd4ed7f 100644 --- a/src/graphics/guest_gpu/pm4.h +++ b/src/graphics/guest_gpu/pm4.h @@ -549,6 +549,8 @@ constexpr uint32_t VGT_SHADER_STAGES_EN = 0x2D5; constexpr uint32_t VGT_LS_HS_CONFIG = 0x2D6; constexpr uint32_t VGT_TF_PARAM = 0x2DB; constexpr uint32_t DB_ALPHA_TO_MASK = 0x2DC; +constexpr uint32_t DB_ALPHA_TO_MASK_ALPHA_TO_MASK_ENABLE_SHIFT = 0; +constexpr uint32_t DB_ALPHA_TO_MASK_ALPHA_TO_MASK_ENABLE_MASK = 0x1; constexpr uint32_t PA_SU_POLY_OFFSET_DB_FMT_CNTL = 0x2DE; constexpr uint32_t PA_SU_POLY_OFFSET_DB_FMT_CNTL_NEG_NUM_DB_BITS_SHIFT = 0; constexpr uint32_t PA_SU_POLY_OFFSET_DB_FMT_CNTL_NEG_NUM_DB_BITS_MASK = 0xFF; diff --git a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp index b54834970..f819686b1 100644 --- a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp @@ -971,6 +971,7 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline( if (static_params.sample_shading_enable && !m_graphics.sample_rate_shading_enabled) { EXIT("Pipeline: sample-rate shading is required but unsupported by the host\n"); } + static_params.alpha_to_coverage_enable = ps_active && ctx.GetShaderRegisters().AlphaToMask(); const bool rect_list = Prospero::IsRectList(command.GetUserConfig().GetPrimType()); static_params.cull_back = !rect_list && mc.cull_back; static_params.cull_front = !rect_list && mc.cull_front; diff --git a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h index 87415984f..1f8e217f9 100644 --- a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h +++ b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h @@ -39,6 +39,7 @@ struct PipelineStaticParameters { bool primitive_restart_enable = false; uint32_t samples = 1; bool sample_shading_enable = false; + bool alpha_to_coverage_enable = false; uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {}; bool cull_front = false; bool cull_back = false; @@ -62,7 +63,7 @@ struct PipelineStaticParameters { static_assert(std::is_trivially_copyable_v); static_assert(std::is_standard_layout_v); static_assert(alignof(PipelineStaticParameters) == 1); -static_assert(sizeof(PipelineStaticParameters) == 116); +static_assert(sizeof(PipelineStaticParameters) == 117); struct PipelineRenderingState { std::array color_formats {}; diff --git a/src/graphics/host_gpu/renderer/pipeline/shaders.cpp b/src/graphics/host_gpu/renderer/pipeline/shaders.cpp index 115ec6fb3..0f413713f 100644 --- a/src/graphics/host_gpu/renderer/pipeline/shaders.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/shaders.cpp @@ -422,6 +422,8 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p multisampling.sampleShadingEnable = static_params.sample_shading_enable ? VK_TRUE : VK_FALSE; multisampling.rasterizationSamples = vulkan_sample_count(static_params.samples); multisampling.minSampleShading = 1.0f; + multisampling.alphaToCoverageEnable = + static_params.alpha_to_coverage_enable ? VK_TRUE : VK_FALSE; vk::PipelineColorBlendAttachmentState color_blend_attachment[RENDER_COLOR_ATTACHMENTS_MAX] = {}; for (uint32_t i = 0; i < rendering.color_count; i++) { diff --git a/src/graphics/host_gpu/renderer/renderDraw.cpp b/src/graphics/host_gpu/renderer/renderDraw.cpp index f4dc30eb0..475711c8d 100644 --- a/src/graphics/host_gpu/renderer/renderDraw.cpp +++ b/src/graphics/host_gpu/renderer/renderDraw.cpp @@ -436,7 +436,7 @@ static bool DrawHasValidVertexShader(const HW::Shader& sh_ctx) { static bool PixelShaderHasDepthOrCoverageSideEffects(const HW::ShaderRegisters& sh_regs) { const auto& db = sh_regs.db_shader_control; return db.shader_kill_enable || db.shader_z_export_enable || db.shader_mask_export_enable || - db.shader_dual_export_enable || db.shader_execute_on_noop; + db.shader_dual_export_enable || db.shader_execute_on_noop || sh_regs.AlphaToMask(); } struct DrawRenderState { diff --git a/src/graphics/shader/shader.cpp b/src/graphics/shader/shader.cpp index f6339fceb..76f52cca7 100644 --- a/src/graphics/shader/shader.cpp +++ b/src/graphics/shader/shader.cpp @@ -355,10 +355,11 @@ static void ShaderGetStaticInputInfoPS( ps_info.ps_pixel_kill_enable = sh.db_shader_control.shader_kill_enable; ps_info.ps_depth_export_enable = sh.db_shader_control.shader_z_export_enable; ps_info.ps_sample_mask_export_enable = sh.db_shader_control.shader_mask_export_enable; + // Alpha-to-mask coverage must gate depth writes, so it rules out early fragment tests. ps_info.ps_early_z = (sh.db_shader_control.shader_z_behavior == 1 && !sh.db_shader_control.shader_kill_enable && !sh.db_shader_control.shader_z_export_enable && - !sh.db_shader_control.shader_mask_export_enable); + !sh.db_shader_control.shader_mask_export_enable && !sh.AlphaToMask()); ps_info.ps_execute_on_noop = sh.db_shader_control.shader_execute_on_noop; for (uint32_t i = 0; i < ps_info.input_num; i++) {