mirror of https://github.com/PCSX2/pcsx2.git
GS: added Motion Adaptive Deinterlacing support for Metal renderer
This commit is contained in:
parent
0f42eab7a4
commit
79b5f2154f
|
@ -150,7 +150,7 @@ The clamp modes are also numerically based.
|
|||
Default: None (`0`)
|
||||
* deinterlace
|
||||
[Value between `0` to `9`]
|
||||
{Automatic Off, WeaveTFF, WeaveBFF, BobTFF, BobBFF, BlendTFF, BlendBFF, AdaptiveTFF, AdaptiveBFF}
|
||||
{Automatic, Off, WeaveTFF, WeaveBFF, BobTFF, BobBFF, BlendTFF, BlendBFF, AdaptiveTFF, AdaptiveBFF}
|
||||
Default: Automatic (No value, looks up GameDB)
|
||||
|
||||
### GS Hardware Renderer Fixes
|
||||
|
|
|
@ -347,7 +347,7 @@ public:
|
|||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) override;
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset) override;
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset, int bufIdx) override;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) override;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) override;
|
||||
void DoExternalFX(GSTexture* sTex, GSTexture* dTex) override;
|
||||
|
|
|
@ -583,18 +583,19 @@ void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
|||
StretchRect(dTex, full_r, sTex[2], dRect[0], ShaderConvert::YUV);
|
||||
}}
|
||||
|
||||
void GSDeviceMTL::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset)
|
||||
void GSDeviceMTL::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset, int bufIdx)
|
||||
{ @autoreleasepool {
|
||||
id<MTLCommandBuffer> cmdbuf = GetRenderCmdBuf();
|
||||
GSScopedDebugGroupMTL dbg(cmdbuf, @"DoInterlace");
|
||||
|
||||
GSVector4 s = GSVector4(dTex->GetSize());
|
||||
GSVector4 ss = GSVector4(sTex->GetSize());
|
||||
GSVector4 ds = GSVector4(dTex->GetSize());
|
||||
|
||||
GSVector4 sRect(0, 0, 1, 1);
|
||||
GSVector4 dRect(0.f, yoffset, s.x, s.y + yoffset);
|
||||
GSVector4 dRect(0.f, yoffset, ds.x, ds.y + yoffset);
|
||||
|
||||
GSMTLInterlacePSUniform cb = {};
|
||||
cb.ZrH = {0, 1.f / s.y};
|
||||
cb.ZrH = {static_cast<float>(bufIdx), 1.0f / ss.y, ss.y, MAD_SENSITIVITY};
|
||||
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_interlace_pipeline[shader], linear, shader > 1 ? LoadAction::DontCareIfFull : LoadAction::Load, &cb, sizeof(cb));
|
||||
}}
|
||||
|
|
|
@ -54,7 +54,7 @@ struct GSMTLPresentPSUniform
|
|||
|
||||
struct GSMTLInterlacePSUniform
|
||||
{
|
||||
vector_float2 ZrH;
|
||||
vector_float4 ZrH;
|
||||
};
|
||||
|
||||
struct GSMTLMainVertex
|
||||
|
|
|
@ -36,9 +36,10 @@ fragment float4 ps_interlace1(ConvertShaderData data [[stage_in]], ConvertPSRes
|
|||
fragment float4 ps_interlace2(ConvertShaderData data [[stage_in]], ConvertPSRes res,
|
||||
constant GSMTLInterlacePSUniform& uniform [[buffer(GSMTLBufferIndexUniforms)]])
|
||||
{
|
||||
float4 c0 = res.sample(data.t - uniform.ZrH);
|
||||
float2 vstep = float2(0.0f, uniform.ZrH.y);
|
||||
float4 c0 = res.sample(data.t - vstep);
|
||||
float4 c1 = res.sample(data.t);
|
||||
float4 c2 = res.sample(data.t + uniform.ZrH);
|
||||
float4 c2 = res.sample(data.t + vstep);
|
||||
return (c0 + c1 * 2.f + c2) / 4.f;
|
||||
}
|
||||
|
||||
|
@ -47,3 +48,124 @@ fragment float4 ps_interlace3(ConvertShaderData data [[stage_in]], ConvertPSRes
|
|||
return res.sample(data.t);
|
||||
}
|
||||
|
||||
fragment float4 ps_interlace4(ConvertShaderData data [[stage_in]], ConvertPSRes res,
|
||||
constant GSMTLInterlacePSUniform& uniform [[buffer(GSMTLBufferIndexUniforms)]])
|
||||
{
|
||||
const int vres = int(round(uniform.ZrH.z));
|
||||
const int idx = int(round(uniform.ZrH.x));
|
||||
const int bank = idx >> 1;
|
||||
const int field = idx & 1;
|
||||
const int vpos = int(data.p.y) + (((((vres + 1) >> 1) << 1) - vres) & bank);
|
||||
const float2 bofs = float2(0.0f, 0.5f * bank);
|
||||
const float2 vscale = float2(1.0f, 2.0f);
|
||||
const float2 optr = data.t - bofs;
|
||||
const float2 iptr = optr * vscale;
|
||||
|
||||
if ((optr.y >= 0.0f) && (optr.y < 0.5f) && ((vpos & 1) == field))
|
||||
return res.sample(iptr);
|
||||
else
|
||||
discard_fragment();
|
||||
|
||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
}
|
||||
|
||||
fragment float4 ps_interlace5(ConvertShaderData data [[stage_in]], ConvertPSRes res,
|
||||
constant GSMTLInterlacePSUniform& uniform [[buffer(GSMTLBufferIndexUniforms)]])
|
||||
{
|
||||
const float sensitivity = uniform.ZrH.w;
|
||||
const float3 motion_thr = float3(1.0, 1.0, 1.0) * sensitivity;
|
||||
const float2 vofs = float2(0.0f, 0.5f);
|
||||
const float2 vscale = float2(1.0f, 0.5f);
|
||||
const int idx = int(round(uniform.ZrH.x));
|
||||
const int bank = idx >> 1;
|
||||
const int field = idx & 1;
|
||||
const float2 line_ofs = float2(0.0f, uniform.ZrH.y);
|
||||
const float2 iptr = data.t * vscale;
|
||||
|
||||
float2 p_new_cf;
|
||||
float2 p_old_cf;
|
||||
float2 p_new_af;
|
||||
float2 p_old_af;
|
||||
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
p_new_cf = iptr;
|
||||
p_new_af = iptr + vofs;
|
||||
p_old_cf = iptr + vofs;
|
||||
p_old_af = iptr;
|
||||
break;
|
||||
case 1:
|
||||
p_new_cf = iptr;
|
||||
p_new_af = iptr;
|
||||
p_old_cf = iptr + vofs;
|
||||
p_old_af = iptr + vofs;
|
||||
break;
|
||||
case 2:
|
||||
p_new_cf = iptr + vofs;
|
||||
p_new_af = iptr;
|
||||
p_old_cf = iptr;
|
||||
p_old_af = iptr + vofs;
|
||||
break;
|
||||
case 3:
|
||||
p_new_cf = iptr + vofs;
|
||||
p_new_af = iptr + vofs;
|
||||
p_old_cf = iptr;
|
||||
p_old_af = iptr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// calculating motion
|
||||
|
||||
float4 hn = res.sample(p_new_cf - line_ofs); // high
|
||||
float4 cn = res.sample(p_new_af); // center
|
||||
float4 ln = res.sample(p_new_cf + line_ofs); // low
|
||||
|
||||
float4 ho = res.sample(p_old_cf - line_ofs); // high
|
||||
float4 co = res.sample(p_old_af); // center
|
||||
float4 lo = res.sample(p_old_cf + line_ofs); // low
|
||||
|
||||
float3 mh = hn.rgb - ho.rgb;
|
||||
float3 mc = cn.rgb - co.rgb;
|
||||
float3 ml = ln.rgb - lo.rgb;
|
||||
|
||||
mh = max(mh, -mh) - motion_thr;
|
||||
mc = max(mc, -mc) - motion_thr;
|
||||
ml = max(ml, -ml) - motion_thr;
|
||||
|
||||
|
||||
// float mh_max = max(max(mh.x, mh.y), mh.z);
|
||||
// float mc_max = max(max(mc.x, mc.y), mc.z);
|
||||
// float ml_max = max(max(ml.x, ml.y), ml.z);
|
||||
|
||||
float mh_max = mh.x + mh.y + mh.z;
|
||||
float mc_max = mc.x + mc.y + mc.z;
|
||||
float ml_max = ml.x + ml.y + ml.z;
|
||||
|
||||
// selecting deinterlacing output
|
||||
|
||||
if (((int(data.p.y) & 1) == field)) // output coordinate present on current field
|
||||
{
|
||||
return res.sample(p_new_cf);
|
||||
}
|
||||
else if ((iptr.y > 0.5f - line_ofs.y) || (iptr.y < 0.0 + line_ofs.y))
|
||||
{
|
||||
return res.sample(p_new_af);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((mh_max > 0.0f) || (ml_max > 0.0f)) || (mc_max > 0.0f))
|
||||
{
|
||||
return (hn + ln) / 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return res.sample(p_new_af);
|
||||
}
|
||||
}
|
||||
|
||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue