Merge pull request #1322 from PCSX2/gsdx-8b-subrt

gsdx: improve detection of channel shuffle
This commit is contained in:
Gregory Hainaut 2016-05-01 14:28:22 +02:00
commit 9cacfee8c7
10 changed files with 369 additions and 231 deletions

View File

@ -779,6 +779,7 @@ GLuint GSDeviceOGL::CompilePS(PSSelector sel)
+ format("#define PS_DFMT %d\n", sel.dfmt)
+ format("#define PS_DEPTH_FMT %d\n", sel.depth_fmt)
+ format("#define PS_CHANNEL_FETCH %d\n", sel.channel)
+ format("#define PS_URBAN_CHAOS_HACK %d\n", sel.urban_chaos_hack)
+ format("#define PS_AEM %d\n", sel.aem)
+ format("#define PS_TFX %d\n", sel.tfx)
+ format("#define PS_TCC %d\n", sel.tcc)

View File

@ -289,8 +289,9 @@ class GSDeviceOGL final : public GSDevice
// Hack
uint32 tcoffsethack:1;
uint32 urban_chaos_hack:1;
uint32 _free2:16;
uint32 _free2:15;
};
uint64 key;

View File

@ -112,86 +112,6 @@ bool GSC_DBZBT3(const GSFrameInfo& fi, int& skip)
return true;
}
// Potentially partially dx only
bool GSC_ICO(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x00800 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03d00 && fi.TPSM == PSM_PSMCT32)
{
skip = 3;
}
else if(fi.TME && fi.FBP == 0x00800 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x02800 && fi.TPSM == PSM_PSMT8H)
{
skip = 1;
}
else if( Aggresive && fi.TME && fi.FBP == 0x0800 && (fi.TBP0 == 0x2800 || fi.TBP0 ==0x2c00) && fi.TPSM ==0 && fi.FBMSK == 0)
{
skip = 1;
}
}
else
{
if(fi.TME && fi.TBP0 == 0x00800 && fi.TPSM == PSM_PSMCT32)
{
skip = 0;
}
}
return true;
}
bool GSC_GT4(const GSFrameInfo& fi, int& skip)
{
// Game requires to extract source from RT (block boundary) (texture cache limitation)
if(skip == 0)
{
if(fi.TME && fi.FBP >= 0x02f00 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01180 /*|| fi.TBP0 == 0x01a40*/) && fi.TPSM == PSM_PSMT8) //TBP0 0x1a40 progressive
{
skip = 770; //ntsc, progressive 1540
}
if(g_crc_region == CRC::EU && fi.TME && fi.FBP >= 0x03400 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01400 ) && fi.TPSM == PSM_PSMT8)
{
skip = 880; //pal
}
else if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01400) && fi.FPSM == PSM_PSMCT24 && fi.TBP0 >= 0x03420 && fi.TPSM == PSM_PSMT8)
{
// TODO: removes gfx from where it is not supposed to (garage)
// skip = 58;
}
}
return true;
}
bool GSC_GT3(const GSFrameInfo& fi, int& skip)
{
// Same issue as GSC_GT4 ???
if(skip == 0)
{
if(fi.TME && fi.FBP >= 0x02de0 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01180) && fi.TPSM == PSM_PSMT8)
{
skip = 770;
}
}
return true;
}
bool GSC_GTConcept(const GSFrameInfo& fi, int& skip)
{
// Same issue as GSC_GT4 ???
if(skip == 0)
{
if(fi.TME && fi.FBP >= 0x03420 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01400) && fi.TPSM == PSM_PSMT8)
{
skip = 880;
}
}
return true;
}
bool GSC_WildArms4(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
@ -234,6 +154,24 @@ bool GSC_WildArms5(const GSFrameInfo& fi, int& skip)
bool GSC_Manhunt2(const GSFrameInfo& fi, int& skip)
{
/*
* The game readback RT as 8 bits index texture to apply a non-linear brightness/gamma correction on all channel
* It could be written in HLE shader as:
* out = blue_lut[in.blue] + green_lut[in.green] + blue_lut[in.blue]
*
* Unlike others games (which do all pages of a channel), man hunt apply the 3 channel corrections by page.
* (in short it is loop index/loop page instead of loop page/loop index)
*
* It is very annoying to detect.So in order to fix the effect the best
* solution will be to implement an alternate draw call and then skip the
* useless gs draw call.
*
* Blue Palette correction is located @ 0x3C08 (TEX0.CBP of the first draw call that will fire the effect)
* Green Palette correction is located @ 0x3C04
* Blue Palette correction is located @ 0x3C00
* Either we upload the data as a new texture or we could hardcode them in a shader
*
*/
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x03c20 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x01400 && fi.TPSM == PSM_PSMT8)
@ -865,36 +803,6 @@ bool GSC_StarWarsForceUnleashed(const GSFrameInfo& fi, int& skip)
return true;
}
bool GSC_StarWarsBattlefront(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP > 0x0 && fi.FBP < 0x01000) && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 > 0x02000 && fi.TBP0 < 0x03000) && fi.TPSM == PSM_PSMT8)
{
skip = 1;
}
}
return true;
}
bool GSC_StarWarsBattlefront2(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP > 0x01000 && fi.FBP < 0x02000) && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 > 0x0 && fi.TBP0 < 0x01000) && fi.TPSM == PSM_PSMT8)
{
skip = 1;
}
if(fi.TME && (fi.FBP > 0x01000 && fi.FBP < 0x02000) && fi.FPSM == PSM_PSMZ32 && (fi.TBP0 > 0x0 && fi.TBP0 < 0x01000) && fi.TPSM == PSM_PSMT8)
{
skip = 1;
}
}
return true;
}
bool GSC_BlackHawkDown(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
@ -1079,34 +987,6 @@ bool GSC_Yakuza2(const GSFrameInfo& fi, int& skip)
return true;
}
bool GSC_SkyGunner(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(!fi.TME && !(fi.FBP == 0x0 || fi.FBP == 0x00800 || fi.FBP == 0x008c0 || fi.FBP == 0x03e00) && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x0 || fi.TBP0 == 0x01800) && fi.TPSM == PSM_PSMCT32)
{
skip = 1; //Huge Vram usage
}
}
return true;
}
bool GSC_JamesBondEverythingOrNothing(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP < 0x02000 && !(fi.FBP == 0x0 || fi.FBP == 0x00e00)) && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 > 0x01c00 && fi.TBP0 < 0x03000) && fi.TPSM == PSM_PSMT8)
{
skip = 1; //Huge Vram usage
}
}
return true;
}
bool GSC_ZettaiZetsumeiToshi2(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
@ -1237,23 +1117,6 @@ bool GSC_FightingBeautyWulong(const GSFrameInfo& fi, int& skip)
return true;
}
bool GSC_TouristTrophy(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP >= 0x02f00 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01180) && fi.TPSM == PSM_PSMT8)
{
skip = 770;
}
if(fi.TME && fi.FBP >= 0x02de0 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 ==0 || fi.TBP0==0x1a40 ||fi.TBP0 ==0x2300) && fi.TPSM == PSM_PSMT8)
{
skip = 770; //480P
}
}
return true;
}
bool GSC_GTASanAndreas(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
@ -1327,29 +1190,6 @@ bool GSC_UltramanFightingEvolution(const GSFrameInfo& fi, int& skip)
return true;
}
bool GSC_DeathByDegreesTekkenNinaWilliams(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP ==0 ) && fi.TBP0==0x34a0 && (fi.TPSM == PSM_PSMCT32))
{
skip = 1;
}
else if((fi.FBP ==0x3500)&& fi.TPSM == PSM_PSMT8 && fi.FBMSK == 0xFFFF00FF)
{
skip = 4;
}
}
if(fi.TME)
{
if((fi.FBP | fi.TBP0 | fi.FPSM | fi.TPSM) && (fi.FBMSK == 0x00FFFFFF ))
{
skip = 1;
}
}
return true;
}
bool GSC_AlpineRacer3(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
@ -1512,6 +1352,182 @@ bool GSC_SteambotChronicles(const GSFrameInfo& fi, int& skip)
////////////////////////////////////////////////////////////////////////////////
// Correctly emulated on OpenGL but can be used as potential speed hack
////////////////////////////////////////////////////////////////////////////////
bool GSC_DeathByDegreesTekkenNinaWilliams(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP ==0 ) && fi.TBP0==0x34a0 && (fi.TPSM == PSM_PSMCT32))
{
skip = 1;
}
else if((fi.FBP ==0x3500)&& fi.TPSM == PSM_PSMT8 && fi.FBMSK == 0xFFFF00FF)
{
skip = 4;
}
}
if(fi.TME)
{
if((fi.FBP | fi.TBP0 | fi.FPSM | fi.TPSM) && (fi.FBMSK == 0x00FFFFFF ))
{
skip = 1;
}
}
return true;
}
bool GSC_ICO(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x00800 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03d00 && fi.TPSM == PSM_PSMCT32)
{
skip = 3;
}
else if(fi.TME && fi.FBP == 0x00800 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x02800 && fi.TPSM == PSM_PSMT8H)
{
skip = 1;
}
else if( Aggresive && fi.TME && fi.FBP == 0x0800 && (fi.TBP0 == 0x2800 || fi.TBP0 ==0x2c00) && fi.TPSM ==0 && fi.FBMSK == 0)
{
skip = 1;
}
}
else
{
if(fi.TME && fi.TBP0 == 0x00800 && fi.TPSM == PSM_PSMCT32)
{
skip = 0;
}
}
return true;
}
bool GSC_GT4(const GSFrameInfo& fi, int& skip)
{
// Game requires to extract source from RT (block boundary) (texture cache limitation)
if(skip == 0)
{
if(fi.TME && fi.FBP >= 0x02f00 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01180 /*|| fi.TBP0 == 0x01a40*/) && fi.TPSM == PSM_PSMT8) //TBP0 0x1a40 progressive
{
skip = 770; //ntsc, progressive 1540
}
if(g_crc_region == CRC::EU && fi.TME && fi.FBP >= 0x03400 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01400 ) && fi.TPSM == PSM_PSMT8)
{
skip = 880; //pal
}
else if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01400) && fi.FPSM == PSM_PSMCT24 && fi.TBP0 >= 0x03420 && fi.TPSM == PSM_PSMT8)
{
// TODO: removes gfx from where it is not supposed to (garage)
// skip = 58;
}
}
return true;
}
bool GSC_GT3(const GSFrameInfo& fi, int& skip)
{
// Same issue as GSC_GT4 ???
if(skip == 0)
{
if(fi.TME && fi.FBP >= 0x02de0 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01180) && fi.TPSM == PSM_PSMT8)
{
skip = 770;
}
}
return true;
}
bool GSC_GTConcept(const GSFrameInfo& fi, int& skip)
{
// Same issue as GSC_GT4 ???
if(skip == 0)
{
if(fi.TME && fi.FBP >= 0x03420 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01400) && fi.TPSM == PSM_PSMT8)
{
skip = 880;
}
}
return true;
}
bool GSC_TouristTrophy(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP >= 0x02f00 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01180) && fi.TPSM == PSM_PSMT8)
{
skip = 770;
}
if(fi.TME && fi.FBP >= 0x02de0 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 ==0 || fi.TBP0==0x1a40 ||fi.TBP0 ==0x2300) && fi.TPSM == PSM_PSMT8)
{
skip = 770; //480P
}
}
return true;
}
bool GSC_SkyGunner(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(!fi.TME && !(fi.FBP == 0x0 || fi.FBP == 0x00800 || fi.FBP == 0x008c0 || fi.FBP == 0x03e00) && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x0 || fi.TBP0 == 0x01800) && fi.TPSM == PSM_PSMCT32)
{
skip = 1; //Huge Vram usage
}
}
return true;
}
bool GSC_JamesBondEverythingOrNothing(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP < 0x02000 && !(fi.FBP == 0x0 || fi.FBP == 0x00e00)) && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 > 0x01c00 && fi.TBP0 < 0x03000) && fi.TPSM == PSM_PSMT8)
{
skip = 1; //Huge Vram usage
}
}
return true;
}
bool GSC_StarWarsBattlefront(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP > 0x0 && fi.FBP < 0x01000) && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 > 0x02000 && fi.TBP0 < 0x03000) && fi.TPSM == PSM_PSMT8)
{
skip = 1;
}
}
return true;
}
bool GSC_StarWarsBattlefront2(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP > 0x01000 && fi.FBP < 0x02000) && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 > 0x0 && fi.TBP0 < 0x01000) && fi.TPSM == PSM_PSMT8)
{
skip = 1;
}
if(fi.TME && (fi.FBP > 0x01000 && fi.FBP < 0x02000) && fi.FPSM == PSM_PSMZ32 && (fi.TBP0 > 0x0 && fi.TBP0 < 0x01000) && fi.TPSM == PSM_PSMT8)
{
skip = 1;
}
}
return true;
}
bool GSC_Okami(const GSFrameInfo& fi, int& skip)
{
@ -2458,7 +2474,6 @@ bool GSState::IsBadFrame(int& skip, int UserHacks_SkipDraw)
map[CRC::CrashBandicootWoC] = GSC_CrashBandicootWoC;
map[CRC::DBZBT2] = GSC_DBZBT2;
map[CRC::DBZBT3] = GSC_DBZBT3;
map[CRC::DeathByDegreesTekkenNinaWilliams] = GSC_DeathByDegreesTekkenNinaWilliams;
map[CRC::DevilMayCry3] = GSC_DevilMayCry3;
map[CRC::EternalPoison] = GSC_EternalPoison;
map[CRC::EvangelionJo] = GSC_EvangelionJo;
@ -2470,16 +2485,11 @@ bool GSState::IsBadFrame(int& skip, int UserHacks_SkipDraw)
map[CRC::GetaWayBlackMonday] = GSC_GetaWay;
map[CRC::GetaWay] = GSC_GetaWay;
map[CRC::GodHand] = GSC_GodHand;
map[CRC::GT3] = GSC_GT3;
map[CRC::GT4] = GSC_GT4;
map[CRC::GTASanAndreas] = GSC_GTASanAndreas;
map[CRC::GTConcept] = GSC_GTConcept;
map[CRC::HauntingGround] = GSC_HauntingGround;
map[CRC::HeavyMetalThunder] = GSC_HeavyMetalThunder;
map[CRC::HummerBadlands] = GSC_HummerBadlands;
map[CRC::ICO] = GSC_ICO;
map[CRC::IkkiTousen] = GSC_IkkiTousen;
map[CRC::JamesBondEverythingOrNothing] = GSC_JamesBondEverythingOrNothing;
map[CRC::KnightsOfTheTemple2] = GSC_KnightsOfTheTemple2;
map[CRC::Kunoichi] = GSC_Kunoichi;
map[CRC::LordOfTheRingsThirdAge] = GSC_LordOfTheRingsThirdAge;
@ -2499,12 +2509,9 @@ bool GSState::IsBadFrame(int& skip, int UserHacks_SkipDraw)
map[CRC::ShadowofRome] = GSC_ShadowofRome;
map[CRC::ShinOnimusha] = GSC_ShinOnimusha;
map[CRC::Simple2000Vol114] = GSC_Simple2000Vol114;
map[CRC::SkyGunner] = GSC_SkyGunner;
map[CRC::SoulCalibur2] = GSC_SoulCalibur2;
map[CRC::SoulCalibur3] = GSC_SoulCalibur3;
map[CRC::Spartan] = GSC_Spartan;
map[CRC::StarWarsBattlefront2] = GSC_StarWarsBattlefront2;
map[CRC::StarWarsBattlefront] = GSC_StarWarsBattlefront;
map[CRC::StarWarsForceUnleashed] = GSC_StarWarsForceUnleashed;
map[CRC::SteambotChronicles] = GSC_SteambotChronicles;
map[CRC::TalesOfAbyss] = GSC_TalesOfAbyss;
@ -2515,7 +2522,6 @@ bool GSState::IsBadFrame(int& skip, int UserHacks_SkipDraw)
map[CRC::TombRaiderAnniversary] = GSC_TombRaider;
map[CRC::TombRaiderLegend] = GSC_TombRaiderLegend;
map[CRC::TombRaiderUnderworld] = GSC_TombRaiderUnderWorld;
map[CRC::TouristTrophy] = GSC_TouristTrophy;
map[CRC::UltramanFightingEvolution] = GSC_UltramanFightingEvolution;
map[CRC::UrbanReign] = GSC_UrbanReign;
map[CRC::WildArms4] = GSC_WildArms4;
@ -2536,9 +2542,11 @@ bool GSState::IsBadFrame(int& skip, int UserHacks_SkipDraw)
// Hack that were fixed on openGL
if (Dx_only) {
// Depth
map[CRC::Bully] = GSC_Bully;
map[CRC::BullyCC] = GSC_BullyCC;
map[CRC::GodOfWar2] = GSC_GodOfWar2;
map[CRC::ICO] = GSC_ICO;
map[CRC::LordOfTheRingsTwoTowers] = GSC_LordOfTheRingsTwoTowers;
map[CRC::Okami] = GSC_Okami;
map[CRC::SimpsonsGame] = GSC_SimpsonsGame;
@ -2560,9 +2568,6 @@ bool GSState::IsBadFrame(int& skip, int UserHacks_SkipDraw)
map[CRC::TenchuFS] = GSC_Tenchu;
map[CRC::TenchuWoH] = GSC_Tenchu;
// Basic Accurate blending + channel effect
map[CRC::MetalGearSolid3] = GSC_MetalGearSolid3;
// Those games might requires accurate fbmask
map[CRC::Sly2] = GSC_Sly2;
map[CRC::Sly3] = GSC_Sly3;
@ -2583,6 +2588,18 @@ bool GSState::IsBadFrame(int& skip, int UserHacks_SkipDraw)
// At least a part of the CRC is fixed with texture shuffle.
// The status of post-processing effect is unknown
map[CRC::Black] = GSC_Black;
// Channel Effect
map[CRC::DeathByDegreesTekkenNinaWilliams] = GSC_DeathByDegreesTekkenNinaWilliams;
map[CRC::GT3] = GSC_GT3;
map[CRC::GT4] = GSC_GT4;
map[CRC::GTConcept] = GSC_GTConcept;
map[CRC::JamesBondEverythingOrNothing] = GSC_JamesBondEverythingOrNothing;
map[CRC::MetalGearSolid3] = GSC_MetalGearSolid3; // + accurate blending
map[CRC::SkyGunner] = GSC_SkyGunner;
map[CRC::StarWarsBattlefront2] = GSC_StarWarsBattlefront2;
map[CRC::StarWarsBattlefront] = GSC_StarWarsBattlefront;
map[CRC::TouristTrophy] = GSC_TouristTrophy;
}
}

View File

@ -58,6 +58,18 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
GSDeviceDX* dev = (GSDeviceDX*)m_dev;
// 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)
if (m_channel_shuffle) {
if (m_context->CLAMP.WMS == 3 && ((m_context->CLAMP.MAXU & 0x8) == 8)) {
;
} else if (m_context->CLAMP.WMS == 3 && ((m_context->CLAMP.MINU & 0x8) == 0)) {
;
} else {
m_channel_shuffle = false;
}
}
if(DATE)
{
if(dev->HasStencil())

View File

@ -372,17 +372,26 @@ void GSRendererHW::Draw()
(context->FRAME.FBP == context->ZBUF.ZBP && !PRIM->TME && !context->ZBUF.ZMSK && !context->FRAME.FBMSK && context->TEST.ZTE)
);
if (PRIM->TME && m_context->FRAME.Block() == m_context->TEX0.TBP0 && (m_vt.m_primclass == GS_SPRITE_CLASS)) {
// Special post-processing effect
GSVector4 delta_p = m_vt.m_max.p - m_vt.m_min.p;
const bool draw_sprite_tex = PRIM->TME && (m_vt.m_primclass == GS_SPRITE_CLASS);
const GSVector4 delta_p = m_vt.m_max.p - m_vt.m_min.p;
bool single_page = (delta_p.x <= 64.0f) && (delta_p.y <= 64.0f);
if (m_channel_shuffle) {
m_channel_shuffle = draw_sprite_tex && (m_context->TEX0.PSM == PSM_PSMT8) && single_page;
if (m_channel_shuffle) {
GL_INS("Channel shuffle effect detected SKIP");
GL_POP();
s_n += 3; // Keep it sync with SW renderer
return;
}
} else if (draw_sprite_tex && m_context->FRAME.Block() == m_context->TEX0.TBP0) {
// Special post-processing effect
if (m_vertex.next == 4) {
// Note potentially we could also check the content of vertex (2nd
// sprite must be half of the first one)
GL_INS("Double downscale effect detected");
m_double_downscale = true;
} else if ((m_context->TEX0.PSM == PSM_PSMT8) && (delta_p.x <= 64.0f) && (delta_p.y <= 32.0f)) {
//fprintf(stderr, "delta_p %f %f\n", delta_p.x, delta_p.y);
} else if ((m_context->TEX0.PSM == PSM_PSMT8) && single_page) {
if (m_channel_shuffle) {
GL_INS("Channel shuffle effect detected SKIP");
GL_POP();
@ -465,10 +474,17 @@ void GSRendererHW::Draw()
//
// Both input and output are 16 bits and texture was initially 32 bits!
m_texture_shuffle = (GSLocalMemory::m_psm[context->FRAME.PSM].bpp == 16) && (tex_psm.bpp == 16)
&& (m_vt.m_primclass == GS_SPRITE_CLASS) && tex->m_32_bits_fmt;
&& draw_sprite_tex && tex->m_32_bits_fmt;
// Texture shuffle is not yet supported with strange clamp mode
ASSERT(!m_texture_shuffle || (context->CLAMP.WMS < 3 && context->CLAMP.WMT < 3));
if (tex->m_target && m_context->TEX0.PSM == PSM_PSMT8 && single_page && draw_sprite_tex) {
GL_INS("Channel shuffle effect detected (2nd shot)");
m_channel_shuffle = true;
} else {
m_channel_shuffle = false;
}
}
if (rt) {
// Be sure texture shuffle detection is properly propagated
@ -578,7 +594,7 @@ void GSRendererHW::Draw()
context->ZBUF.ZMSK = zm != 0;
// A couple of hack to avoid upscaling issue. So far it seems to impacts mostly sprite
if ((m_upscale_multiplier > 1) && (m_vt.m_primclass == GS_SPRITE_CLASS)) {
if ((m_upscale_multiplier > 1) && draw_sprite_tex) {
size_t count = m_vertex.next;
GSVertex* v = &m_vertex.buff[0];

View File

@ -773,8 +773,12 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
// Pop
GL_INS("Red channel");
ps_sel.channel = 1;
} else if ((tex->m_texture->GetType() == GSTexture::DepthStencil) && !(tex->m_32_bits_fmt)) {
GL_INS("Urban Chaos Crazyness");
ps_sel.urban_chaos_hack = 1;
} else {
GL_INS("channel not supported");
m_channel_shuffle = false;
ASSERT(0);
}
dev->PSSetShaderResource(4, tex->m_from_target);
@ -981,10 +985,16 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
}
// Depth format
if (psm.depth) {
// Require a float conversion if the texure is a depth otherwise uses Integral scaling
if (tex->m_texture->GetType() == GSTexture::DepthStencil) {
// Require a float conversion if the texure is a depth format
ps_sel.depth_fmt = (psm.bpp == 16) ? 2 : 1;
// Don't force interpolation on depth format
bilinear &= m_vt.IsLinear();
} else if (psm.depth) {
// Use Integral scaling
ps_sel.depth_fmt = (tex->m_texture->GetType() != GSTexture::DepthStencil) ? 3 :
(psm.bpp == 16) ? 2 : 1;
// Don't force interpolation on depth format
bilinear &= m_vt.IsLinear();
}

View File

@ -85,12 +85,11 @@ void GSTextureCache::RemoveAll()
}
}
GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r)
GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, bool palette)
{
if (!CanConvertDepth()) return NULL;
if(GSLocalMemory::m_psm[TEX0.PSM].pal > 0)
m_renderer->m_mem.m_clut.Read32(TEX0, TEXA);
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
Source* src = NULL;
Target* dst = NULL;
@ -98,6 +97,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0
// Check only current frame, I guess it is only used as a postprocessing effect
uint32 bp = TEX0.TBP0;
uint32 psm = TEX0.PSM;
for(auto t : m_dst[DepthStencil]) {
if(!t->m_age && t->m_used && t->m_dirty.empty() && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM))
{
@ -122,23 +122,32 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0
if (dst) {
GL_CACHE("TC depth: dst %s hit: %d (0x%x, F:0x%x)", to_string(dst->m_type),
dst->m_texture ? dst->m_texture->GetID() : 0,
TEX0.TBP0, TEX0.PSM);
TEX0.TBP0, psm);
// Create a shared texture source
src = new Source(m_renderer, TEX0, TEXA, m_temp, true);
src->m_texture = dst->m_texture;
src->m_shared_texture = true;
src->m_target = true; // So renderer can check if a conversion is required
src->m_from_target = dst->m_texture; // avoid complex condition on the renderer
src->m_32_bits_fmt = dst->m_32_bits_fmt;
// Insert the texture in the hash set to keep track of it. But don't bother with
// texture cache list. It means that a new Source is created everytime we need it.
// If it is too expensive, one could cut memory allocation in Source constructor for this
// use case.
if (palette) {
const uint32* clut = m_renderer->m_mem.m_clut;
int size = psm_s.pal * sizeof(clut[0]);
src->m_palette = m_renderer->m_dev->CreateTexture(256, 1);
src->m_palette->Update(GSVector4i(0, 0, psm_s.pal, 1), clut, size);
src->m_initpalette = false;
}
m_src.m_surfaces.insert(src);
} else {
GL_CACHE("TC depth: ERROR miss (0x%x, F:0x%x)", TEX0.TBP0, TEX0.PSM);
GL_CACHE("TC depth: ERROR miss (0x%x, F:0x%x)", TEX0.TBP0, psm);
// Possible ? In this case we could call LookupSource
// Or just put a basic texture
// src->m_texture = m_renderer->m_dev->CreateTexture(tw, th);
@ -156,12 +165,12 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0
GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r)
{
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM];
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
//const GSLocalMemory::psm_t& cpsm = psm.pal > 0 ? GSLocalMemory::m_psm[TEX0.CPSM] : psm;
// Until DX is fixed
if (s_IS_OPENGL) {
if(psm.pal > 0)
if(psm_s.pal > 0)
m_renderer->m_mem.m_clut.Read32(TEX0, TEXA);
} else {
GIFRegTEXA plainTEXA;
@ -188,16 +197,16 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
// Target are converted (AEM & palette) on the fly by the GPU. They don't need extra check
if (!s->m_target) {
// We request a palette texture (psm.pal). If the texture was
// We request a palette texture (psm_s.pal). If the texture was
// converted by the CPU (s->m_palette == NULL), we need to ensure
// palette content is the same.
// Note: content of the palette will be uploaded at the end of the function
if (psm.pal > 0 && s->m_palette == NULL && !GSVector4i::compare64(clut, s->m_clut, psm.pal * sizeof(clut[0])))
if (psm_s.pal > 0 && s->m_palette == NULL && !GSVector4i::compare64(clut, s->m_clut, psm_s.pal * sizeof(clut[0])))
continue;
// We request a 24/16 bit RGBA texture. Alpha expansion was done by
// the CPU. We need to check that TEXA is identical
if (psm.pal == 0 && psm.fmt > 0 && s->m_TEXA.u64 != TEXA.u64)
if (psm_s.pal == 0 && psm_s.fmt > 0 && s->m_TEXA.u64 != TEXA.u64)
continue;
}
@ -295,14 +304,16 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
if(!t->m_age && t->m_used && t->m_dirty.empty() && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM))
{
GL_INS("TC: Warning depth format read as color format. Pixels will be scrambled");
//dst = t;
//break;
// Let's fetch a depth format texture. Rational, it will avoid the texture allocation and the
// rescaling of the current function.
GIFRegTEX0 depth_TEX0;
depth_TEX0.u32[0] = TEX0.u32[0] | (0x30u << 20u);
depth_TEX0.u32[1] = TEX0.u32[1];
return LookupDepthSource(depth_TEX0, TEXA, r);
if (psm_s.bpp > 8) {
GIFRegTEX0 depth_TEX0;
depth_TEX0.u32[0] = TEX0.u32[0] | (0x30u << 20u);
depth_TEX0.u32[1] = TEX0.u32[1];
return LookupDepthSource(depth_TEX0, TEXA, r);
} else {
return LookupDepthSource(TEX0, TEXA, r, true);
}
}
}
}
@ -334,11 +345,11 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
if (src->m_palette)
{
int size = psm.pal * sizeof(clut[0]);
int size = psm_s.pal * sizeof(clut[0]);
if(src->m_initpalette || !GSVector4i::update(src->m_clut, clut, size))
{
src->m_palette->Update(GSVector4i(0, 0, psm.pal, 1), src->m_clut, size);
src->m_palette->Update(GSVector4i(0, 0, psm_s.pal, 1), src->m_clut, size);
src->m_initpalette = false;
}
}

