diff --git a/bin/resources/shaders/dx11/convert.fx b/bin/resources/shaders/dx11/convert.fx index 2681f65eb2..183fcad4f7 100644 --- a/bin/resources/shaders/dx11/convert.fx +++ b/bin/resources/shaders/dx11/convert.fx @@ -113,6 +113,28 @@ PS_OUTPUT ps_datm0(PS_INPUT input) return output; } +PS_OUTPUT ps_datm1_rta_correction(PS_INPUT input) +{ + PS_OUTPUT output; + + clip(sample_c(input.t).a - 254.5f / 255); // >= 0x80 pass + + output.c = 0; + + return output; +} + +PS_OUTPUT ps_datm0_rta_correction(PS_INPUT input) +{ + PS_OUTPUT output; + + clip(254.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass) + + output.c = 0; + + return output; +} + PS_OUTPUT ps_rta_correction(PS_INPUT input) { PS_OUTPUT output; @@ -414,3 +436,25 @@ float ps_stencil_image_init_1(PS_INPUT input) : SV_Target c = float(0x7FFFFFFF); return c; } + +float ps_stencil_image_init_2(PS_INPUT input) + : SV_Target +{ + float c; + if ((254.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass) + c = float(-1); + else + c = float(0x7FFFFFFF); + return c; +} + +float ps_stencil_image_init_3(PS_INPUT input) + : SV_Target +{ + float c; + if (sample_c(input.t).a < (254.5f / 255.0f)) // >= 0x80 pass + c = float(-1); + else + c = float(0x7FFFFFFF); + return c; +} diff --git a/bin/resources/shaders/opengl/convert.glsl b/bin/resources/shaders/opengl/convert.glsl index c3d9a40be8..ef0ea2a9fe 100644 --- a/bin/resources/shaders/opengl/convert.glsl +++ b/bin/resources/shaders/opengl/convert.glsl @@ -313,6 +313,26 @@ void ps_datm0() } #endif +// Used for DATE (stencil) +// DATM == 1 +#ifdef ps_datm1_rta_correction +void ps_datm1_rta_correction() +{ + if(sample_c().a < (254.5f / 255.0f)) // >= 0x80 pass + discard; +} +#endif + +// Used for DATE (stencil) +// DATM == 0 +#ifdef ps_datm0_rta_correction +void ps_datm0_rta_correction() +{ + if((254.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass) + discard; +} +#endif + #ifdef ps_rta_correction void ps_rta_correction() { @@ -435,7 +455,7 @@ void ps_yuv() } #endif -#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1) +#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1) || defined(ps_stencil_image_init_2) || defined(ps_stencil_image_init_3) void main() { @@ -449,6 +469,14 @@ void main() if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass SV_Target0 = vec4(-1); #endif + #ifdef ps_stencil_image_init_2 + if((254.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass) + SV_Target0 = vec4(-1); + #endif + #ifdef ps_stencil_image_init_3 + if(sample_c().a < (254.5f / 255.0f)) // >= 0x80 pass + SV_Target0 = vec4(-1); + #endif } #endif diff --git a/bin/resources/shaders/opengl/tfx_fs.glsl b/bin/resources/shaders/opengl/tfx_fs.glsl index 0dcae0d976..fe0ccd2d1a 100644 --- a/bin/resources/shaders/opengl/tfx_fs.glsl +++ b/bin/resources/shaders/opengl/tfx_fs.glsl @@ -943,10 +943,18 @@ void ps_main() #if (PS_DATE & 3) == 1 // DATM == 0: Pixel with alpha equal to 1 will failed - bool bad = (127.5f / 255.0f) < rt_a; + #if PS_RTA_CORRECTION + bool bad = (254.5f / 255.0f) < rt_a; + #else + bool bad = (127.5f / 255.0f) < rt_a; + #endif #elif (PS_DATE & 3) == 2 // DATM == 1: Pixel with alpha equal to 0 will failed - bool bad = rt_a < (127.5f / 255.0f); + #if PS_RTA_CORRECTION + bool bad = rt_a < (254.5f / 255.0f); + #else + bool bad = rt_a < (127.5f / 255.0f); + #endif #endif if (bad) { diff --git a/bin/resources/shaders/vulkan/convert.glsl b/bin/resources/shaders/vulkan/convert.glsl index b85f319865..3dafea724a 100644 --- a/bin/resources/shaders/vulkan/convert.glsl +++ b/bin/resources/shaders/vulkan/convert.glsl @@ -24,6 +24,8 @@ layout(location = 0) in vec2 v_tex; layout(location = 0) out uint o_col0; #elif !defined(ps_datm1) && \ !defined(ps_datm0) && \ + !defined(ps_datm1_rta_correction) && \ + !defined(ps_datm0_rta_correction) && \ !defined(ps_convert_rgba8_float32) && \ !defined(ps_convert_rgba8_float24) && \ !defined(ps_convert_rgba8_float16) && \ @@ -92,6 +94,22 @@ void ps_datm0() } #endif +#ifdef ps_datm1_rta_correction +void ps_datm1_rta_correction() +{ + if(sample_c(v_tex).a < (254.5f / 255.0f)) // >= 0x80 pass + discard; +} +#endif + +#ifdef ps_datm0_rta_correction +void ps_datm0_rta_correction() +{ + if((254.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass) + discard; +} +#endif + #ifdef ps_rta_correction void ps_rta_correction() { @@ -416,7 +434,7 @@ void ps_yuv() } #endif -#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1) +#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1) || defined(ps_stencil_image_init_2) || defined(ps_stencil_image_init_3) void main() { @@ -430,6 +448,14 @@ void main() if(sample_c(v_tex).a < (127.5f / 255.0f)) // >= 0x80 pass o_col0 = vec4(-1); #endif + #ifdef ps_stencil_image_init_2 + if((254.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass) + o_col0 = vec4(-1); + #endif + #ifdef ps_stencil_image_init_3 + if(sample_c(v_tex).a < (254.5f / 255.0f)) // >= 0x80 pass + o_col0 = vec4(-1); + #endif } #endif diff --git a/bin/resources/shaders/vulkan/tfx.glsl b/bin/resources/shaders/vulkan/tfx.glsl index fcf75efcf0..79ce3de6c0 100644 --- a/bin/resources/shaders/vulkan/tfx.glsl +++ b/bin/resources/shaders/vulkan/tfx.glsl @@ -1194,10 +1194,18 @@ void main() #if (PS_DATE & 3) == 1 // DATM == 0: Pixel with alpha equal to 1 will failed - bool bad = (127.5f / 255.0f) < rt_a; + #if PS_RTA_CORRECTION + bool bad = (254.5f / 255.0f) < rt_a; + #else + bool bad = (127.5f / 255.0f) < rt_a; + #endif #elif (PS_DATE & 3) == 2 // DATM == 1: Pixel with alpha equal to 0 will failed - bool bad = rt_a < (127.5f / 255.0f); + #if PS_RTA_CORRECTION + bool bad = rt_a < (254.5f / 255.0f); + #else + bool bad = rt_a < (127.5f / 255.0f); + #endif #endif if (bad) { diff --git a/pcsx2/GS/Renderers/Common/GSDevice.cpp b/pcsx2/GS/Renderers/Common/GSDevice.cpp index 8e31b220a8..b94eb29371 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.cpp +++ b/pcsx2/GS/Renderers/Common/GSDevice.cpp @@ -17,6 +17,22 @@ #include +int SetDATMShader(SetDATM datm) +{ + switch (datm) + { + case SetDATM::DATM1_RTA_CORRECTION: + return static_cast(ShaderConvert::DATM_1_RTA_CORRECTION); + case SetDATM::DATM0_RTA_CORRECTION: + return static_cast(ShaderConvert::DATM_0_RTA_CORRECTION); + case SetDATM::DATM1: + return static_cast(ShaderConvert::DATM_1); + case SetDATM::DATM0: + default: + return static_cast(ShaderConvert::DATM_0); + } +} + const char* shaderName(ShaderConvert value) { switch (value) @@ -26,6 +42,8 @@ const char* shaderName(ShaderConvert value) case ShaderConvert::RGBA8_TO_16_BITS: return "ps_convert_rgba8_16bits"; case ShaderConvert::DATM_1: return "ps_datm1"; case ShaderConvert::DATM_0: return "ps_datm0"; + case ShaderConvert::DATM_1_RTA_CORRECTION: return "ps_datm1_rta_correction"; + case ShaderConvert::DATM_0_RTA_CORRECTION: return "ps_datm0_rta_correction"; case ShaderConvert::HDR_INIT: return "ps_hdr_init"; case ShaderConvert::HDR_RESOLVE: return "ps_hdr_resolve"; case ShaderConvert::RTA_CORRECTION: return "ps_rta_correction"; diff --git a/pcsx2/GS/Renderers/Common/GSDevice.h b/pcsx2/GS/Renderers/Common/GSDevice.h index adbcbb0f60..9f76181e75 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.h +++ b/pcsx2/GS/Renderers/Common/GSDevice.h @@ -19,6 +19,8 @@ enum class ShaderConvert RGBA8_TO_16_BITS, DATM_1, DATM_0, + DATM_1_RTA_CORRECTION, + DATM_0_RTA_CORRECTION, HDR_INIT, HDR_RESOLVE, RTA_CORRECTION, @@ -45,6 +47,14 @@ enum class ShaderConvert Count }; +enum class SetDATM : u8 +{ + DATM0 = 0U, + DATM1, + DATM0_RTA_CORRECTION, + DATM1_RTA_CORRECTION +}; + enum class ShaderInterlace { WEAVE = 0, @@ -80,6 +90,8 @@ static inline bool HasStencilOutput(ShaderConvert shader) { case ShaderConvert::DATM_0: case ShaderConvert::DATM_1: + case ShaderConvert::DATM_0_RTA_CORRECTION: + case ShaderConvert::DATM_1_RTA_CORRECTION: return true; default: return false; @@ -140,6 +152,7 @@ enum class PresentShader /// Get the name of a shader /// (Can't put methods on an enum class) +int SetDATMShader(SetDATM datm); const char* shaderName(ShaderConvert value); const char* shaderName(PresentShader value); @@ -653,7 +666,7 @@ struct alignas(16) GSHWDrawConfig bool require_full_barrier; ///< Require texture barrier between all prims DestinationAlphaMode destination_alpha; - bool datm : 1; + SetDATM datm : 2; bool line_expand : 1; bool separate_alpha_pass : 1; bool second_separate_alpha_pass : 1; diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index dfda3905cf..b4d0bb16b3 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -2089,7 +2089,7 @@ void GSDevice11::RenderImGui() m_ctx->IASetVertexBuffers(0, 1, m_vb.addressof(), &m_state.vb_stride, &vb_offset); } -void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm) +void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, SetDATM datm) { // sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows @@ -2117,7 +2117,7 @@ void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vert // ps PSSetShaderResource(0, rt); PSSetSamplerState(m_convert.pt.get()); - PSSetShader(m_convert.ps[static_cast(datm ? ShaderConvert::DATM_1 : ShaderConvert::DATM_0)].get(), nullptr); + PSSetShader(m_convert.ps[SetDATMShader(datm)].get(), nullptr); // @@ -2484,7 +2484,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) return; StretchRect(config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(), - primid_tex, GSVector4(config.drawarea), m_date.primid_init_ps[config.datm].get(), nullptr, false); + primid_tex, GSVector4(config.drawarea), m_date.primid_init_ps[static_cast(config.datm)].get(), nullptr, false); } else if (config.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Off) { diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.h b/pcsx2/GS/Renderers/DX11/GSDevice11.h index 9f70639d4a..790ba68472 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.h +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.h @@ -227,7 +227,7 @@ private: { wil::com_ptr_nothrow dss; wil::com_ptr_nothrow bs; - wil::com_ptr_nothrow primid_init_ps[2]; + wil::com_ptr_nothrow primid_init_ps[4]; } m_date; struct @@ -322,7 +322,7 @@ public: void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override; void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, const GSVector2& ds); - void SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm); + void SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, SetDATM datm); void* IAMapVertexBuffer(u32 stride, u32 count); void IAUnmapVertexBuffer(u32 stride, u32 count); diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index e07ea69eea..a03fde9b88 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -34,7 +34,7 @@ static u32 s_debug_scope_depth = 0; static bool IsDATMConvertShader(ShaderConvert i) { - return (i == ShaderConvert::DATM_0 || i == ShaderConvert::DATM_1); + return (i == ShaderConvert::DATM_0 || i == ShaderConvert::DATM_1 || i == ShaderConvert::DATM_0_RTA_CORRECTION || i == ShaderConvert::DATM_1_RTA_CORRECTION); } static bool IsDATEModePrimIDInit(u32 flag) { @@ -2401,6 +2401,8 @@ bool GSDevice12::CompileConvertPipelines() break; case ShaderConvert::DATM_0: case ShaderConvert::DATM_1: + case ShaderConvert::DATM_0_RTA_CORRECTION: + case ShaderConvert::DATM_1_RTA_CORRECTION: { gpb.ClearRenderTargets(); gpb.SetDepthStencilFormat(DXGI_FORMAT_D32_FLOAT_S8X24_UINT); @@ -2478,10 +2480,10 @@ bool GSDevice12::CompileConvertPipelines() } } - for (u32 datm = 0; datm < 2; datm++) + for (u32 datm = 0; datm < 4; datm++) { - ComPtr ps( - GetUtilityPixelShader(*shader, datm ? "ps_stencil_image_init_1" : "ps_stencil_image_init_0")); + const std::string entry_point(StringUtil::StdStringFromFormat("ps_stencil_image_init_%d", datm)); + ComPtr ps(GetUtilityPixelShader(*shader, entry_point.c_str())); if (!ps) return false; @@ -2501,7 +2503,7 @@ bool GSDevice12::CompileConvertPipelines() return false; D3D12::SetObjectName(m_date_image_setup_pipelines[ds][datm].get(), - TinyString::from_fmt("DATE image clear pipeline (ds={}, datm={})", ds, datm)); + TinyString::from_fmt("DATE image clear pipeline (ds={}, datm={})", ds, (datm == 1 || datm == 3))); } } @@ -3621,7 +3623,7 @@ void GSDevice12::SetPSConstantBuffer(const GSHWDrawConfig::PSConstantBuffer& cb) m_dirty_flags |= DIRTY_FLAG_PS_CONSTANT_BUFFER; } -void GSDevice12::SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVector4i& bbox) +void GSDevice12::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox) { GL_PUSH("SetupDATE {%d,%d} %dx%d", bbox.left, bbox.top, bbox.width(), bbox.height()); @@ -3641,7 +3643,7 @@ void GSDevice12::SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVect OMSetRenderTargets(nullptr, ds, bbox); IASetVertexBuffer(vertices, sizeof(vertices[0]), 4); SetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - SetPipeline(m_convert[static_cast(datm ? ShaderConvert::DATM_1 : ShaderConvert::DATM_0)].get()); + SetPipeline(m_convert[SetDATMShader(datm)].get()); SetStencilRef(1); BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, @@ -3693,7 +3695,7 @@ GSTexture12* GSDevice12::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, Pipe }; SetUtilityRootSignature(); SetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - SetPipeline(m_date_image_setup_pipelines[pipe.ds][config.datm].get()); + SetPipeline(m_date_image_setup_pipelines[pipe.ds][static_cast(config.datm)].get()); IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices)); if (ApplyUtilityState()) DrawPrimitive(); diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.h b/pcsx2/GS/Renderers/DX12/GSDevice12.h index b8a846a3a1..f0104ed90f 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.h +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.h @@ -317,7 +317,7 @@ private: std::array, NUM_INTERLACE_SHADERS> m_interlace{}; std::array, 2> m_hdr_setup_pipelines{}; // [depth] std::array, 2> m_hdr_finish_pipelines{}; // [depth] - std::array, 2>, 2> m_date_image_setup_pipelines{}; // [depth][datm] + std::array, 4>, 2> m_date_image_setup_pipelines{}; // [depth][datm] ComPtr m_fxaa_pipeline; ComPtr m_shadeboost_pipeline; ComPtr m_imgui_pipeline; @@ -450,7 +450,7 @@ public: const ID3D12PipelineState* pipeline, bool linear, bool allow_discard); void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds); - void SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVector4i& bbox); + void SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox); GSTexture12* SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, PipelineSelector& pipe); void IASetVertexBuffer(const void* vertex, size_t stride, size_t count); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index ff34fff158..d775cf7f5a 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -4301,9 +4301,8 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT m_conf.ps.blend_b = 0; m_conf.ps.blend_d = 0; - // TODO: Make it work on DATE, switch to new shaders with Ad doubled. const bool rta_decorrection = m_channel_shuffle || m_texture_shuffle || rt_alpha_max > 128 || m_conf.ps.fbmask || m_conf.ps.tex_is_fb; - const bool rta_correction = !rta_decorrection && !m_cached_ctx.TEST.DATE && !blend_ad_alpha_masked && m_conf.ps.blend_c == 1 && !(blend_flag & BLEND_A_MAX); + const bool rta_correction = !rta_decorrection && !blend_ad_alpha_masked && m_conf.ps.blend_c == 1 && !(blend_flag & BLEND_A_MAX); if (rta_correction) { rt->RTACorrect(rt); @@ -5351,7 +5350,10 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta else if (features.stencil_buffer) m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Stencil; - m_conf.datm = m_cached_ctx.TEST.DATM; + if (m_conf.ps.rta_correction) + m_conf.datm = static_cast(m_cached_ctx.TEST.DATM + 2); + else + m_conf.datm = static_cast(m_cached_ctx.TEST.DATM); // If we're doing stencil DATE and we don't have a depth buffer, we need to allocate a temporary one. GSTexture* temp_ds = nullptr; @@ -6899,7 +6901,7 @@ GSHWDrawConfig& GSRendererHW::BeginHLEHardwareDraw( config.require_one_barrier = false; config.require_full_barrier = false; config.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Off; - config.datm = false; + config.datm = SetDATM::DATM0; config.line_expand = false; config.separate_alpha_pass = false; config.second_separate_alpha_pass = false; diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h index 7a5fef9060..02480d4385 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h @@ -247,13 +247,15 @@ public: MRCOwned> m_convert_pipeline_copy_mask[1 << 4]; MRCOwned> m_merge_pipeline[4]; MRCOwned> m_interlace_pipeline[NUM_INTERLACE_SHADERS]; - MRCOwned> m_datm_pipeline[2]; + MRCOwned> m_datm_pipeline[4]; MRCOwned> m_clut_pipeline[2]; MRCOwned> m_stencil_clear_pipeline; - MRCOwned> m_primid_init_pipeline[2][2]; + MRCOwned> m_primid_init_pipeline[2][4]; MRCOwned> m_hdr_init_pipeline; + MRCOwned> m_hdr_rta_init_pipeline; MRCOwned> m_hdr_clear_pipeline; MRCOwned> m_hdr_resolve_pipeline; + MRCOwned> m_hdr_rta_resolve_pipeline; MRCOwned> m_fxaa_pipeline; MRCOwned> m_shadeboost_pipeline; MRCOwned> m_imgui_pipeline; @@ -430,7 +432,7 @@ public: // MARK: Render HW - void SetupDestinationAlpha(GSTexture* rt, GSTexture* ds, const GSVector4i& r, bool datm); + void SetupDestinationAlpha(GSTexture* rt, GSTexture* ds, const GSVector4i& r, SetDATM datm); void RenderHW(GSHWDrawConfig& config) override; void SendHWDraw(GSHWDrawConfig& config, id enc, id buffer, size_t off); diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm index d4a4430308..b10960d50d 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm @@ -1048,15 +1048,21 @@ bool GSDeviceMTL::Create() pdesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; m_datm_pipeline[0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_datm0"), @"datm0"); m_datm_pipeline[1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_datm1"), @"datm1"); + m_datm_pipeline[2] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_datm0_rta_correction"), @"datm0 rta"); + m_datm_pipeline[3] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_datm1_rta_correction"), @"datm1 rta"); m_stencil_clear_pipeline = MakePipeline(pdesc, fs_triangle, nil, @"Stencil Clear"); pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::PrimID); pdesc.stencilAttachmentPixelFormat = MTLPixelFormatInvalid; pdesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; m_primid_init_pipeline[1][0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm0"), @"PrimID DATM0 Clear"); m_primid_init_pipeline[1][1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm1"), @"PrimID DATM1 Clear"); + m_primid_init_pipeline[1][2] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_rta_init_datm0"), @"PrimID DATM0 RTA Clear"); + m_primid_init_pipeline[1][3] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_rta_init_datm1"), @"PrimID DATM1 RTA Clear"); pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; m_primid_init_pipeline[0][0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm0"), @"PrimID DATM0 Clear"); m_primid_init_pipeline[0][1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm1"), @"PrimID DATM1 Clear"); + m_primid_init_pipeline[0][2] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_rta_init_datm0"), @"PrimID DATM0 RTA Clear"); + m_primid_init_pipeline[0][3] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_rta_init_datm1"), @"PrimID DATM1 RTA Clear"); pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color); applyAttribute(pdesc.vertexDescriptor, 0, MTLVertexFormatFloat2, offsetof(ConvertShaderVertex, pos), 0); @@ -1077,6 +1083,8 @@ bool GSDeviceMTL::Create() case ShaderConvert::Count: case ShaderConvert::DATM_0: case ShaderConvert::DATM_1: + case ShaderConvert::DATM_0_RTA_CORRECTION: + case ShaderConvert::DATM_1_RTA_CORRECTION: case ShaderConvert::CLUT_4: case ShaderConvert::CLUT_8: case ShaderConvert::HDR_INIT: @@ -2032,7 +2040,7 @@ static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, STScale) == of static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, DitherMatrix) == offsetof(GSMTLMainPSUniform, dither_matrix)); static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, ScaleFactor) == offsetof(GSMTLMainPSUniform, scale_factor)); -void GSDeviceMTL::SetupDestinationAlpha(GSTexture* rt, GSTexture* ds, const GSVector4i& r, bool datm) +void GSDeviceMTL::SetupDestinationAlpha(GSTexture* rt, GSTexture* ds, const GSVector4i& r, SetDATM datm) { FlushClears(rt); BeginRenderPass(@"Destination Alpha Setup", nullptr, MTLLoadActionDontCare, nullptr, MTLLoadActionDontCare, ds, MTLLoadActionDontCare); @@ -2040,7 +2048,7 @@ void GSDeviceMTL::SetupDestinationAlpha(GSTexture* rt, GSTexture* ds, const GSVe MRESetDSS(m_dss_stencil_zero); RenderCopy(nullptr, m_stencil_clear_pipeline, r); MRESetDSS(m_dss_stencil_write); - RenderCopy(rt, m_datm_pipeline[datm], r); + RenderCopy(rt, m_datm_pipeline[static_cast(datm)], r); } static id getTexture(GSTexture* tex) @@ -2115,7 +2123,7 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config) dsel.zwe = 0; GSTexture* depth = dsel.key == DepthStencilSelector::NoDepth().key ? nullptr : config.ds; BeginRenderPass(@"PrimID Destination Alpha Init", primid_tex, MTLLoadActionDontCare, depth, MTLLoadActionLoad); - RenderCopy(config.rt, m_primid_init_pipeline[static_cast(depth)][config.datm], config.drawarea); + RenderCopy(config.rt, m_primid_init_pipeline[static_cast(depth)][static_cast(config.datm)], config.drawarea); MRESetDSS(dsel); pxAssert(config.ps.date == 1 || config.ps.date == 2); if (config.ps.tex_is_fb) diff --git a/pcsx2/GS/Renderers/Metal/convert.metal b/pcsx2/GS/Renderers/Metal/convert.metal index dd4c28e896..29fe653131 100644 --- a/pcsx2/GS/Renderers/Metal/convert.metal +++ b/pcsx2/GS/Renderers/Metal/convert.metal @@ -88,20 +88,42 @@ fragment void ps_datm1(float4 p [[position]], DirectReadTextureIn tex) discard_fragment(); } +fragment void ps_datm0_rta_correction(float4 p [[position]], DirectReadTextureIn tex) +{ + if (tex.read(p).a > (254.5f / 255.f)) + discard_fragment(); +} + +fragment void ps_datm1_rta_correction(float4 p [[position]], DirectReadTextureIn tex) +{ + if (tex.read(p).a < (254.5f / 255.f)) + discard_fragment(); +} + fragment void ps_datm0(float4 p [[position]], DirectReadTextureIn tex) { if (tex.read(p).a > (127.5f / 255.f)) discard_fragment(); } +fragment float4 ps_primid_init_datm1(float4 p [[position]], DirectReadTextureIn tex) +{ + return tex.read(p).a < (127.5f / 255.f) ? -1 : FLT_MAX; +} + fragment float4 ps_primid_init_datm0(float4 p [[position]], DirectReadTextureIn tex) { return tex.read(p).a > (127.5f / 255.f) ? -1 : FLT_MAX; } -fragment float4 ps_primid_init_datm1(float4 p [[position]], DirectReadTextureIn tex) +fragment float4 ps_primid_rta_init_datm1(float4 p [[position]], DirectReadTextureIn tex) { - return tex.read(p).a < (127.5f / 255.f) ? -1 : FLT_MAX; + return tex.read(p).a < (254.5f / 255.f) ? -1 : FLT_MAX; +} + +fragment float4 ps_primid_rta_init_datm0(float4 p [[position]], DirectReadTextureIn tex) +{ + return tex.read(p).a > (254.5f / 255.f) ? -1 : FLT_MAX; } fragment float4 ps_rta_correction(float4 p [[position]], DirectReadTextureIn tex) diff --git a/pcsx2/GS/Renderers/Metal/tfx.metal b/pcsx2/GS/Renderers/Metal/tfx.metal index e13c2824d2..b1280f677e 100644 --- a/pcsx2/GS/Renderers/Metal/tfx.metal +++ b/pcsx2/GS/Renderers/Metal/tfx.metal @@ -1019,7 +1019,7 @@ struct PSMain { // 1 => DATM == 0, 2 => DATM == 1 float rt_a = PS_WRITE_RG ? current_color.g : current_color.a; - bool bad = (PS_DATE & 3) == 1 ? (rt_a > 0.5) : (rt_a < 0.5); + bool bad = PS_RTA_CORRECTION ? ((PS_DATE & 3) == 1 ? (rt_a > (254.5f / 255.f)) : (rt_a < (254.5f / 255.f))) : ((PS_DATE & 3) == 1 ? (rt_a > 0.5) : (rt_a < 0.5)); if (bad) discard_fragment(); diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index 3f3e6f5ea3..dc2ff65654 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -1233,7 +1233,7 @@ GSDepthStencilOGL* GSDeviceOGL::CreateDepthStencil(OMDepthStencilSelector dssel) return dss; } -GSTexture* GSDeviceOGL::InitPrimDateTexture(GSTexture* rt, const GSVector4i& area, bool datm) +GSTexture* GSDeviceOGL::InitPrimDateTexture(GSTexture* rt, const GSVector4i& area, SetDATM datm) { const GSVector2i& rtsize = rt->GetSize(); @@ -1242,7 +1242,7 @@ GSTexture* GSDeviceOGL::InitPrimDateTexture(GSTexture* rt, const GSVector4i& are return nullptr; GL_PUSH("PrimID Destination Alpha Clear"); - StretchRect(rt, GSVector4(area) / GSVector4(rtsize).xyxy(), tex, GSVector4(area), m_date.primid_ps[datm], false); + StretchRect(rt, GSVector4(area) / GSVector4(rtsize).xyxy(), tex, GSVector4(area), m_date.primid_ps[static_cast(datm)], false); return tex; } @@ -1856,18 +1856,18 @@ void GSDeviceOGL::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float par StretchRect(sTex, sRect, dTex, dRect, m_shadeboost.ps, false); } -void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm) +void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, SetDATM datm) { GL_PUSH("DATE First Pass"); // sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows OMSetRenderTargets(nullptr, ds, &GLState::scissor); - - const GLint clear_color = 0; - glClearBufferiv(GL_STENCIL, 0, &clear_color); - - m_convert.ps[static_cast(datm ? ShaderConvert::DATM_1 : ShaderConvert::DATM_0)].Bind(); + { + const GLint clear_color = 0; + glClearBufferiv(GL_STENCIL, 0, &clear_color); + } + m_convert.ps[SetDATMShader(datm)].Bind(); // om diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h index 1b2a021bea..2106c49bcd 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h @@ -190,7 +190,7 @@ private: struct { GSDepthStencilOGL* dss = nullptr; - GLProgram primid_ps[2]; + GLProgram primid_ps[4]; } m_date; struct @@ -306,7 +306,7 @@ public: std::unique_ptr CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override; - GSTexture* InitPrimDateTexture(GSTexture* rt, const GSVector4i& area, bool datm); + GSTexture* InitPrimDateTexture(GSTexture* rt, const GSVector4i& area, SetDATM datm); void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) override; @@ -331,7 +331,7 @@ public: void RenderHW(GSHWDrawConfig& config) override; void SendHWDraw(const GSHWDrawConfig& config, bool needs_barrier); - void SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm); + void SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, SetDATM datm); void IASetVAO(GLuint vao); void IASetPrimitiveTopology(GLenum topology); diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 1160b355c8..f47115e36f 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -50,7 +50,7 @@ static u32 s_debug_scope_depth = 0; static bool IsDATMConvertShader(ShaderConvert i) { - return (i == ShaderConvert::DATM_0 || i == ShaderConvert::DATM_1); + return (i == ShaderConvert::DATM_0 || i == ShaderConvert::DATM_1 || i == ShaderConvert::DATM_0_RTA_CORRECTION || i == ShaderConvert::DATM_1_RTA_CORRECTION); } static bool IsDATEModePrimIDInit(u32 flag) { @@ -3967,6 +3967,8 @@ bool GSDeviceVK::CompileConvertPipelines() break; case ShaderConvert::DATM_0: case ShaderConvert::DATM_1: + case ShaderConvert::DATM_0_RTA_CORRECTION: + case ShaderConvert::DATM_1_RTA_CORRECTION: { rp = m_date_setup_render_pass; } @@ -4068,10 +4070,11 @@ bool GSDeviceVK::CompileConvertPipelines() } } - for (u32 datm = 0; datm < 2; datm++) + for (u32 datm = 0; datm < 4; datm++) { + const std::string entry_point(StringUtil::StdStringFromFormat("ps_stencil_image_init_%d", datm)); VkShaderModule ps = - GetUtilityFragmentShader(*shader, datm ? "ps_stencil_image_init_1" : "ps_stencil_image_init_0"); + GetUtilityFragmentShader(*shader, entry_point.c_str()); if (ps == VK_NULL_HANDLE) return false; @@ -4093,7 +4096,7 @@ bool GSDeviceVK::CompileConvertPipelines() return false; Vulkan::SetObjectName(m_device, m_date_image_setup_pipelines[ds][datm], - "DATE image clear pipeline (ds=%u, datm=%u)", ds, datm); + "DATE image clear pipeline (ds=%u, datm=%u)", ds, (datm == 1 || datm == 3)); } } @@ -4624,7 +4627,7 @@ void GSDeviceVK::DestroyResources() } for (u32 ds = 0; ds < 2; ds++) { - for (u32 datm = 0; datm < 2; datm++) + for (u32 datm = 0; datm < 4; datm++) { if (m_date_image_setup_pipelines[ds][datm] != VK_NULL_HANDLE) vkDestroyPipeline(m_device, m_date_image_setup_pipelines[ds][datm], nullptr); @@ -5479,7 +5482,7 @@ void GSDeviceVK::SetPSConstantBuffer(const GSHWDrawConfig::PSConstantBuffer& cb) m_dirty_flags |= DIRTY_FLAG_PS_CONSTANT_BUFFER; } -void GSDeviceVK::SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVector4i& bbox) +void GSDeviceVK::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox) { GL_PUSH("SetupDATE {%d,%d} %dx%d", bbox.left, bbox.top, bbox.width(), bbox.height()); @@ -5498,7 +5501,7 @@ void GSDeviceVK::SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVect SetUtilityTexture(rt, m_point_sampler); OMSetRenderTargets(nullptr, ds, bbox); IASetVertexBuffer(vertices, sizeof(vertices[0]), 4); - SetPipeline(m_convert[static_cast(datm ? ShaderConvert::DATM_1 : ShaderConvert::DATM_0)]); + SetPipeline(m_convert[SetDATMShader(datm)]); BeginClearRenderPass(m_date_setup_render_pass, bbox, 0.0f, 0); if (ApplyUtilityState()) DrawPrimitive(); @@ -5553,7 +5556,7 @@ GSTextureVK* GSDeviceVK::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config) {GSVector4(dst.x, -dst.w, 0.5f, 1.0f), GSVector2(src.x, src.w)}, {GSVector4(dst.z, -dst.w, 0.5f, 1.0f), GSVector2(src.z, src.w)}, }; - const VkPipeline pipeline = m_date_image_setup_pipelines[ds][config.datm]; + const VkPipeline pipeline = m_date_image_setup_pipelines[ds][static_cast(config.datm)]; SetPipeline(pipeline); IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices)); if (ApplyUtilityState()) diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h index 04b57ab516..1982d5c42b 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h @@ -422,7 +422,7 @@ private: VkPipeline m_hdr_setup_pipelines[2][2] = {}; // [depth][feedback_loop] VkPipeline m_hdr_finish_pipelines[2][2] = {}; // [depth][feedback_loop] VkRenderPass m_date_image_setup_render_passes[2][2] = {}; // [depth][clear] - VkPipeline m_date_image_setup_pipelines[2][2] = {}; // [depth][datm] + VkPipeline m_date_image_setup_pipelines[2][4] = {}; // [depth][datm] VkPipeline m_fxaa_pipeline = {}; VkPipeline m_shadeboost_pipeline = {}; @@ -572,7 +572,7 @@ public: void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override; - void SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVector4i& bbox); + void SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox); GSTextureVK* SetupPrimitiveTrackingDATE(GSHWDrawConfig& config); void IASetVertexBuffer(const void* vertex, size_t stride, size_t count);