mirror of https://github.com/PCSX2/pcsx2.git
GS: Implemented Motion Adaptive Deinterlacing for all renderers
implemented FastMAD motion-adaptive deinterlacing for OpenGL renderer, other renderers will crash. FastMAD is replacing blend (either mode) so select blend to activate MAD under the hood fixed an assert and assessed that one MUST select mode Blend bottom field first to enable MAD removed forced mode 2, added separate motion thresholds for current field and alternate field motion and optimized MAD for Top-FIeld-First mode committing kind-of broken status for review the algorithm works well on most games, but somehow Kingdom Hearts works at half resolution completely fixed weird artifacts on MAD, I only need to fix a 1-line offset that is causing the top of the screen to flicker fixed flicker on first line, I still need to fine-tune some coefficients solved all nastiness by realizing that MAD MUST work on an even resolution, so odd resolutions are rounded up. Now all games I tried look great made MAD sensitivity adjustable inside GDDevice.h and passed to shaders as a parameters. For this purpose ZrH is now a vec4 to hold more parameters conveniently ported MAD to DX11 and DX12 removed rounding of texture size to closest multiple of 2 and fized odd number of lines inside the shaders by also passing the vertical resolution as a parameter improved compatibility of upper buffer offset adjustment for odd resolutions added Vulkan support
This commit is contained in:
parent
e1f7fe5700
commit
f10e7f4ab7
|
@ -5,7 +5,7 @@ SamplerState Sampler;
|
|||
|
||||
cbuffer cb0
|
||||
{
|
||||
float2 ZrH;
|
||||
float4 ZrH;
|
||||
};
|
||||
|
||||
struct PS_INPUT
|
||||
|
@ -32,9 +32,10 @@ float4 ps_main1(PS_INPUT input) : SV_Target0
|
|||
|
||||
float4 ps_main2(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
float4 c0 = Texture.Sample(Sampler, input.t - ZrH);
|
||||
float2 vstep = float2(0.0f, ZrH.y);
|
||||
float4 c0 = Texture.Sample(Sampler, input.t - vstep);
|
||||
float4 c1 = Texture.Sample(Sampler, input.t);
|
||||
float4 c2 = Texture.Sample(Sampler, input.t + ZrH);
|
||||
float4 c2 = Texture.Sample(Sampler, input.t + vstep);
|
||||
|
||||
return (c0 + c1 * 2 + c2) / 4;
|
||||
}
|
||||
|
@ -43,4 +44,128 @@ float4 ps_main3(PS_INPUT input) : SV_Target0
|
|||
{
|
||||
return Texture.Sample(Sampler, input.t);
|
||||
}
|
||||
|
||||
|
||||
float4 ps_main4(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
const int vres = int(round(ZrH.z));
|
||||
const int idx = int(round(ZrH.x));
|
||||
const int bank = idx >> 1;
|
||||
const int field = idx & 1;
|
||||
const int vpos = int(input.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 = input.t - bofs;
|
||||
const float2 iptr = optr * vscale;
|
||||
|
||||
if ((optr.y >= 0.0f) && (optr.y < 0.5f) && ((vpos & 1) == field))
|
||||
return Texture.Sample(Sampler, iptr);
|
||||
else
|
||||
discard;
|
||||
|
||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
}
|
||||
|
||||
|
||||
float4 ps_main5(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
const float sensitivity = 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(ZrH.x));
|
||||
const int bank = idx >> 1;
|
||||
const int field = idx & 1;
|
||||
const float2 line_ofs = float2(0.0f, ZrH.y);
|
||||
const float2 iptr = input.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 = Texture.Sample(Sampler, p_new_cf - line_ofs); // high
|
||||
float4 cn = Texture.Sample(Sampler, p_new_af); // center
|
||||
float4 ln = Texture.Sample(Sampler, p_new_cf + line_ofs); // low
|
||||
|
||||
float4 ho = Texture.Sample(Sampler, p_old_cf - line_ofs); // high
|
||||
float4 co = Texture.Sample(Sampler, p_old_af); // center
|
||||
float4 lo = Texture.Sample(Sampler, 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(input.p.y) & 1) == field)) // output coordinate present on current field
|
||||
{
|
||||
return Texture.Sample(Sampler, p_new_cf);
|
||||
}
|
||||
else if ((iptr.y > 0.5f - line_ofs.y) || (iptr.y < 0.0 + line_ofs.y))
|
||||
{
|
||||
return Texture.Sample(Sampler, p_new_af);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((mh_max > 0.0f) || (ml_max > 0.0f)) || (mc_max > 0.0f))
|
||||
{
|
||||
return (hn + ln) / 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Texture.Sample(Sampler, p_new_af);
|
||||
}
|
||||
}
|
||||
|
||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,7 +6,7 @@ in vec4 PSin_p;
|
|||
in vec2 PSin_t;
|
||||
in vec4 PSin_c;
|
||||
|
||||
uniform vec2 ZrH;
|
||||
uniform vec4 ZrH;
|
||||
|
||||
layout(location = 0) out vec4 SV_Target0;
|
||||
|
||||
|
@ -35,9 +35,10 @@ void ps_main1()
|
|||
|
||||
void ps_main2()
|
||||
{
|
||||
vec4 c0 = texture(TextureSampler, PSin_t - ZrH);
|
||||
vec2 vstep = vec2(0.0f, ZrH.y);
|
||||
vec4 c0 = texture(TextureSampler, PSin_t - vstep);
|
||||
vec4 c1 = texture(TextureSampler, PSin_t);
|
||||
vec4 c2 = texture(TextureSampler, PSin_t + ZrH);
|
||||
vec4 c2 = texture(TextureSampler, PSin_t + vstep);
|
||||
|
||||
SV_Target0 = (c0 + c1 * 2.0f + c2) / 4.0f;
|
||||
}
|
||||
|
@ -47,4 +48,122 @@ void ps_main3()
|
|||
SV_Target0 = texture(TextureSampler, PSin_t);
|
||||
}
|
||||
|
||||
|
||||
void ps_main4()
|
||||
{
|
||||
const int vres = int(round(ZrH.z));
|
||||
const int idx = int(round(ZrH.x));
|
||||
const int bank = idx >> 1;
|
||||
const int field = idx & 1;
|
||||
const int vpos = int(gl_FragCoord.y) + (((((vres + 1) >> 1) << 1) - vres) & bank);
|
||||
const vec2 bofs = vec2(0.0f, 0.5f * bank);
|
||||
const vec2 vscale = vec2(1.0f, 2.0f);
|
||||
const vec2 optr = PSin_t - bofs;
|
||||
const vec2 iptr = optr * vscale;
|
||||
|
||||
if ((optr.y >= 0.0f) && (optr.y < 0.5f) && ((vpos & 1) == field))
|
||||
//if ((optr.y >= 0.0f) && (optr.y < 0.5f) && (int(iptr.y * vres) & 1) == field)
|
||||
SV_Target0 = texture(TextureSampler, iptr);
|
||||
else
|
||||
discard;
|
||||
}
|
||||
|
||||
|
||||
void ps_main5()
|
||||
{
|
||||
const float sensitivity = ZrH.w;
|
||||
const vec3 motion_thr = vec3(1.0, 1.0, 1.0) * sensitivity;
|
||||
const vec2 vofs = vec2(0.0f, 0.5f);
|
||||
const vec2 vscale = vec2(1.0f, 0.5f);
|
||||
const int idx = int(round(ZrH.x));
|
||||
const int bank = idx >> 1;
|
||||
const int field = idx & 1;
|
||||
const vec2 line_ofs = vec2(0.0f, ZrH.y);
|
||||
const vec2 iptr = PSin_t * vscale;
|
||||
|
||||
vec2 p_new_cf;
|
||||
vec2 p_old_cf;
|
||||
vec2 p_new_af;
|
||||
vec2 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
|
||||
|
||||
vec4 hn = texture(TextureSampler, p_new_cf - line_ofs); // high
|
||||
vec4 cn = texture(TextureSampler, p_new_af); // center
|
||||
vec4 ln = texture(TextureSampler, p_new_cf + line_ofs); // low
|
||||
|
||||
vec4 ho = texture(TextureSampler, p_old_cf - line_ofs); // high
|
||||
vec4 co = texture(TextureSampler, p_old_af); // center
|
||||
vec4 lo = texture(TextureSampler, p_old_cf + line_ofs); // low
|
||||
|
||||
vec3 mh = hn.rgb - ho.rgb;
|
||||
vec3 mc = cn.rgb - co.rgb;
|
||||
vec3 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(gl_FragCoord.y) & 1) == field)) // output coordinate present on current field
|
||||
{
|
||||
SV_Target0 = texture(TextureSampler, p_new_cf);
|
||||
|
||||
}
|
||||
else if ((iptr.y > 0.5f - line_ofs.y) || (iptr.y < 0.0 + line_ofs.y))
|
||||
{
|
||||
SV_Target0 = texture(TextureSampler, p_new_af);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(((mh_max > 0.0f) || (ml_max > 0.0f)) || (mc_max > 0.0f))
|
||||
{
|
||||
SV_Target0 = (hn + ln) / 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
SV_Target0 = texture(TextureSampler, p_new_af);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,7 @@ layout(location = 0) out vec4 o_col0;
|
|||
|
||||
layout(push_constant) uniform cb0
|
||||
{
|
||||
vec2 ZrH;
|
||||
vec4 ZrH;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D samp0;
|
||||
|
@ -46,9 +46,10 @@ void ps_main1()
|
|||
#ifdef ps_main2
|
||||
void ps_main2()
|
||||
{
|
||||
vec4 c0 = texture(samp0, v_tex - ZrH);
|
||||
vec2 vstep = vec2(0.0f, ZrH.y);
|
||||
vec4 c0 = texture(samp0, v_tex - vstep);
|
||||
vec4 c1 = texture(samp0, v_tex);
|
||||
vec4 c2 = texture(samp0, v_tex + ZrH);
|
||||
vec4 c2 = texture(samp0, v_tex + vstep);
|
||||
|
||||
o_col0 = (c0 + c1 * 2.0f + c2) / 4.0f;
|
||||
}
|
||||
|
@ -61,4 +62,127 @@ void ps_main3()
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ps_main4
|
||||
void ps_main4()
|
||||
{
|
||||
const int vres = int(round(ZrH.z));
|
||||
const int idx = int(round(ZrH.x));
|
||||
const int bank = idx >> 1;
|
||||
const int field = idx & 1;
|
||||
const int vpos = int(gl_FragCoord.y) + (((((vres + 1) >> 1) << 1) - vres) & bank);
|
||||
const vec2 bofs = vec2(0.0f, 0.5f * bank);
|
||||
const vec2 vscale = vec2(1.0f, 2.0f);
|
||||
const vec2 optr = v_tex - bofs;
|
||||
const vec2 iptr = optr * vscale;
|
||||
|
||||
if ((optr.y >= 0.0f) && (optr.y < 0.5f) && ((vpos & 1) == field))
|
||||
o_col0 = texture(samp0, iptr);
|
||||
else
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ps_main5
|
||||
void ps_main5()
|
||||
{
|
||||
const float sensitivity = ZrH.w;
|
||||
const vec3 motion_thr = vec3(1.0, 1.0, 1.0) * sensitivity;
|
||||
const vec2 vofs = vec2(0.0f, 0.5f);
|
||||
const vec2 vscale = vec2(1.0f, 0.5f);
|
||||
|
||||
int idx = int(round(ZrH.x));
|
||||
int bank = idx >> 1;
|
||||
int field = idx & 1;
|
||||
vec2 line_ofs = vec2(0.0f, ZrH.y);
|
||||
|
||||
vec2 iptr = v_tex * vscale;
|
||||
vec2 p_new_cf = vec2(0.0f, 0.0f);
|
||||
vec2 p_old_cf = vec2(0.0f, 0.0f);
|
||||
vec2 p_new_af = vec2(0.0f, 0.0f);
|
||||
vec2 p_old_af = vec2(0.0f, 0.0f);
|
||||
|
||||
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
|
||||
|
||||
vec4 hn = texture(samp0, p_new_cf - line_ofs); // high
|
||||
vec4 cn = texture(samp0, p_new_af); // center
|
||||
vec4 ln = texture(samp0, p_new_cf + line_ofs); // low
|
||||
|
||||
vec4 ho = texture(samp0, p_old_cf - line_ofs); // high
|
||||
vec4 co = texture(samp0, p_old_af); // center
|
||||
vec4 lo = texture(samp0, p_old_cf + line_ofs); // low
|
||||
|
||||
vec3 mh = hn.rgb - ho.rgb;
|
||||
vec3 mc = cn.rgb - co.rgb;
|
||||
vec3 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(gl_FragCoord.y) & 1) == field)) // output coordinate present on current field
|
||||
{
|
||||
o_col0 = texture(samp0, p_new_cf);
|
||||
|
||||
}
|
||||
else if ((iptr.y > 0.5f - line_ofs.y) || (iptr.y < 0.0 + line_ofs.y))
|
||||
{
|
||||
o_col0 = texture(samp0, p_new_af);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(((mh_max > 0.0f) || (ml_max > 0.0f)) || (mc_max > 0.0f))
|
||||
{
|
||||
o_col0 = (hn + ln) / 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
o_col0 = texture(samp0, p_new_af);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -86,6 +86,7 @@ GSDevice::~GSDevice()
|
|||
delete m_merge;
|
||||
delete m_weavebob;
|
||||
delete m_blend;
|
||||
delete m_mad;
|
||||
delete m_target_tmp;
|
||||
}
|
||||
|
||||
|
@ -101,11 +102,13 @@ void GSDevice::Destroy()
|
|||
delete m_merge;
|
||||
delete m_weavebob;
|
||||
delete m_blend;
|
||||
delete m_mad;
|
||||
delete m_target_tmp;
|
||||
|
||||
m_merge = nullptr;
|
||||
m_weavebob = nullptr;
|
||||
m_blend = nullptr;
|
||||
m_mad = nullptr;
|
||||
m_target_tmp = nullptr;
|
||||
|
||||
m_current = nullptr; // current is special, points to other textures, no need to delete
|
||||
|
@ -312,11 +315,13 @@ void GSDevice::ClearCurrent()
|
|||
delete m_merge;
|
||||
delete m_weavebob;
|
||||
delete m_blend;
|
||||
delete m_mad;
|
||||
delete m_target_tmp;
|
||||
|
||||
m_merge = nullptr;
|
||||
m_weavebob = nullptr;
|
||||
m_blend = nullptr;
|
||||
m_mad = nullptr;
|
||||
m_target_tmp = nullptr;
|
||||
}
|
||||
|
||||
|
@ -358,37 +363,40 @@ void GSDevice::Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, con
|
|||
|
||||
void GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffset)
|
||||
{
|
||||
ResizeTarget(&m_weavebob, ds.x, ds.y);
|
||||
static int bufIdx = 0;
|
||||
|
||||
if (mode == 0 || mode == 2) // weave or blend
|
||||
if (mode == 0) // weave
|
||||
{
|
||||
// weave first
|
||||
const float offset = yoffset * static_cast<float>(field);
|
||||
|
||||
DoInterlace(m_merge, m_weavebob, field, false, GSConfig.DisableInterlaceOffset ? 0.0f : offset);
|
||||
|
||||
if (mode == 2)
|
||||
{
|
||||
// blend
|
||||
|
||||
ResizeTarget(&m_blend, ds.x, ds.y);
|
||||
|
||||
DoInterlace(m_weavebob, m_blend, 2, false, 0);
|
||||
|
||||
m_current = m_blend;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResizeTarget(&m_weavebob, ds.x, ds.y);
|
||||
DoInterlace(m_merge, m_weavebob, field, false, GSConfig.DisableInterlaceOffset ? 0.0f : offset, 0);
|
||||
m_current = m_weavebob;
|
||||
}
|
||||
}
|
||||
else if (mode == 1) // bob
|
||||
{
|
||||
// Field is reversed here as we are countering the bounce.
|
||||
DoInterlace(m_merge, m_weavebob, 3, true, yoffset * (1-field));
|
||||
|
||||
ResizeTarget(&m_weavebob, ds.x, ds.y);
|
||||
DoInterlace(m_merge, m_weavebob, 3, true, yoffset * (1-field), 0);
|
||||
m_current = m_weavebob;
|
||||
}
|
||||
else if (mode == 2) // FastMAD Motion Adaptive Deinterlacing
|
||||
{
|
||||
bufIdx++;
|
||||
bufIdx &= ~(field ^ 1);
|
||||
bufIdx |= (field);
|
||||
bufIdx &= 3;
|
||||
|
||||
float offset = (yoffset * field);
|
||||
offset = GSConfig.DisableInterlaceOffset ? 0.0f : offset;
|
||||
|
||||
ResizeTarget(&m_mad, ds.x, ds.y * 2.0f);
|
||||
DoInterlace(m_merge, m_mad, 4, false, offset, bufIdx);
|
||||
ResizeTarget(&m_blend, ds.x, ds.y);
|
||||
DoInterlace(m_mad, m_blend, 5, false, 0, bufIdx);
|
||||
|
||||
|
||||
m_current = m_blend;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_current = m_merge;
|
||||
|
|
|
@ -191,9 +191,7 @@ public:
|
|||
class InterlaceConstantBuffer
|
||||
{
|
||||
public:
|
||||
GSVector2 ZrH;
|
||||
float _pad[2];
|
||||
|
||||
GSVector4 ZrH; // data passed to the shader
|
||||
InterlaceConstantBuffer() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
|
@ -739,11 +737,14 @@ private:
|
|||
static const std::array<u8, 16> m_replaceDualSrcBlendMap;
|
||||
|
||||
protected:
|
||||
static constexpr int NUM_INTERLACE_SHADERS = 6;
|
||||
static constexpr float MAD_SENSITIVITY = 0.08f;
|
||||
static constexpr u32 MAX_POOLED_TEXTURES = 300;
|
||||
|
||||
GSTexture* m_merge = nullptr;
|
||||
GSTexture* m_weavebob = nullptr;
|
||||
GSTexture* m_blend = nullptr;
|
||||
GSTexture* m_mad = nullptr;
|
||||
GSTexture* m_target_tmp = nullptr;
|
||||
GSTexture* m_current = nullptr;
|
||||
struct
|
||||
|
@ -762,7 +763,7 @@ protected:
|
|||
GSTexture* FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_reuse);
|
||||
|
||||
virtual void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) = 0;
|
||||
virtual void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset) = 0;
|
||||
virtual void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset, int bufIdx) = 0;
|
||||
virtual void DoFXAA(GSTexture* sTex, GSTexture* dTex) {}
|
||||
virtual void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) {}
|
||||
virtual void DoExternalFX(GSTexture* sTex, GSTexture* dTex) {}
|
||||
|
|
|
@ -823,16 +823,17 @@ void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
|||
}
|
||||
}
|
||||
|
||||
void GSDevice11::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset)
|
||||
void GSDevice11::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset, int bufIdx)
|
||||
{
|
||||
const GSVector4 s = GSVector4(dTex->GetSize());
|
||||
const GSVector4 ss = GSVector4(sTex->GetSize());
|
||||
const GSVector4 ds = GSVector4(dTex->GetSize());
|
||||
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0.0f, yoffset, s.x, s.y + yoffset);
|
||||
const GSVector4 dRect(0.0f, yoffset, ds.x, ds.y + yoffset);
|
||||
|
||||
InterlaceConstantBuffer cb;
|
||||
|
||||
cb.ZrH = GSVector2(0, 1.0f / s.y);
|
||||
cb.ZrH = GSVector4(static_cast<float>(bufIdx), 1.0f / ss.y, ss.y, MAD_SENSITIVITY);
|
||||
|
||||
m_ctx->UpdateSubresource(m_interlace.cb.get(), 0, nullptr, &cb, 0, 0);
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ private:
|
|||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) final;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final;
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0, int bufIdx = 0) final;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
||||
void DoExternalFX(GSTexture* sTex, GSTexture* dTex) final;
|
||||
|
@ -185,7 +185,7 @@ private:
|
|||
|
||||
struct
|
||||
{
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> ps[4];
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> ps[NUM_INTERLACE_SHADERS];
|
||||
wil::com_ptr_nothrow<ID3D11Buffer> cb;
|
||||
} m_interlace;
|
||||
|
||||
|
|
|
@ -720,22 +720,24 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
|||
static_cast<GSTexture12*>(dTex)->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
}
|
||||
|
||||
void GSDevice12::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset)
|
||||
void GSDevice12::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset, int bufIdx)
|
||||
{
|
||||
const GSVector2i size(dTex->GetSize());
|
||||
const GSVector4 s = GSVector4(size);
|
||||
const GSVector4 ss = GSVector4(sTex->GetSize());
|
||||
const GSVector4 ds = GSVector4(dTex->GetSize());
|
||||
const GSVector2i ds_i(dTex->GetSize());
|
||||
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0.0f, yoffset, s.x, s.y + yoffset);
|
||||
const GSVector4 dRect(0.0f, yoffset, ds.x, ds.y + yoffset);
|
||||
|
||||
InterlaceConstantBuffer cb;
|
||||
cb.ZrH = GSVector2(0, 1.0f / s.y);
|
||||
|
||||
cb.ZrH = GSVector4(static_cast<float>(bufIdx), 1.0f / ss.y, ss.y, MAD_SENSITIVITY);
|
||||
|
||||
GL_PUSH("DoInterlace %dx%d Shader:%d Linear:%d", size.x, size.y, shader, linear);
|
||||
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
|
||||
const GSVector4i rc(0, 0, size.x, size.y);
|
||||
const GSVector4i rc(0, 0, ds_i.x, ds_i.y);
|
||||
EndRenderPass();
|
||||
OMSetRenderTargets(dTex, nullptr, rc);
|
||||
SetUtilityRootSignature();
|
||||
|
|
|
@ -156,7 +156,7 @@ private:
|
|||
std::array<ComPtr<ID3D12PipelineState>, static_cast<int>(PresentShader::Count)> m_present{};
|
||||
std::array<ComPtr<ID3D12PipelineState>, 16> m_color_copy{};
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2> m_merge{};
|
||||
std::array<ComPtr<ID3D12PipelineState>, 4> m_interlace{};
|
||||
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]
|
||||
|
@ -181,7 +181,7 @@ private:
|
|||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
|
||||
const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final;
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0, int bufIdx = 0) final;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ private:
|
|||
GSTexture* CreateSurface(GSTexture::Type type, int w, int h, GSTexture::Format format);
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) {}
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) {}
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0, int bufIdx = 0) {}
|
||||
u16 ConvertBlendEnum(u16 generic) { return 0xFFFF; }
|
||||
|
||||
public:
|
||||
|
|
|
@ -1385,19 +1385,20 @@ void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
|||
StretchRect(dTex, full_r, sTex[2], dRect[2], ShaderConvert::YUV);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset)
|
||||
void GSDeviceOGL::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset, int bufIdx)
|
||||
{
|
||||
GL_PUSH("DoInterlace");
|
||||
|
||||
OMSetColorMaskState();
|
||||
|
||||
const GSVector4 s = GSVector4(dTex->GetSize());
|
||||
const GSVector4 ss = GSVector4(sTex->GetSize());
|
||||
const GSVector4 ds = GSVector4(dTex->GetSize());
|
||||
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0.0f, yoffset, s.x, s.y + yoffset);
|
||||
const GSVector4 dRect(0.0f, yoffset, ds.x, ds.y + yoffset);
|
||||
|
||||
m_interlace.ps[shader].Bind();
|
||||
m_interlace.ps[shader].Uniform2f(0, 0, 1.0f / s.y);
|
||||
m_interlace.ps[shader].Uniform4f(0, bufIdx, 1.0f / ss.y, ss.y, MAD_SENSITIVITY);
|
||||
|
||||
StretchRect(sTex, sRect, dTex, dRect, m_interlace.ps[shader], linear);
|
||||
}
|
||||
|
|
|
@ -239,7 +239,7 @@ private:
|
|||
|
||||
struct
|
||||
{
|
||||
GL::Program ps[4]; // program object
|
||||
GL::Program ps[NUM_INTERLACE_SHADERS]; // program object
|
||||
} m_interlace;
|
||||
|
||||
struct
|
||||
|
@ -300,7 +300,7 @@ private:
|
|||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) final;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final;
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0, int bufIdx = 0) final;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
||||
void DoExternalFX(GSTexture* sTex, GSTexture* dTex) final;
|
||||
|
|
|
@ -855,22 +855,24 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
|||
static_cast<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
|
||||
void GSDeviceVK::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset)
|
||||
void GSDeviceVK::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset, int bufIdx)
|
||||
{
|
||||
const GSVector2i size(dTex->GetSize());
|
||||
const GSVector4 s = GSVector4(size);
|
||||
const GSVector4 ss = GSVector4(sTex->GetSize());
|
||||
const GSVector4 ds = GSVector4(dTex->GetSize());
|
||||
const GSVector2i ds_i(dTex->GetSize());
|
||||
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0.0f, yoffset, s.x, s.y + yoffset);
|
||||
const GSVector4 dRect(0.0f, yoffset, ds.x, ds.y + yoffset);
|
||||
|
||||
InterlaceConstantBuffer cb;
|
||||
cb.ZrH = GSVector2(0, 1.0f / s.y);
|
||||
|
||||
cb.ZrH = GSVector4(static_cast<float>(bufIdx), 1.0f / ss.y, ss.y, MAD_SENSITIVITY);
|
||||
|
||||
GL_PUSH("DoInterlace %dx%d Shader:%d Linear:%d", size.x, size.y, shader, linear);
|
||||
|
||||
static_cast<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
const GSVector4i rc(0, 0, size.x, size.y);
|
||||
const GSVector4i rc(0, 0, ds_i.x, ds_i.y);
|
||||
EndRenderPass();
|
||||
OMSetRenderTargets(dTex, nullptr, rc, false);
|
||||
SetUtilityTexture(sTex, linear ? m_linear_sampler : m_point_sampler);
|
||||
|
|
|
@ -120,7 +120,7 @@ private:
|
|||
std::array<VkPipeline, static_cast<int>(PresentShader::Count)> m_present{};
|
||||
std::array<VkPipeline, 16> m_color_copy{};
|
||||
std::array<VkPipeline, 2> m_merge{};
|
||||
std::array<VkPipeline, 4> m_interlace{};
|
||||
std::array<VkPipeline, NUM_INTERLACE_SHADERS> m_interlace{};
|
||||
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]
|
||||
|
@ -155,7 +155,7 @@ private:
|
|||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
|
||||
const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final;
|
||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0, int bufIdx = 0) final;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
|
||||
|
||||
|
|
Loading…
Reference in New Issue