View File

@ -149,7 +149,7 @@ public:
void RemovePartial();
Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r);
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r);
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, bool palette = false);
Target* LookupTarget(const GIFRegTEX0& TEX0, int w, int h, int type, bool used);
Target* LookupTarget(const GIFRegTEX0& TEX0, int w, int h, int real_h);

View File

@ -225,7 +225,21 @@ vec4 sample_depth(vec2 st)
ivec2 uv = ivec2(uv_f);
vec4 t;
#if PS_DEPTH_FMT == 1
#if PS_URBAN_CHAOS_HACK == 1
// Convert a GL_FLOAT32 to a special color format expected by the game
int depth = int(fetch_c(uv).r * exp2(32.0f));
// Convert lsb based on the palette
t = texelFetch(PaletteSampler, ivec2((depth & 0xFF), 0), 0);
// Msb is easier
float green = float((depth >> 8) & 0xFF) * 36.0f;
green = min(green, 255.0f);
t.g += green;
#elif PS_DEPTH_FMT == 1
// Based on ps_main11 of convert
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
@ -252,6 +266,7 @@ vec4 sample_depth(vec2 st)
#endif
// warning t ranges from 0 to 255
#if (PS_AEM_FMT == FMT_24)
t.a = ( (PS_AEM == 0) || any(bvec3(t.rgb)) ) ? 255.0f * TA.x : 0.0f;
@ -266,27 +281,47 @@ vec4 sample_depth(vec2 st)
//////////////////////////////////////////////////////////////////////
// Fetch a Single Channel
//////////////////////////////////////////////////////////////////////
int fetch_raw_depth()
{
return int(texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0).r * exp2(32.0f));
}
vec4 fetch_raw_color()
{
return texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0);
}
vec4 fetch_red()
{
vec4 rt = texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0);
#if PS_DEPTH_FMT == 1 || PS_DEPTH_FMT == 2
int depth = (fetch_raw_depth()) & 0xFF;
vec4 rt = vec4(depth) / 255.0f;
#else
vec4 rt = fetch_raw_color();
#endif
return sample_p(rt.r) * 255.0f;
}
vec4 fetch_blue()
{
vec4 rt = texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0);
#if PS_DEPTH_FMT == 1 || PS_DEPTH_FMT == 2
int depth = (fetch_raw_depth() >> 16) & 0xFF;
vec4 rt = vec4(depth) / 255.0f;
#else
vec4 rt = fetch_raw_color();
#endif
return sample_p(rt.b) * 255.0f;
}
vec4 fetch_green()
{
vec4 rt = texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0);
vec4 rt = fetch_raw_color();
return sample_p(rt.g) * 255.0f;
}
vec4 fetch_alpha()
{
vec4 rt = texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0);
vec4 rt = fetch_raw_color();
return sample_p(rt.a) * 255.0f;
}

View File

@ -1069,7 +1069,21 @@ static const char* const tfx_fs_all_glsl =
" ivec2 uv = ivec2(uv_f);\n"
"\n"
" vec4 t;\n"
"#if PS_DEPTH_FMT == 1\n"
"#if PS_URBAN_CHAOS_HACK == 1\n"
" // Convert a GL_FLOAT32 to a special color format expected by the game\n"
" int depth = int(fetch_c(uv).r * exp2(32.0f));\n"
"\n"
" // Convert lsb based on the palette\n"
" t = texelFetch(PaletteSampler, ivec2((depth & 0xFF), 0), 0);\n"
"\n"
" // Msb is easier\n"
" float green = float((depth >> 8) & 0xFF) * 36.0f;\n"
" green = min(green, 255.0f);\n"
"\n"
" t.g += green;\n"
"\n"
"\n"
"#elif PS_DEPTH_FMT == 1\n"
" // Based on ps_main11 of convert\n"
"\n"
" // Convert a GL_FLOAT32 depth texture into a RGBA color texture\n"
@ -1096,6 +1110,7 @@ static const char* const tfx_fs_all_glsl =
"\n"
"#endif\n"
"\n"
"\n"
" // warning t ranges from 0 to 255\n"
"#if (PS_AEM_FMT == FMT_24)\n"
" t.a = ( (PS_AEM == 0) || any(bvec3(t.rgb)) ) ? 255.0f * TA.x : 0.0f;\n"
@ -1110,27 +1125,47 @@ static const char* const tfx_fs_all_glsl =
"//////////////////////////////////////////////////////////////////////\n"
"// Fetch a Single Channel\n"
"//////////////////////////////////////////////////////////////////////\n"
"int fetch_raw_depth()\n"
"{\n"
" return int(texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0).r * exp2(32.0f));\n"
"}\n"
"\n"
"vec4 fetch_raw_color()\n"
"{\n"
" return texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0);\n"
"}\n"
"\n"
"vec4 fetch_red()\n"
"{\n"
" vec4 rt = texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0);\n"
"#if PS_DEPTH_FMT == 1 || PS_DEPTH_FMT == 2\n"
" int depth = (fetch_raw_depth()) & 0xFF;\n"
" vec4 rt = vec4(depth) / 255.0f;\n"
"#else\n"
" vec4 rt = fetch_raw_color();\n"
"#endif\n"
" return sample_p(rt.r) * 255.0f;\n"
"}\n"
"\n"
"vec4 fetch_blue()\n"
"{\n"
" vec4 rt = texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0);\n"
"#if PS_DEPTH_FMT == 1 || PS_DEPTH_FMT == 2\n"
" int depth = (fetch_raw_depth() >> 16) & 0xFF;\n"
" vec4 rt = vec4(depth) / 255.0f;\n"
"#else\n"
" vec4 rt = fetch_raw_color();\n"
"#endif\n"
" return sample_p(rt.b) * 255.0f;\n"
"}\n"
"\n"
"vec4 fetch_green()\n"
"{\n"
" vec4 rt = texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0);\n"
" vec4 rt = fetch_raw_color();\n"
" return sample_p(rt.g) * 255.0f;\n"
"}\n"
"\n"
"vec4 fetch_alpha()\n"
"{\n"
" vec4 rt = texelFetch(RawTextureSampler, ivec2(gl_FragCoord.xy), 0);\n"
" vec4 rt = fetch_raw_color();\n"
" return sample_p(rt.a) * 255.0f;\n"
"}\n"
"\n"