mirror of https://github.com/PCSX2/pcsx2.git
gsdx-d3d11: Partial port of frame buffer masking from opengl.
It works on games such as Fifa Street 1 and 2 (character and stage rendering), mission impossible operation surma (shadow rendering). It needs at least Basic level of blending enabled on d3d11.
This commit is contained in:
parent
9d60d6acfd
commit
de5e9a85bb
|
@ -99,6 +99,7 @@ public:
|
|||
GSVector4 MinF_TA;
|
||||
GSVector4i MskFix;
|
||||
GSVector4i ChannelShuffle;
|
||||
GSVector4i FbMask;
|
||||
|
||||
GSVector4 TC_OffsetHack;
|
||||
|
||||
|
@ -111,6 +112,7 @@ public:
|
|||
MinF_TA = GSVector4::zero();
|
||||
MskFix = GSVector4i::zero();
|
||||
ChannelShuffle = GSVector4i::zero();
|
||||
FbMask = GSVector4i::zero();
|
||||
}
|
||||
|
||||
__forceinline bool Update(const PSConstantBuffer* cb)
|
||||
|
@ -118,7 +120,7 @@ public:
|
|||
GSVector4i* a = (GSVector4i*)this;
|
||||
GSVector4i* b = (GSVector4i*)cb;
|
||||
|
||||
if(!((a[0] == b[0]) /*& (a[1] == b1)*/ & (a[2] == b[2]) & (a[3] == b[3]) & (a[4] == b[4]) & (a[5] == b[5]) & (a[6] == b[6])).alltrue()) // if WH matches HalfTexel does too
|
||||
if(!((a[0] == b[0]) /*& (a[1] == b1)*/ & (a[2] == b[2]) & (a[3] == b[3]) & (a[4] == b[4]) & (a[5] == b[5]) & (a[6] == b[6]) & (a[7] == b[7])).alltrue()) // if WH matches HalfTexel does too
|
||||
{
|
||||
a[0] = b[0];
|
||||
a[1] = b[1];
|
||||
|
@ -127,6 +129,7 @@ public:
|
|||
a[4] = b[4];
|
||||
a[5] = b[5];
|
||||
a[6] = b[6];
|
||||
a[7] = b[7];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -201,6 +204,7 @@ public:
|
|||
// Shuffle and fbmask effect
|
||||
uint32 shuffle:1;
|
||||
uint32 read_ba:1;
|
||||
uint32 fbmask:1;
|
||||
|
||||
// *** Word 2
|
||||
// Blend and Colclip
|
||||
|
@ -210,7 +214,6 @@ public:
|
|||
uint32 channel:3;
|
||||
|
||||
// Hack
|
||||
uint32 aout:1;
|
||||
uint32 spritehack:1;
|
||||
uint32 tcoffsethack:1;
|
||||
uint32 urban_chaos_hle:1;
|
||||
|
|
|
@ -26,13 +26,9 @@ GSRendererDX11::GSRendererDX11()
|
|||
: GSRendererHW(new GSTextureCache11(this))
|
||||
{
|
||||
if (theApp.GetConfigB("UserHacks"))
|
||||
{
|
||||
UserHacks_AlphaStencil = theApp.GetConfigB("UserHacks_AlphaStencil");
|
||||
}
|
||||
else
|
||||
{
|
||||
UserHacks_AlphaStencil = false;
|
||||
}
|
||||
|
||||
ResetStates();
|
||||
}
|
||||
|
@ -244,38 +240,71 @@ void GSRendererDX11::EmulateTextureShuffleAndFbmask()
|
|||
if (rg_mask != 0xFF)
|
||||
{
|
||||
if (write_ba)
|
||||
{
|
||||
// fprintf(stderr, "Color shuffle %s => B\n", read_ba ? "B" : "R");
|
||||
m_om_bsel.wb = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// fprintf(stderr, "Color shuffle %s => R"\n, read_ba ? "B" : "R");
|
||||
m_om_bsel.wr = 1;
|
||||
}
|
||||
else if ((fbmask & 0xFF) != 0xFF)
|
||||
{
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
fprintf(stderr, "Please fix me! wb %u wr %u\n", m_om_bsel.wb, m_om_bsel.wr);
|
||||
if (rg_mask)
|
||||
{
|
||||
fprintf(stderr, "ERROR: FBMASK SW emulated fb_mask:%x on RG tex shuffle not supported\n", fbmask);
|
||||
// ASSERT(0);
|
||||
}
|
||||
#endif
|
||||
//ASSERT(0);
|
||||
}
|
||||
|
||||
if (ba_mask != 0xFF)
|
||||
{
|
||||
if (write_ba)
|
||||
{
|
||||
// fprintf(stderr, "Color shuffle %s => A"\n, read_ba ? "A" : "G");
|
||||
m_om_bsel.wa = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// fprintf(stderr, "Color shuffle %s => G"\n, read_ba ? "A" : "G");
|
||||
m_om_bsel.wg = 1;
|
||||
}
|
||||
else if ((fbmask & 0xFF) != 0xFF)
|
||||
{
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
fprintf(stderr, "Please fix me! wa %u wg %u\n", m_om_bsel.wa, m_om_bsel.wg);
|
||||
if (ba_mask)
|
||||
{
|
||||
fprintf(stderr, "ERROR: FBMASK SW emulated fb_mask:%x on BA tex shuffle not supported\n", fbmask);
|
||||
// ASSERT(0);
|
||||
}
|
||||
#endif
|
||||
//ASSERT(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ps_sel.dfmt = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmt;
|
||||
|
||||
m_om_bsel.wrgba = ~GSVector4i::load((int)m_context->FRAME.FBMSK).eq8(GSVector4i::xffffffff()).mask();
|
||||
GSVector4i fbmask_v = GSVector4i::load((int)m_context->FRAME.FBMSK);
|
||||
int ff_fbmask = fbmask_v.eq8(GSVector4i::xffffffff()).mask();
|
||||
int zero_fbmask = fbmask_v.eq8(GSVector4i::zero()).mask();
|
||||
|
||||
m_om_bsel.wrgba = ~ff_fbmask; // Enable channel if at least 1 bit is 0
|
||||
|
||||
m_ps_sel.fbmask = m_sw_blending && (~ff_fbmask & ~zero_fbmask & 0xF);
|
||||
|
||||
if (m_ps_sel.fbmask)
|
||||
{
|
||||
ps_cb.FbMask = fbmask_v.u8to32();
|
||||
// Only alpha is special here, I think we can take a very unsafe shortcut
|
||||
// Alpha isn't blended on the GS but directly copyied into the RT.
|
||||
//
|
||||
// Behavior is clearly undefined however there is a high probability that
|
||||
// it will work. Masked bit will be constant and normally the same everywhere
|
||||
// RT/FS output/Cached value.
|
||||
|
||||
/*fprintf(stderr, "FBMASK SW emulated alpha fb_mask:%x on %d bits format\n", m_context->FRAME.FBMSK,
|
||||
(GSLocalMemory::m_psm[m_context->FRAME.PSM].fmt == 2) ? 16 : 32);*/
|
||||
m_bind_rtsample = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -621,6 +650,8 @@ void GSRendererDX11::EmulateTextureSampler(const GSTextureCache::Source* tex)
|
|||
|
||||
void GSRendererDX11::ResetStates()
|
||||
{
|
||||
m_bind_rtsample = false;
|
||||
|
||||
m_vs_sel.key = 0;
|
||||
m_gs_sel.key = 0;
|
||||
m_ps_sel.key = 0;
|
||||
|
@ -912,6 +943,15 @@ void GSRendererDX11::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sou
|
|||
m_ps_sel.tfx = 4;
|
||||
}
|
||||
|
||||
if (m_bind_rtsample)
|
||||
{
|
||||
// Bind the RT.This way special effect can use it.
|
||||
// Do not always bind the rt when it's not needed,
|
||||
// only bind it when effects use it such as fbmask emulation currently
|
||||
// because we copy the frame buffer and it is quite slow.
|
||||
dev->PSSetShaderResource(3, rt);
|
||||
}
|
||||
|
||||
if (m_game.title == CRC::ICO)
|
||||
{
|
||||
GSVertex* v = &m_vertex.buff[0];
|
||||
|
|
|
@ -29,6 +29,7 @@ class GSRendererDX11 final : public GSRendererHW
|
|||
{
|
||||
private:
|
||||
bool UserHacks_AlphaStencil;
|
||||
bool m_bind_rtsample;
|
||||
|
||||
private:
|
||||
inline void ResetStates();
|
||||
|
|
|
@ -220,7 +220,7 @@ void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSe
|
|||
str[8] = format("%d", sel.fog);
|
||||
str[9] = format("%d", sel.clr1);
|
||||
str[10] = format("%d", sel.fba);
|
||||
str[11] = format("%d", sel.aout);
|
||||
str[11] = format("%d", sel.fbmask);
|
||||
str[12] = format("%d", sel.ltf);
|
||||
str[13] = format("%d", sel.spritehack);
|
||||
str[14] = format("%d", sel.tcoffsethack);
|
||||
|
@ -249,7 +249,7 @@ void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSe
|
|||
{"PS_FOG", str[8].c_str()},
|
||||
{"PS_CLR1", str[9].c_str()},
|
||||
{"PS_FBA", str[10].c_str()},
|
||||
{"PS_AOUT", str[11].c_str()},
|
||||
{"PS_FBMASK", str[11].c_str()},
|
||||
{"PS_LTF", str[12].c_str()},
|
||||
{"PS_SPRITEHACK", str[13].c_str()},
|
||||
{"PS_TCOFFSETHACK", str[14].c_str()},
|
||||
|
|
|
@ -40,6 +40,7 @@ GSRendererHW::GSRendererHW(GSTextureCache* tc)
|
|||
m_upscale_multiplier = theApp.GetConfigI("upscale_multiplier");
|
||||
m_large_framebuffer = theApp.GetConfigB("large_framebuffer");
|
||||
m_accurate_date = theApp.GetConfigI("accurate_date");
|
||||
m_sw_blending = theApp.GetConfigI("accurate_blending_unit");
|
||||
if (theApp.GetConfigB("UserHacks")) {
|
||||
m_userhacks_enabled_gs_mem_clear = !theApp.GetConfigB("UserHacks_Disable_Safe_Features");
|
||||
m_userHacks_enabled_unscale_ptln = !theApp.GetConfigB("UserHacks_Disable_Safe_Features");
|
||||
|
|
|
@ -151,6 +151,7 @@ protected:
|
|||
float m_userhacks_tcoffset_y;
|
||||
|
||||
int m_accurate_date;
|
||||
int m_sw_blending;
|
||||
|
||||
bool m_channel_shuffle;
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
GSRendererOGL::GSRendererOGL()
|
||||
: GSRendererHW(new GSTextureCacheOGL(this))
|
||||
{
|
||||
m_sw_blending = theApp.GetConfigI("accurate_blending_unit");
|
||||
if (theApp.GetConfigB("UserHacks"))
|
||||
UserHacks_tri_filter = static_cast<TriFiltering>(theApp.GetConfigI("UserHacks_TriFilter"));
|
||||
else
|
||||
|
|
|
@ -49,7 +49,6 @@ class GSRendererOGL final : public GSRendererHW
|
|||
};
|
||||
|
||||
private:
|
||||
int m_sw_blending;
|
||||
PRIM_OVERLAP m_prim_overlap;
|
||||
std::vector<size_t> m_drawlist;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#define PS_FOG 0
|
||||
#define PS_CLR1 0
|
||||
#define PS_FBA 0
|
||||
#define PS_AOUT 0
|
||||
#define PS_FBMASK 0
|
||||
#define PS_LTF 1
|
||||
#define PS_SPRITEHACK 0
|
||||
#define PS_TCOFFSETHACK 0
|
||||
|
@ -81,6 +81,7 @@ struct PS_OUTPUT
|
|||
|
||||
Texture2D<float4> Texture : register(t0);
|
||||
Texture2D<float4> Palette : register(t1);
|
||||
Texture2D<float4> RtSample : register(t3);
|
||||
Texture2D<float4> RawTexture : register(t4);
|
||||
SamplerState TextureSampler : register(s0);
|
||||
SamplerState PaletteSampler : register(s1);
|
||||
|
@ -103,6 +104,7 @@ cbuffer cb1
|
|||
float2 TA;
|
||||
uint4 MskFix;
|
||||
int4 ChannelShuffle;
|
||||
uint4 FbMask;
|
||||
float4 TC_OffsetHack;
|
||||
};
|
||||
|
||||
|
@ -902,9 +904,10 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
|||
}
|
||||
}
|
||||
|
||||
output.c1 = c.a * 255.0f / 128.0f; // used for alpha blending
|
||||
// Must be done before alpha correction
|
||||
float alpha_blend = c.a * 255.0f / 128.0f;
|
||||
|
||||
if ((PS_DFMT == FMT_16) || PS_AOUT) // 16 bit output
|
||||
if (PS_DFMT == FMT_16) // 16 bit output
|
||||
{
|
||||
float a = 128.0f / 255; // alpha output will be 0x80
|
||||
|
||||
|
@ -915,7 +918,16 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
|||
if (c.a < 128.0f / 255.0f) c.a += 128.0f / 255.0f;
|
||||
}
|
||||
|
||||
if (PS_FBMASK)
|
||||
{
|
||||
float4 rt = RtSample.Load(int3(input.p.xy, 0));
|
||||
uint4 denorm_rt = uint4(rt * 255.0f + 0.5f);
|
||||
uint4 denorm_c = uint4(c * 255.0f + 0.5f);
|
||||
c = float4((denorm_c & ~FbMask) | (denorm_rt & FbMask)) / 255.0f;
|
||||
}
|
||||
|
||||
output.c0 = c;
|
||||
output.c1 = (float4)(alpha_blend);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue