diff --git a/plugins/GSdx/GSDeviceOGL.cpp b/plugins/GSdx/GSDeviceOGL.cpp index 10745619b8..26ca9bf17e 100644 --- a/plugins/GSdx/GSDeviceOGL.cpp +++ b/plugins/GSdx/GSDeviceOGL.cpp @@ -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) diff --git a/plugins/GSdx/GSDeviceOGL.h b/plugins/GSdx/GSDeviceOGL.h index 47d1bb87f7..d56ff8a3ba 100644 --- a/plugins/GSdx/GSDeviceOGL.h +++ b/plugins/GSdx/GSDeviceOGL.h @@ -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; diff --git a/plugins/GSdx/GSHwHack.cpp b/plugins/GSdx/GSHwHack.cpp index 5b68146092..9bc1476bd5 100644 --- a/plugins/GSdx/GSHwHack.cpp +++ b/plugins/GSdx/GSHwHack.cpp @@ -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; } } diff --git a/plugins/GSdx/GSRendererDX.cpp b/plugins/GSdx/GSRendererDX.cpp index 35d7e44812..b0a7baa82c 100644 --- a/plugins/GSdx/GSRendererDX.cpp +++ b/plugins/GSdx/GSRendererDX.cpp @@ -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()) diff --git a/plugins/GSdx/GSRendererHW.cpp b/plugins/GSdx/GSRendererHW.cpp index 51ed73bd31..6aa06cc50b 100644 --- a/plugins/GSdx/GSRendererHW.cpp +++ b/plugins/GSdx/GSRendererHW.cpp @@ -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]; diff --git a/plugins/GSdx/GSRendererOGL.cpp b/plugins/GSdx/GSRendererOGL.cpp index 5f50e8b041..1f514048e0 100644 --- a/plugins/GSdx/GSRendererOGL.cpp +++ b/plugins/GSdx/GSRendererOGL.cpp @@ -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(); } diff --git a/plugins/GSdx/GSTextureCache.cpp b/plugins/GSdx/GSTextureCache.cpp index 9c5cbcd584..4e5a0fe9d7 100644 --- a/plugins/GSdx/GSTextureCache.cpp +++ b/plugins/GSdx/GSTextureCache.cpp @@ -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; } } diff --git a/plugins/GSdx/GSTextureCache.h b/plugins/GSdx/GSTextureCache.h index 2b458d8966..52f0083f30 100644 --- a/plugins/GSdx/GSTextureCache.h +++ b/plugins/GSdx/GSTextureCache.h @@ -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); diff --git a/plugins/GSdx/res/glsl/tfx_fs.glsl b/plugins/GSdx/res/glsl/tfx_fs.glsl index 7681f73501..b7ca4c2d8f 100644 --- a/plugins/GSdx/res/glsl/tfx_fs.glsl +++ b/plugins/GSdx/res/glsl/tfx_fs.glsl @@ -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; } diff --git a/plugins/GSdx/res/glsl_source.h b/plugins/GSdx/res/glsl_source.h index 3030bc92b5..646b527218 100644 --- a/plugins/GSdx/res/glsl_source.h +++ b/plugins/GSdx/res/glsl_source.h @@ -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"