mirror of https://github.com/PCSX2/pcsx2.git
GSdx-d3d: Add support for channel shuffle in GSRendererDX.
Split the code from GSRendererDX to GSRendererDX9 and GSRendererDX11. We ensure d3d9 doesn't blow up with regressions, add required code to GSRendererDX11 to properly support channel shuffle. Note the feature is still not yet complete, copy function needs to be implemented (suggested by Gregory) but it can be done at a later date, this still fixes a bunch of issues on various games.
This commit is contained in:
parent
c7aca64642
commit
c511ce80d2
|
@ -174,6 +174,145 @@ void GSRendererDX11::EmulateTextureShuffleAndFbmask()
|
|||
}
|
||||
}
|
||||
|
||||
void GSRendererDX11::EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex)
|
||||
{
|
||||
// Uncomment to disable HLE emulation (allow to trace the draw call)
|
||||
// m_channel_shuffle = false;
|
||||
|
||||
// First let's check we really have a channel shuffle effect
|
||||
if (m_channel_shuffle)
|
||||
{
|
||||
if (m_game.title == CRC::Tekken5)
|
||||
{
|
||||
if (m_context->FRAME.FBW == 1)
|
||||
{
|
||||
// Used in stages: Secret Garden, Acid Rain, Moonlit Wilderness
|
||||
// fprintf(stderr, "Tekken5 RGB Channel\n");
|
||||
// m_ps_sel.channel = ChannelFetch_RGB;
|
||||
// m_context->FRAME.FBMSK = 0xFF000000;
|
||||
// 12 pages: 2 calls by channel, 3 channels, 1 blit
|
||||
// Minus current draw call
|
||||
m_skip = 12 * (3 + 3 + 1) - 1;
|
||||
// *rt = tex->m_from_target;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Could skip model drawing if wrongly detected
|
||||
m_channel_shuffle = false;
|
||||
}
|
||||
}
|
||||
else if ((tex->m_texture->GetType() == GSTexture::DepthStencil) && !(tex->m_32_bits_fmt))
|
||||
{
|
||||
// So far 2 games hit this code path. Urban Chaos and Tales of Abyss.
|
||||
// Lacks shader like usual but maybe we can still use it to skip some bad draw calls.
|
||||
// fprintf(stderr, "Tales Of Abyss Crazyness/Urban Chaos channel not supported\n");
|
||||
throw GSDXRecoverableError();
|
||||
}
|
||||
else if (m_index.tail <= 64 && m_context->CLAMP.WMT == 3)
|
||||
{
|
||||
// Blood will tell. I think it is channel effect too but again
|
||||
// implemented in a different way. I don't want to add more CRC stuff. So
|
||||
// let's disable channel when the signature is different.
|
||||
//
|
||||
// Note: Tales Of Abyss and Tekken5 could hit this path too. Those games are
|
||||
// handled above.
|
||||
// fprintf(stderr, "Maybe not a channel!\n");
|
||||
m_channel_shuffle = false;
|
||||
}
|
||||
else if (m_context->CLAMP.WMS == 3 && ((m_context->CLAMP.MAXU & 0x8) == 8))
|
||||
{
|
||||
// Read either blue or Alpha. Let's go for Blue ;)
|
||||
// MGS3/Kill Zone
|
||||
// fprintf(stderr, "Blue channel\n");
|
||||
m_ps_sel.channel = ChannelFetch_BLUE;
|
||||
}
|
||||
else if (m_context->CLAMP.WMS == 3 && ((m_context->CLAMP.MINU & 0x8) == 0))
|
||||
{
|
||||
// Read either Red or Green. Let's check the V coordinate. 0-1 is likely top so
|
||||
// red. 2-3 is likely bottom so green (actually depends on texture base pointer offset)
|
||||
bool green = PRIM->FST && (m_vertex.buff[0].V & 32);
|
||||
if (green && (m_context->FRAME.FBMSK & 0x00FFFFFF) == 0x00FFFFFF)
|
||||
{
|
||||
// Typically used in Terminator 3
|
||||
int blue_mask = m_context->FRAME.FBMSK >> 24;
|
||||
int green_mask = ~blue_mask & 0xFF;
|
||||
int blue_shift = -1;
|
||||
|
||||
// Note: potentially we could also check the value of the clut
|
||||
switch (m_context->FRAME.FBMSK >> 24)
|
||||
{
|
||||
case 0xFF: ASSERT(0); break;
|
||||
case 0xFE: blue_shift = 1; break;
|
||||
case 0xFC: blue_shift = 2; break;
|
||||
case 0xF8: blue_shift = 3; break;
|
||||
case 0xF0: blue_shift = 4; break;
|
||||
case 0xE0: blue_shift = 5; break;
|
||||
case 0xC0: blue_shift = 6; break;
|
||||
case 0x80: blue_shift = 7; break;
|
||||
default: ASSERT(0); break;
|
||||
}
|
||||
|
||||
int green_shift = 8 - blue_shift;
|
||||
ps_cb.ChannelShuffle = GSVector4i(blue_mask, blue_shift, green_mask, green_shift);
|
||||
|
||||
if (blue_shift >= 0)
|
||||
{
|
||||
// fprintf(stderr, "Green/Blue channel (%d, %d)\n", blue_shift, green_shift);
|
||||
m_ps_sel.channel = ChannelFetch_GXBY;
|
||||
m_context->FRAME.FBMSK = 0x00FFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
// fprintf(stderr, "Green channel (wrong mask) (fbmask %x)\n", m_context->FRAME.FBMSK >> 24);
|
||||
m_ps_sel.channel = ChannelFetch_GREEN;
|
||||
}
|
||||
|
||||
}
|
||||
else if (green)
|
||||
{
|
||||
// fprintf(stderr, "Green channel\n");
|
||||
m_ps_sel.channel = ChannelFetch_GREEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pop
|
||||
// fprintf(stderr, "Red channel\n");
|
||||
m_ps_sel.channel = ChannelFetch_RED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// fprintf(stderr, "Channel not supported\n");
|
||||
m_channel_shuffle = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Effect is really a channel shuffle effect so let's cheat a little
|
||||
if (m_channel_shuffle)
|
||||
{
|
||||
dev->PSSetShaderResource(4, tex->m_from_target);
|
||||
// Replace current draw with a fullscreen sprite
|
||||
//
|
||||
// Performance GPU note: it could be wise to reduce the size to
|
||||
// the rendered size of the framebuffer
|
||||
|
||||
GSVertex* s = &m_vertex.buff[0];
|
||||
s[0].XYZ.X = (uint16)(m_context->XYOFFSET.OFX + 0);
|
||||
s[1].XYZ.X = (uint16)(m_context->XYOFFSET.OFX + 16384);
|
||||
s[0].XYZ.Y = (uint16)(m_context->XYOFFSET.OFY + 0);
|
||||
s[1].XYZ.Y = (uint16)(m_context->XYOFFSET.OFY + 16384);
|
||||
|
||||
m_vertex.head = m_vertex.tail = m_vertex.next = 2;
|
||||
m_index.tail = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
dev->PSSetShaderResource(4, NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void GSRendererDX11::SetupIA(const float& sx, const float& sy)
|
||||
{
|
||||
GSDevice11* dev = (GSDevice11*)m_dev;
|
||||
|
|
|
@ -29,6 +29,7 @@ class GSRendererDX11 : public GSRendererDX
|
|||
{
|
||||
protected:
|
||||
void EmulateTextureShuffleAndFbmask();
|
||||
void EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex);
|
||||
void SetupIA(const float& sx, const float& sy);
|
||||
|
||||
public:
|
||||
|
|
|
@ -56,6 +56,61 @@ bool GSRendererDX9::CreateDevice(GSDevice* dev)
|
|||
return true;
|
||||
}
|
||||
|
||||
void GSRendererDX9::EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex)
|
||||
{
|
||||
// Channel shuffle will never be supported on Direct3D9 through shaders so just
|
||||
// use code that skips the bad draw calls.
|
||||
if (m_channel_shuffle)
|
||||
{
|
||||
if (m_game.title == CRC::Tekken5)
|
||||
{
|
||||
if (m_context->FRAME.FBW == 1)
|
||||
{
|
||||
// Used in stages: Secret Garden, Acid Rain, Moonlit Wilderness
|
||||
// 12 pages: 2 calls by channel, 3 channels, 1 blit
|
||||
// Minus current draw call
|
||||
m_skip = 12 * (3 + 3 + 1) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Could skip model drawing if wrongly detected
|
||||
m_channel_shuffle = false;
|
||||
}
|
||||
}
|
||||
else if ((tex->m_texture->GetType() == GSTexture::DepthStencil) && !(tex->m_32_bits_fmt))
|
||||
{
|
||||
// So far 2 games hit this code path. Urban Chaos and Tales of Abyss.
|
||||
throw GSDXRecoverableError();
|
||||
}
|
||||
else if (m_index.tail <= 64 && m_context->CLAMP.WMT == 3)
|
||||
{
|
||||
// Blood will tell. I think it is channel effect too but again
|
||||
// implemented in a different way. I don't want to add more CRC stuff. So
|
||||
// let's disable channel when the signature is different.
|
||||
//
|
||||
// Note: Tales Of Abyss and Tekken5 could hit this path too. Those games are
|
||||
// handled above.
|
||||
m_channel_shuffle = false;
|
||||
}
|
||||
else if (m_context->CLAMP.WMS == 3 && ((m_context->CLAMP.MAXU & 0x8) == 8))
|
||||
{
|
||||
// Read either blue or Alpha.
|
||||
// MGS3/Kill Zone
|
||||
throw GSDXRecoverableError();
|
||||
}
|
||||
else if (m_context->CLAMP.WMS == 3 && ((m_context->CLAMP.MINU & 0x8) == 0))
|
||||
{
|
||||
// Read either Red or Green.
|
||||
// Terminator 3
|
||||
throw GSDXRecoverableError();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_channel_shuffle = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSRendererDX9::EmulateTextureShuffleAndFbmask()
|
||||
{
|
||||
if (m_texture_shuffle)
|
||||
|
|
|
@ -35,6 +35,7 @@ protected:
|
|||
} m_fba;
|
||||
|
||||
void EmulateTextureShuffleAndFbmask();
|
||||
void EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex);
|
||||
void SetupIA(const float& sx, const float& sy);
|
||||
void UpdateFBA(GSTexture* rt);
|
||||
|
||||
|
|
|
@ -156,68 +156,6 @@ void GSRendererDX::EmulateZbuffer()
|
|||
}
|
||||
}
|
||||
|
||||
void GSRendererDX::EmulateChannelShuffle(const GSTextureCache::Source* tex)
|
||||
{
|
||||
// Channel shuffle effect not supported on DX. Let's keep the logic because it help to
|
||||
// reduce memory requirement (and why not a partial port)
|
||||
|
||||
// Uncomment to disable (allow to trace the draw call)
|
||||
// m_channel_shuffle = false;
|
||||
|
||||
// First let's check we really have a channel shuffle effect
|
||||
if (m_channel_shuffle)
|
||||
{
|
||||
if (m_game.title == CRC::Tekken5)
|
||||
{
|
||||
if (m_context->FRAME.FBW == 1)
|
||||
{
|
||||
// Used in stages: Secret Garden, Acid Rain, Moonlit Wilderness
|
||||
// Skip channel effect, it misses a shader for proper screen effect but at least the top left screen issue isn't appearing anymore
|
||||
// 12 pages: 2 calls by channel, 3 channels, 1 blit
|
||||
// Minus current draw call
|
||||
m_skip = 12 * (3 + 3 + 1) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Could skip model drawing if wrongly detected
|
||||
m_channel_shuffle = false;
|
||||
}
|
||||
}
|
||||
else if ((tex->m_texture->GetType() == GSTexture::DepthStencil) && !(tex->m_32_bits_fmt))
|
||||
{
|
||||
// So far 2 games hit this code path. Urban Chaos and Tales of Abyss.
|
||||
// Lacks shader like usual but maybe we can still use it to skip some bad draw calls.
|
||||
throw GSDXRecoverableError();
|
||||
}
|
||||
else if (m_index.tail <= 64 && m_context->CLAMP.WMT == 3)
|
||||
{
|
||||
// Blood will tell. I think it is channel effect too but again
|
||||
// implemented in a different way. I don't want to add more CRC stuff. So
|
||||
// let's disable channel when the signature is different.
|
||||
//
|
||||
// Note: Tales Of Abyss and Tekken5 could hit this path too. Those games are
|
||||
// handled above.
|
||||
m_channel_shuffle = false;
|
||||
}
|
||||
else if (m_context->CLAMP.WMS == 3 && ((m_context->CLAMP.MAXU & 0x8) == 8))
|
||||
{
|
||||
// Read either blue or Alpha. Let's go for Blue ;)
|
||||
// MGS3/Kill Zone
|
||||
throw GSDXRecoverableError();
|
||||
}
|
||||
else if (m_context->CLAMP.WMS == 3 && ((m_context->CLAMP.MINU & 0x8) == 0))
|
||||
{
|
||||
// Read either Red or Green. Let's check the V coordinate. 0-1 is likely top so
|
||||
// red. 2-3 is likely bottom so green (actually depends on texture base pointer offset)
|
||||
throw GSDXRecoverableError();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_channel_shuffle = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSRendererDX::EmulateTextureSampler(const GSTextureCache::Source* tex)
|
||||
{
|
||||
const GSLocalMemory::psm_t &psm = GSLocalMemory::m_psm[m_context->TEX0.PSM];
|
||||
|
@ -402,7 +340,7 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
|
|||
// HLE implementation of the channel selection effect
|
||||
//
|
||||
// Warning it must be done at the begining because it will change the vertex list
|
||||
EmulateChannelShuffle(tex);
|
||||
EmulateChannelShuffle(&rt, tex);
|
||||
|
||||
// Upscaling hack to avoid various line/grid issues
|
||||
MergeSprite(tex);
|
||||
|
@ -729,7 +667,8 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
|
|||
}
|
||||
|
||||
// rs
|
||||
GSVector4i scissor = GSVector4i(GSVector4(rtscale).xyxy() * m_context->scissor.in).rintersect(GSVector4i(rtsize).zwxy());
|
||||
const GSVector4& hacked_scissor = m_channel_shuffle ? GSVector4(0, 0, 1024, 1024) : m_context->scissor.in;
|
||||
GSVector4i scissor = GSVector4i(GSVector4(rtscale).xyxy() * hacked_scissor).rintersect(GSVector4i(rtsize).zwxy());
|
||||
|
||||
dev->OMSetRenderTargets(rt, ds, &scissor);
|
||||
dev->PSSetShaderResource(0, tex ? tex->m_texture : NULL);
|
||||
|
|
|
@ -37,10 +37,10 @@ protected:
|
|||
void ResetStates();
|
||||
void EmulateAtst(const int pass, const GSTextureCache::Source* tex);
|
||||
void EmulateZbuffer();
|
||||
void EmulateChannelShuffle(const GSTextureCache::Source* tex);
|
||||
void EmulateTextureSampler(const GSTextureCache::Source* tex);
|
||||
virtual void DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex);
|
||||
virtual void EmulateTextureShuffleAndFbmask() = 0;
|
||||
virtual void EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex) = 0;
|
||||
virtual void SetupIA(const float& sx, const float& sy) = 0;
|
||||
virtual void UpdateFBA(GSTexture* rt) {}
|
||||
|
||||
|
|
Loading…
Reference in New Issue