mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Replace Ico CRC hack with move handler
This commit is contained in:
parent
d5776e8946
commit
3109c5ef67
|
@ -383,6 +383,7 @@ PCPX-96322:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
PCPX-96328:
|
||||
name: "3 Title Special Disc (Saru! Get You! 2 - PoPoLoCrois: Hajimari no Bouken - Boku no Natsuyasumi 2)"
|
||||
region: "NTSC-J"
|
||||
|
@ -959,6 +960,7 @@ SCAJ-20099:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCAJ-20100:
|
||||
name: "Tenchu Kurenai"
|
||||
region: "NTSC-Ch-J"
|
||||
|
@ -1711,6 +1713,7 @@ SCCS-40005:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCCS-40006:
|
||||
name: "Zhen Sanguo Wushuang 2"
|
||||
region: "NTSC-C"
|
||||
|
@ -2030,6 +2033,7 @@ SCED-50844:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCED-50907:
|
||||
name: "Final Fantasy X [Bonus Disc - Beyond Final Fantasy]"
|
||||
region: "PAL-Unk"
|
||||
|
@ -3387,6 +3391,7 @@ SCES-50760:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCES-50781:
|
||||
name: "Destruction Derby Arenas [Beta, Promo, & Full Retail]"
|
||||
region: "PAL-M6"
|
||||
|
@ -5325,6 +5330,7 @@ SCKA-20028:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCKA-20029:
|
||||
name: "Gran Turismo - Concept 2002 Tokyo-Seoul [PlayStation 2 Big Hit Series]"
|
||||
region: "NTSC-K"
|
||||
|
@ -5847,6 +5853,7 @@ SCPS-11003:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCPS-11004:
|
||||
name: "Bikkuri Mouse"
|
||||
region: "NTSC-J"
|
||||
|
@ -6688,6 +6695,7 @@ SCPS-19103:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCPS-19104:
|
||||
name: "Pipo Saru 2001 [PlayStation 2 The Best]"
|
||||
region: "NTSC-J"
|
||||
|
@ -6704,6 +6712,7 @@ SCPS-19151:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCPS-19152:
|
||||
name: "Saru Get You! 2 [PlayStation 2 The Best]"
|
||||
region: "NTSC-J"
|
||||
|
@ -7155,6 +7164,7 @@ SCPS-55001:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCPS-55002:
|
||||
name: "Zero"
|
||||
region: "NTSC-J"
|
||||
|
@ -7427,6 +7437,7 @@ SCPS-56001:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCPS-56002:
|
||||
name: "Tekken Tag Tournament"
|
||||
region: "NTSC-K"
|
||||
|
@ -7602,6 +7613,7 @@ SCUS-97113:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCUS-97114:
|
||||
name: "NBA ShootOut 2001"
|
||||
region: "NTSC-U"
|
||||
|
@ -7787,6 +7799,7 @@ SCUS-97159:
|
|||
gsHWFixes:
|
||||
mipmap: 1
|
||||
halfPixelOffset: 1 # Fixes effect misalignment.
|
||||
moveHandler: "MV_Ico" # Fixes depth buffer post-processing.
|
||||
SCUS-97160:
|
||||
name: "Extermination [Demo]"
|
||||
region: "NTSC-U"
|
||||
|
|
|
@ -26,13 +26,6 @@ const CRC::Game CRC::m_games[] =
|
|||
{
|
||||
// Note: IDs 0x7ACF7E03, 0x7D4EA48F, 0x37C53760 - shouldn't be added as it's from the multiloaders when packing games.
|
||||
{0x00000000, NoTitle /* NoRegion */},
|
||||
{0x6F8545DB, ICO /* US */},
|
||||
{0x48CDF317, ICO /* US */}, // Demo
|
||||
{0xB01A4C95, ICO /* JP */},
|
||||
{0x2DF2C1EA, ICO /* KO */},
|
||||
{0x5C991F4E, ICO /* EU */},
|
||||
{0x788D8B4F, ICO /* EU */},
|
||||
{0x29C28734, ICO /* CH */},
|
||||
{0xFC46EA61, Tekken5 /* JP */},
|
||||
{0x1F88EE37, Tekken5 /* EU */},
|
||||
{0x1F88BECD, Tekken5 /* EU */}, // language selector...
|
||||
|
|
|
@ -23,7 +23,6 @@ public:
|
|||
enum Title : u32
|
||||
{
|
||||
NoTitle,
|
||||
ICO,
|
||||
SMTNocturne,
|
||||
Tekken5,
|
||||
TitleCount,
|
||||
|
|
|
@ -616,7 +616,7 @@ bool GSHwHack::GSC_PolyphonyDigitalGames(GSRendererHW& r, int& skip)
|
|||
// have to set up the palette ourselves too, since GSC executes before it does
|
||||
r.m_mem.m_clut.Read32(RTEX0, r.m_draw_env->TEXA);
|
||||
std::shared_ptr<GSTextureCache::Palette> palette =
|
||||
g_texture_cache->LookupPaletteObject(GSLocalMemory::m_psm[RTEX0.PSM].pal, true);
|
||||
g_texture_cache->LookupPaletteObject(r.m_mem.m_clut, GSLocalMemory::m_psm[RTEX0.PSM].pal, true);
|
||||
if (!palette)
|
||||
return false;
|
||||
|
||||
|
@ -1167,7 +1167,6 @@ static bool GetMoveTargetPair(GSRendererHW& r, GSTextureCache::Target** src, GIF
|
|||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Disabled to avoid compiler warnings, enable when it is needed.
|
||||
static bool GetMoveTargetPair(GSRendererHW& r, GSTextureCache::Target** src, GSTextureCache::Target** dst,
|
||||
bool req_target = false, bool preserve_target = false)
|
||||
|
@ -1175,7 +1174,8 @@ static bool GetMoveTargetPair(GSRendererHW& r, GSTextureCache::Target** src, GST
|
|||
return GetMoveTargetPair(r, src, GIFRegTEX0::Create(RSBP, RSBW, RSPSM), dst, GIFRegTEX0::Create(RDBP, RDBW, RDPSM),
|
||||
req_target, preserve_target);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int s_last_hacked_move_n = 0;
|
||||
|
||||
bool GSHwHack::MV_Growlanser(GSRendererHW& r)
|
||||
{
|
||||
|
@ -1192,8 +1192,7 @@ bool GSHwHack::MV_Growlanser(GSRendererHW& r)
|
|||
return false;
|
||||
|
||||
// All the moves happen inbetween two draws, so we can take advantage of that to know when to stop.
|
||||
static int last_hacked_move_n = 0;
|
||||
if (r.s_n == last_hacked_move_n)
|
||||
if (r.s_n == s_last_hacked_move_n)
|
||||
return true;
|
||||
|
||||
GSTextureCache::Target *src, *dst;
|
||||
|
@ -1212,7 +1211,53 @@ bool GSHwHack::MV_Growlanser(GSRendererHW& r)
|
|||
g_gs_device->StretchRect(src->GetTexture(), GSVector4(rc) / GSVector4(src->GetUnscaledSize()).xyxy(),
|
||||
dst->GetTexture(), GSVector4(rc) * GSVector4(dst->GetScale()), ShaderConvert::RGBA8_TO_FLOAT32, false);
|
||||
|
||||
last_hacked_move_n = r.s_n;
|
||||
s_last_hacked_move_n = r.s_n;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::MV_Ico(GSRendererHW& r)
|
||||
{
|
||||
// Ico unswizzles the depth buffer (usually) 0x1800 to (usually) 0x2800 with a Z32->C32 move.
|
||||
// Then it does a bunch of P4 moves to shift the bits in the blue channel to the alpha channel.
|
||||
// The shifted target then gets used as a P8H texture, basically mapping depth bits 16..24 to a LUT.
|
||||
// We can't currently HLE that in the usual move handler, so instead, emulate it with a channel shuffle.
|
||||
|
||||
// If we've started skipping moves (i.e. HLE'ed the first one), skip the others.
|
||||
if (r.s_n == s_last_hacked_move_n && RSPSM == PSMT4 && RDPSM == PSMT4)
|
||||
return true;
|
||||
|
||||
// 512x448 moves from C32->Z32.
|
||||
if (RSPSM != PSMZ32 || RDPSM != PSMCT32 || RWIDTH < 512 || RHEIGHT < 448)
|
||||
return false;
|
||||
|
||||
GL_PUSH("MV_Ico: %x -> %x %dx%d", RSBP, RDBP, RWIDTH, RHEIGHT);
|
||||
|
||||
GSTextureCache::Target *src, *dst;
|
||||
if (!GetMoveTargetPair(r, &src, &dst, false, false))
|
||||
return false;
|
||||
|
||||
// Store B -> A using a channel shuffle.
|
||||
u32 pal[256];
|
||||
for (u32 i = 0; i < std::size(pal); i++)
|
||||
pal[i] = i << 24;
|
||||
std::shared_ptr<GSTextureCache::Palette> palette = g_texture_cache->LookupPaletteObject(pal, 256, true);
|
||||
if (!palette)
|
||||
return false;
|
||||
|
||||
const GSVector4i draw_rc = GSVector4i(0, 0, RWIDTH, RHEIGHT);
|
||||
dst->UpdateValidChannels(PSMCT32, 0);
|
||||
dst->UpdateValidity(draw_rc);
|
||||
|
||||
GSHWDrawConfig& config = GSRendererHW::GetInstance()->BeginHLEHardwareDraw(dst->GetTexture(), nullptr,
|
||||
dst->GetScale(), src->GetTexture(), src->GetScale(), draw_rc);
|
||||
config.pal = palette->GetPaletteGSTexture();
|
||||
config.ps.channel = ChannelFetch_BLUE;
|
||||
config.ps.depth_fmt = 1;
|
||||
config.ps.tfx = TFX_DECAL; // T -> A.
|
||||
config.ps.tcc = true;
|
||||
GSRendererHW::GetInstance()->EndHLEHardwareDraw(false);
|
||||
|
||||
s_last_hacked_move_n = r.s_n;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1291,6 +1336,7 @@ const GSHwHack::Entry<GSRendererHW::OI_Ptr> GSHwHack::s_before_draw_functions[]
|
|||
|
||||
const GSHwHack::Entry<GSRendererHW::MV_Ptr> GSHwHack::s_move_handler_functions[] = {
|
||||
CRC_F(MV_Growlanser),
|
||||
CRC_F(MV_Ico),
|
||||
};
|
||||
|
||||
#undef CRC_F
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
static bool OI_HauntingGround(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
|
||||
static bool MV_Growlanser(GSRendererHW& r);
|
||||
static bool MV_Ico(GSRendererHW& r);
|
||||
|
||||
template <typename F>
|
||||
struct Entry
|
||||
|
|
|
@ -3972,40 +3972,6 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
|||
m_conf.tex = tex->m_texture;
|
||||
m_conf.pal = tex->m_palette;
|
||||
|
||||
if (m_game.title == CRC::ICO)
|
||||
{
|
||||
const GSVertex* v = &m_vertex.buff[0];
|
||||
const GSVideoMode mode = GetVideoMode();
|
||||
if (tex && m_vt.m_primclass == GS_SPRITE_CLASS && m_vertex.next == 2 && PRIM->ABE && // Blend texture
|
||||
((v[1].U == 8200 && v[1].V == 7176 && mode == GSVideoMode::NTSC) || // at display resolution 512x448
|
||||
(v[1].U == 8200 && v[1].V == 8200 && mode == GSVideoMode::PAL)) && // at display resolution 512x512
|
||||
tex->m_TEX0.PSM == PSMT8H) // i.e. read the alpha channel of a 32 bits texture
|
||||
{
|
||||
// Note potentially we can limit to TBP0:0x2800
|
||||
|
||||
// Depth buffer was moved so GS will invalide it which means a
|
||||
// downscale. ICO uses the MSB depth bits as the texture alpha
|
||||
// channel. However this depth of field effect requires
|
||||
// texel:pixel mapping accuracy.
|
||||
//
|
||||
// Use an HLE shader to sample depth directly as the alpha channel
|
||||
GL_INS("ICO sample depth as alpha");
|
||||
m_conf.require_full_barrier = true;
|
||||
// Extract the depth as palette index
|
||||
m_conf.ps.depth_fmt = 1;
|
||||
m_conf.ps.channel = ChannelFetch_BLUE;
|
||||
m_conf.tex = ds->m_texture;
|
||||
|
||||
// We need the palette to convert the depth to the correct alpha value.
|
||||
if (!tex->m_palette)
|
||||
{
|
||||
const u16 pal = GSLocalMemory::m_psm[tex->m_TEX0.PSM].pal;
|
||||
g_texture_cache->AttachPaletteToSource(tex, pal, true);
|
||||
m_conf.pal = tex->m_palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hazard handling (i.e. reading from the current RT/DS).
|
||||
GSTextureCache::SourceRegion source_region = tex->GetRegion();
|
||||
bool target_region = (tex->IsFromTarget() && source_region.HasEither());
|
||||
|
|
|
@ -4494,9 +4494,9 @@ GSTexture* GSTextureCache::LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVec
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<GSTextureCache::Palette> GSTextureCache::LookupPaletteObject(u16 pal, bool need_gs_texture)
|
||||
std::shared_ptr<GSTextureCache::Palette> GSTextureCache::LookupPaletteObject(const u32* clut, u16 pal, bool need_gs_texture)
|
||||
{
|
||||
return m_palette_map.LookupPalette(pal, need_gs_texture);
|
||||
return m_palette_map.LookupPalette(clut, pal, need_gs_texture);
|
||||
}
|
||||
|
||||
void GSTextureCache::Read(Target* t, const GSVector4i& r)
|
||||
|
@ -5615,13 +5615,13 @@ void GSTextureCache::InjectHashCacheTexture(const HashCacheKey& key, GSTexture*
|
|||
|
||||
// GSTextureCache::Palette
|
||||
|
||||
GSTextureCache::Palette::Palette(u16 pal, bool need_gs_texture)
|
||||
GSTextureCache::Palette::Palette(const u32* clut, u16 pal, bool need_gs_texture)
|
||||
: m_tex_palette(nullptr)
|
||||
, m_pal(pal)
|
||||
{
|
||||
const u16 palette_size = pal * sizeof(u32);
|
||||
m_clut = (u32*)_aligned_malloc(palette_size, 64);
|
||||
memcpy(m_clut, (const u32*)g_gs_renderer->m_mem.m_clut, palette_size);
|
||||
memcpy(m_clut, clut, palette_size);
|
||||
if (need_gs_texture)
|
||||
{
|
||||
InitializeTexture();
|
||||
|
@ -5699,6 +5699,11 @@ GSTextureCache::PaletteMap::PaletteMap()
|
|||
}
|
||||
|
||||
std::shared_ptr<GSTextureCache::Palette> GSTextureCache::PaletteMap::LookupPalette(u16 pal, bool need_gs_texture)
|
||||
{
|
||||
return LookupPalette(g_gs_renderer->m_mem.m_clut, pal, need_gs_texture);
|
||||
}
|
||||
|
||||
std::shared_ptr<GSTextureCache::Palette> GSTextureCache::PaletteMap::LookupPalette(const u32* clut, u16 pal, bool need_gs_texture)
|
||||
{
|
||||
ASSERT(pal == 16 || pal == 256);
|
||||
|
||||
|
@ -5707,8 +5712,6 @@ std::shared_ptr<GSTextureCache::Palette> GSTextureCache::PaletteMap::LookupPalet
|
|||
// pal == 256 : index 1
|
||||
auto& map = m_maps[pal == 16 ? 0 : 1];
|
||||
|
||||
const u32* clut = (const u32*)g_gs_renderer->m_mem.m_clut;
|
||||
|
||||
// Create PaletteKey for searching into map (clut is actually not copied, so do not store this key into the map)
|
||||
const PaletteKey palette_key = {clut, pal};
|
||||
|
||||
|
@ -5763,7 +5766,7 @@ std::shared_ptr<GSTextureCache::Palette> GSTextureCache::PaletteMap::LookupPalet
|
|||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Palette> palette = std::make_shared<Palette>(pal, need_gs_texture);
|
||||
std::shared_ptr<Palette> palette = std::make_shared<Palette>(clut, pal, need_gs_texture);
|
||||
|
||||
map.emplace(palette->GetPaletteKey(), palette);
|
||||
|
||||
|
|
|
@ -181,7 +181,7 @@ public:
|
|||
std::pair<u8, u8> m_alpha_minmax;
|
||||
|
||||
public:
|
||||
Palette(u16 pal, bool need_gs_texture);
|
||||
Palette(const u32* clut, u16 pal, bool need_gs_texture);
|
||||
~Palette();
|
||||
|
||||
__fi std::pair<u8, u8> GetAlphaMinMax() const { return m_alpha_minmax; }
|
||||
|
@ -335,6 +335,7 @@ public:
|
|||
|
||||
// Retrieves a shared pointer to a valid Palette from m_maps or creates a new one adding it to the data structure
|
||||
std::shared_ptr<Palette> LookupPalette(u16 pal, bool need_gs_texture);
|
||||
std::shared_ptr<Palette> LookupPalette(const u32* clut, u16 pal, bool need_gs_texture);
|
||||
|
||||
void Clear(); // Clears m_maps, thus deletes Palette objects
|
||||
};
|
||||
|
@ -470,7 +471,7 @@ public:
|
|||
void DirtyRectByPage(u32 sbp, u32 spsm, u32 sbw, Target* t, GSVector4i src_r);
|
||||
|
||||
GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size);
|
||||
std::shared_ptr<Palette> LookupPaletteObject(u16 pal, bool need_gs_texture);
|
||||
std::shared_ptr<Palette> LookupPaletteObject(const u32* clut, u16 pal, bool need_gs_texture);
|
||||
|
||||
Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod, const bool possible_shuffle);
|
||||
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, bool palette = false);
|
||||
|
|
Loading…
Reference in New Issue