GS/HW: RTA Correction, implement on DATE.

Less copies, and makes it work with DATE.
This commit is contained in:
lightningterror 2024-02-23 20:00:40 +00:00
parent 58628b8dd3
commit 0900c2fd8b
20 changed files with 240 additions and 56 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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) {

View File

@ -17,6 +17,22 @@
#include <algorithm>
int SetDATMShader(SetDATM datm)
{
switch (datm)
{
case SetDATM::DATM1_RTA_CORRECTION:
return static_cast<int>(ShaderConvert::DATM_1_RTA_CORRECTION);
case SetDATM::DATM0_RTA_CORRECTION:
return static_cast<int>(ShaderConvert::DATM_0_RTA_CORRECTION);
case SetDATM::DATM1:
return static_cast<int>(ShaderConvert::DATM_1);
case SetDATM::DATM0:
default:
return static_cast<int>(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";

View File

@ -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;

View File

@ -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<int>(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<u8>(config.datm)].get(), nullptr, false);
}
else if (config.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Off)
{

View File

@ -227,7 +227,7 @@ private:
{
wil::com_ptr_nothrow<ID3D11DepthStencilState> dss;
wil::com_ptr_nothrow<ID3D11BlendState> bs;
wil::com_ptr_nothrow<ID3D11PixelShader> primid_init_ps[2];
wil::com_ptr_nothrow<ID3D11PixelShader> 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);

View File

@ -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<ID3DBlob> 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<ID3DBlob> 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<int>(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<u8>(config.datm)].get());
IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices));
if (ApplyUtilityState())
DrawPrimitive();

View File

@ -317,7 +317,7 @@ private:
std::array<ComPtr<ID3D12PipelineState>, NUM_INTERLACE_SHADERS> m_interlace{};
std::array<ComPtr<ID3D12PipelineState>, 2> m_hdr_setup_pipelines{}; // [depth]
std::array<ComPtr<ID3D12PipelineState>, 2> m_hdr_finish_pipelines{}; // [depth]
std::array<std::array<ComPtr<ID3D12PipelineState>, 2>, 2> m_date_image_setup_pipelines{}; // [depth][datm]
std::array<std::array<ComPtr<ID3D12PipelineState>, 4>, 2> m_date_image_setup_pipelines{}; // [depth][datm]
ComPtr<ID3D12PipelineState> m_fxaa_pipeline;
ComPtr<ID3D12PipelineState> m_shadeboost_pipeline;
ComPtr<ID3D12PipelineState> 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);

View File

@ -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<SetDATM>(m_cached_ctx.TEST.DATM + 2);
else
m_conf.datm = static_cast<SetDATM>(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;

View File

@ -247,13 +247,15 @@ public:
MRCOwned<id<MTLRenderPipelineState>> m_convert_pipeline_copy_mask[1 << 4];
MRCOwned<id<MTLRenderPipelineState>> m_merge_pipeline[4];
MRCOwned<id<MTLRenderPipelineState>> m_interlace_pipeline[NUM_INTERLACE_SHADERS];
MRCOwned<id<MTLRenderPipelineState>> m_datm_pipeline[2];
MRCOwned<id<MTLRenderPipelineState>> m_datm_pipeline[4];
MRCOwned<id<MTLRenderPipelineState>> m_clut_pipeline[2];
MRCOwned<id<MTLRenderPipelineState>> m_stencil_clear_pipeline;
MRCOwned<id<MTLRenderPipelineState>> m_primid_init_pipeline[2][2];
MRCOwned<id<MTLRenderPipelineState>> m_primid_init_pipeline[2][4];
MRCOwned<id<MTLRenderPipelineState>> m_hdr_init_pipeline;
MRCOwned<id<MTLRenderPipelineState>> m_hdr_rta_init_pipeline;
MRCOwned<id<MTLRenderPipelineState>> m_hdr_clear_pipeline;
MRCOwned<id<MTLRenderPipelineState>> m_hdr_resolve_pipeline;
MRCOwned<id<MTLRenderPipelineState>> m_hdr_rta_resolve_pipeline;
MRCOwned<id<MTLRenderPipelineState>> m_fxaa_pipeline;
MRCOwned<id<MTLRenderPipelineState>> m_shadeboost_pipeline;
MRCOwned<id<MTLRenderPipelineState>> 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<MTLRenderCommandEncoder> enc, id<MTLBuffer> buffer, size_t off);

View File

@ -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<u8>(datm)], r);
}
static id<MTLTexture> 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<bool>(depth)][config.datm], config.drawarea);
RenderCopy(config.rt, m_primid_init_pipeline[static_cast<bool>(depth)][static_cast<u8>(config.datm)], config.drawarea);
MRESetDSS(dsel);
pxAssert(config.ps.date == 1 || config.ps.date == 2);
if (config.ps.tex_is_fb)

View File

@ -88,20 +88,42 @@ fragment void ps_datm1(float4 p [[position]], DirectReadTextureIn<float> tex)
discard_fragment();
}
fragment void ps_datm0_rta_correction(float4 p [[position]], DirectReadTextureIn<float> tex)
{
if (tex.read(p).a > (254.5f / 255.f))
discard_fragment();
}
fragment void ps_datm1_rta_correction(float4 p [[position]], DirectReadTextureIn<float> tex)
{
if (tex.read(p).a < (254.5f / 255.f))
discard_fragment();
}
fragment void ps_datm0(float4 p [[position]], DirectReadTextureIn<float> tex)
{
if (tex.read(p).a > (127.5f / 255.f))
discard_fragment();
}
fragment float4 ps_primid_init_datm1(float4 p [[position]], DirectReadTextureIn<float> tex)
{
return tex.read(p).a < (127.5f / 255.f) ? -1 : FLT_MAX;
}
fragment float4 ps_primid_init_datm0(float4 p [[position]], DirectReadTextureIn<float> tex)
{
return tex.read(p).a > (127.5f / 255.f) ? -1 : FLT_MAX;
}
fragment float4 ps_primid_init_datm1(float4 p [[position]], DirectReadTextureIn<float> tex)
fragment float4 ps_primid_rta_init_datm1(float4 p [[position]], DirectReadTextureIn<float> 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<float> tex)
{
return tex.read(p).a > (254.5f / 255.f) ? -1 : FLT_MAX;
}
fragment float4 ps_rta_correction(float4 p [[position]], DirectReadTextureIn<float> tex)

View File

@ -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();

View File

@ -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<u8>(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<int>(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

View File

@ -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<GSDownloadTexture> 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);

View File

@ -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<int>(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<u8>(config.datm)];
SetPipeline(pipeline);
IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices));
if (ApplyUtilityState())

View File

@ -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);