pcsx2/plugins/GSdx/Renderers/HW/GSHwHack.cpp
lightningterror f54b79c274 gsdx-hw: Move GSC_XenosagaE3 crc hacks to Aggressive state.
It will allow D3D11 to render Texture shuffle effects.

Keep the crc hacks on aggressive instead of removing them as they might
still be useful.
2020-01-31 16:19:58 +01:00

1570 lines
44 KiB
C++

/*
* Copyright (C) 2007-2016 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSState.h"
#include "GSdx.h"
bool s_nativeres;
static CRCHackLevel s_crc_hack_level = CRCHackLevel::Full;
// hacks
#define Dx_and_OGL (s_crc_hack_level >= CRCHackLevel::Partial)
#define Dx_only (s_crc_hack_level >= CRCHackLevel::Full)
#define Aggressive (s_crc_hack_level >= CRCHackLevel::Aggressive)
CRC::Region g_crc_region = CRC::NoRegion;
////////////////////////////////////////////////////////////////////////////////
// Broken on both DirectX and OpenGL
// (note: could potentially work with latest OpenGL)
////////////////////////////////////////////////////////////////////////////////
bool GSC_BigMuthaTruckers(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.TBP0 == 0x01400 || fi.TBP0 == 0x012c0) && fi.FPSM == fi.TPSM && fi.TPSM == PSM_PSMCT16)
{
// Mid-texture pointer is a cache miss,
// luckily we replace a half-screen TS effect with a full-screen one in
// EmulateTextureShuffleAndFbmask (see #2934).
// While this works for the time being, it's not ideal.
// Skip the unneeded extra TS draw.
skip = 1;
}
}
return true;
}
bool GSC_Bully(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && !fi.TME && (fi.FBP == 0x02300 || fi.FBP == 0x02800) && fi.FPSM == PSM_PSMCT24)
{
// ntsc 0x02300, pal 0x02800
// Don't enable hack on native res if crc is below aggressive.
// Previous value 6, ntsc didn't like it.
skip = 8; // Upscaling blur/ghosting
}
}
return true;
}
bool GSC_DBZBT2(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && !fi.TME && (fi.FBP == 0x02a00 || fi.FBP == 0x03000) && fi.FPSM == PSM_PSMCT16)
{
// Character outlines.
// Glow/blur effect. Causes ghosting on upscaled resolution.
// Don't enable hack on native res if crc is below aggressive.
skip = 10;
}
}
return true;
}
bool GSC_DBZBT3(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && fi.TME && (fi.FBP == 0x03400 || fi.FBP == 0x02e00) && fi.FPSM == fi.TPSM && fi.TBP0 == 0x03f00 && fi.TPSM == PSM_PSMCT32)
{
// Ghosting/Blur effect. Upscaling issue.
// Can be fixed with TC X,Y offsets.
// Don't enable hack on native res if crc is below aggressive.
skip = 3;
}
}
return true;
}
bool GSC_DeathByDegreesTekkenNinaWilliams(const GSFrameInfo& fi, int& skip)
{
// Note: Game also has issues with texture shuffle not supported on strange clamp mode.
// See https://forums.pcsx2.net/Thread-GSDX-Texture-Cache-Bug-Report-Death-By-Degrees-SLUS-20934-NTSC
if(skip == 0)
{
if((Aggressive || !s_nativeres) && fi.TME && fi.FBP == 0 && fi.TBP0==0x34a0 && fi.TPSM == PSM_PSMCT32)
{
// Don't enable hack on native res if crc is below aggressive.
// Upscaling issue similar to Tekken 5.
skip = 1; // Animation pane
}
else if(Aggressive && fi.FBP == 0x3500 && fi.TPSM == PSM_PSMT8 && fi.FBMSK == 0xFFFF00FF)
{
// Needs to be further tested so put it on Aggressive for now, likely channel shuffle.
skip = 4; // Underwater white fog
}
}
else
{
if((Aggressive || !s_nativeres) && fi.TME && (fi.FBP | fi.TBP0 | fi.FPSM | fi.TPSM) && fi.FBMSK == 0x00FFFFFF)
{
// Needs to be further tested so assume it's related with the upscaling hack.
skip = 1; // Animation speed
}
}
return true;
}
bool GSC_GiTS(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x03000 && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT8)
{
// Channel effect not properly supported yet
skip = 9;
}
}
return true;
}
bool GSC_GodOfWar2(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(Aggressive && fi.TME && fi.FPSM == PSM_PSMCT16 && (fi.FBP == 0x00100 || fi.FBP == 0x02100) && (fi.TBP0 == 0x00100 || fi.TBP0 == 0x02100) && fi.TPSM == PSM_PSMCT16)
{
// Can be used as a speed hack.
// Removes shadows.
skip = 1000;
}
else if(Aggressive && fi.TME && fi.TPSM == PSM_PSMCT24 && fi.FBP == 0x1300 && (fi.TBP0 == 0x0F00 || fi.TBP0 == 0x1300 || fi.TBP0 == 0x2b00)) // || fi.FBP == 0x0100
{
// Upscaling hack maybe ? Needs to be verified, move it to Aggressive state just in case.
skip = 1; // global haze/halo
}
else if((Aggressive || !s_nativeres) && fi.TME && fi.TPSM == PSM_PSMCT24 && (fi.FBP == 0x0100 || fi.FBP == 0x2100) && (fi.TBP0 == 0x2b00 || fi.TBP0 == 0x2e80 || fi.TBP0 == 0x3100)) // 480P 2e80, interlaced 3100
{
// Upscaling issue.
// Don't enable hack on native res if crc is below aggressive.
skip = 1; // water effect and water vertical lines
}
}
else
{
if(Aggressive && fi.TME && (fi.FBP == 0x00100 || fi.FBP == 0x02100) && fi.FPSM == PSM_PSMCT16)
{
skip = 3;
}
}
return true;
}
bool GSC_WildArmsGames(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x03100 && fi.FPSM == PSM_PSMZ32 && fi.TBP0 == 0x01c00 && fi.TPSM == PSM_PSMZ32)
{
skip = 100;
}
}
else
{
if(fi.TME && fi.FBP == 0x00e00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x02a00 && fi.TPSM == PSM_PSMCT32)
{
skip = 1;
}
}
return true;
}
// Channel effect not properly supported yet
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)
{
skip = 640;
}
}
return true;
}
bool GSC_CrashBandicootWoC(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x008c0 || fi.FBP == 0x00a00) && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x008c0 || fi.TBP0 == 0x00a00) && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.FPSM == fi.TPSM)
{
return false; // allowed
}
if(fi.TME && (fi.FBP == 0x01e40 || fi.FBP == 0x02200) && fi.FPSM == PSM_PSMZ24 && (fi.TBP0 == 0x01180 || fi.TBP0 == 0x01400) && fi.TPSM == PSM_PSMZ24)
{
skip = 42;
}
}
else
{
if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x008c0 || fi.FBP == 0x00a00) && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03c00 && fi.TPSM == PSM_PSMCT32)
{
skip = 0;
}
else if(!fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x008c0 || fi.FBP == 0x00a00))
{
skip = 0;
}
}
return true;
}
bool GSC_SacredBlaze(const GSFrameInfo& fi, int& skip)
{
//Fix Sacred Blaze rendering glitches
if(skip == 0)
{
if(fi.TME && (fi.FBP==0x0000 || fi.FBP==0x0e00) && (fi.TBP0==0x2880 || fi.TBP0==0x2a80 ) && fi.FPSM==fi.TPSM && fi.TPSM == PSM_PSMCT32 && fi.FBMSK == 0x0)
{
skip = 1;
}
}
return true;
}
bool GSC_Spartan(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME)
{
// depth textures (bully, mgs3s1 intro, Front Mission 5)
if( (fi.TPSM == PSM_PSMZ32 || fi.TPSM == PSM_PSMZ24 || fi.TPSM == PSM_PSMZ16 || fi.TPSM == PSM_PSMZ16S) ||
// General, often problematic post processing
(GSUtil::HasSharedBits(fi.FBP, fi.FPSM, fi.TBP0, fi.TPSM)) )
{
skip = 2;
}
}
}
return true;
}
bool GSC_IkkiTousen(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && fi.TME && fi.FBP == 0x00700 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x01180 && fi.TPSM == PSM_PSMZ24)
{
// Might not be needed if any of the upscaling hacks fix the issues, needs to be further tested.
// Don't enable hack on native res if crc is below aggressive.
skip = 11; // Upscaling blur/ghosting
}
}
return true;
}
bool GSC_Onimusha3(const GSFrameInfo& fi, int& skip)
{
if(fi.TME /*&& (fi.FBP == 0x00000 || fi.FBP == 0x00700)*/ && (fi.TBP0 == 0x01180 || fi.TBP0 == 0x00e00 || fi.TBP0 == 0x01000 || fi.TBP0 == 0x01200) && (fi.TPSM == PSM_PSMCT32 || fi.TPSM == PSM_PSMCT24))
{
skip = 1;
}
return true;
}
bool GSC_Genji(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x01500 && fi.FPSM == PSM_PSMCT16 && fi.TBP0 == 0x00e00 && fi.TPSM == PSM_PSMZ16)
{
// likely fixed in openGL (texture shuffle)
// Missing block at the top left
if (Dx_only)
skip = 6;
else
return false;
}
else if(fi.TPSM == PSM_PSMCT24 && fi.TME ==0x0001 && fi.TBP0==fi.FBP)
{
skip = 1; // Blur
}
else if(fi.TPSM == PSM_PSMT8H && fi.FBMSK == 0)
{
skip = 1; // White Fog
}
}
return true;
}
bool GSC_EvangelionJo(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && fi.TME && fi.TBP0 == 0x2BC0 || (fi.FBP == 0 || fi.FBP == 0x1180) && (fi.FPSM | fi.TPSM) == 0)
{
// Don't enable hack on native res if crc is below aggressive.
// Removes blur/glow. Fixes ghosting when resolution is upscaled.
skip = 1;
}
}
return true;
}
bool GSC_Oneechanbara2Special(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && fi.TPSM == PSM_PSMCT24 && fi.TME && fi.FBP == 0x01180)
{
// Don't enable hack on native res if crc is below aggressive.
// Ghosting upscaling issue, bottom and right red lines also by upscaling.
skip = 1;
}
}
return true;
}
bool GSC_SakuraTaisen(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(!fi.TME && (fi.FBP == 0x0 || fi.FBP == 0x1180) && (fi.TBP0!=0x3fc0 && fi.TBP0!=0x3c9a && fi.TBP0 !=0x3dec /*fi.TBP0 ==0x38d0 || fi.TBP0==0x3912 ||fi.TBP0==0x3bdc ||fi.TBP0==0x3ab3 ||fi.TBP0<=0x3a92*/) && fi.FPSM == PSM_PSMCT32 && (fi.TPSM == PSM_PSMT8 || fi.TPSM == PSM_PSMT4) && (fi.FBMSK == 0x00FFFFFF || !fi.FBMSK))
{
skip = 0; //3dec 3fc0 3c9a
}
if(!fi.TME && (fi.FBP | fi.TBP0) !=0 && (fi.FBP | fi.TBP0) !=0x1180 && (fi.FBP | fi.TBP0) !=0x3be0 && (fi.FBP | fi.TBP0) !=0x3c80 && fi.TBP0!=0x3c9a && (fi.FBP | fi.TBP0) !=0x3d80 && fi.TBP0 !=0x3dec&& fi.FPSM == PSM_PSMCT32 && (fi.FBMSK==0))
{
skip =0; //3dec 3fc0 3c9a
}
if(!fi.TME && (fi.FBP | fi.TBP0) !=0 && (fi.FBP | fi.TBP0) !=0x1180 && (fi.FBP | fi.TBP0) !=0x3be0 && (fi.FBP | fi.TBP0) !=0x3c80 && (fi.FBP | fi.TBP0) !=0x3d80 && fi.TBP0!=0x3c9a && fi.TBP0 !=0x3de && fi.FPSM == PSM_PSMCT32 && (fi.FBMSK==0))
{
skip =1; //3dec 3fc0 3c9a
}
else if(fi.TME && (fi.FBP == 0 || fi.FBP == 0x1180) && fi.TBP0 == 0x35B8 && fi.TPSM == PSM_PSMT4)
{
skip = 1;
}
else
{
if(!fi.TME && (fi.FBP | fi.TBP0) ==0x38d0 && fi.FPSM == PSM_PSMCT32 )
{
skip = 1; //3dec 3fc0 3c9a
}
}
}
return true;
}
bool GSC_ShadowofRome(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.FBP && fi.TPSM == PSM_PSMT8H && ( fi.FBMSK ==0x00FFFFFF))
{
// Depth issues on all renders, white wall and white duplicate characters.
skip = 1;
}
else if(fi.TME ==0x0001 && (fi.TBP0==0x1300 || fi.TBP0==0x0f00) && fi.FBMSK>=0xFFFFFF)
{
// Cause a grey transparent wall (D3D) and a transparent vertical grey line (all renders) on the left side of the screen.
// Blur effect maybe ?
skip = 1;
}
else if(fi.TME && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 ==0x0160 ||fi.TBP0==0x01e0 || fi.TBP0<=0x0800) && fi.TPSM == PSM_PSMT8)
{
skip = 1; // Speedhack ?
}
}
return true;
}
bool GSC_SFEX3(const GSFrameInfo& fi, int& skip)
{
if (skip == 0)
{
if (fi.TME && fi.FBP == 0x00500 && fi.FPSM == PSM_PSMCT16 && fi.TBP0 == 0x00f00 && fi.TPSM == PSM_PSMCT16)
{
// Not an upscaling issue.
// Elements on the screen show double/distorted.
skip = 2;
}
}
return true;
}
bool GSC_TimeSplitters2(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00e00 || fi.FBP == 0x01000) && fi.FPSM == fi.TPSM && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x00e00 || fi.TBP0 == 0x01000) && fi.TPSM == PSM_PSMCT32 && fi.FBMSK == 0x0FF000000)
{
skip = 1;
}
}
return true;
}
bool GSC_LordOfTheRingsThirdAge(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(!fi.TME && fi.FBP == 0x03000 && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT4 && fi.FBMSK == 0xFF000000)
{
skip = 1000; //shadows
}
}
else
{
if (fi.TME && (fi.FBP == 0x0 || fi.FBP == 0x00e00 || fi.FBP == 0x01000) && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03000 && fi.TPSM == PSM_PSMCT24)
{
skip = 1;
}
}
return true;
}
bool GSC_Tekken5(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && fi.TME && (fi.FBP == 0x02d60 || fi.FBP == 0x02d80 || fi.FBP == 0x02ea0 || fi.FBP == 0x03620 || fi.FBP == 0x03640) && fi.FPSM == fi.TPSM && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32)
{
// Don't enable hack on native res if crc is below aggressive.
// Fixes/removes ghosting/blur effect and white lines appearing in stages: Moonfit Wilderness, Acid Rain - caused by upscaling.
// Downside is it also removes the channel effect which is fixed on OpenGL.
// Let's enable this hack for Aggressive only since it's an upscaling issue for both renders.
skip = 95;
}
else if(fi.TME && (fi.FBP == 0x02bc0 || fi.FBP == 0x02be0 || fi.FBP == 0x02d00 || fi.FBP == 0x03480 || fi.FBP == 0x034a0) && fi.FPSM == fi.TPSM && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32)
{
// The moving display effect(flames) is not emulated properly in the entire screen so let's remove the effect in the stage: Burning Temple. Related to half screen bottom issue.
// Fixes black lines in the stage: Burning Temple - caused by upscaling. Note the black lines can also be fixed with Merge Sprite hack.
skip = 2;
}
}
return true;
}
bool GSC_TombRaiderAnniversary(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x01000 && fi.FPSM == fi.TPSM && fi.TPSM == PSM_PSMCT32)
{
skip = 1; // Garbage TC
}
}
return true;
}
bool GSC_TombRaiderLegend(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
// ||fi.TBP0 ==0x2F00
if(fi.TME && fi.FBP == 0x01000 && fi.FPSM == fi.TPSM && fi.TPSM == PSM_PSMCT32 && (fi.TBP0 == 0x2b60 ||fi.TBP0 == 0x2b80 || fi.TBP0 == 0x2E60 ||fi.TBP0 ==0x3020 ||fi.TBP0 == 0x3200 || fi.TBP0 == 0x3320))
{
skip = 1; // Garbage TC
}
else if(fi.TPSM == PSM_PSMCT32 && (fi.TPSM | fi.FBP)==0x2fa0 && (fi.TBP0==0x2bc0 ) && fi.FBMSK ==0)
{
skip = 2; // Underwater black screen
}
}
return true;
}
bool GSC_TombRaiderUnderWorld(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x01000 && fi.FPSM == fi.TPSM && fi.TPSM == PSM_PSMCT32 && (fi.TBP0 == 0x2B60 /*|| fi.TBP0 == 0x2EFF || fi.TBP0 ==0x2F00 || fi.TBP0 == 0x3020*/ || fi.TBP0 >= 0x2C01 && fi.TBP0!=0x3029 && fi.TBP0!=0x302d))
{
skip = 1; // Garbage TC
}
else if(fi.TPSM == PSM_PSMCT32 && (fi.TPSM | fi.FBP)==0x2c00 && (fi.TBP0 ==0x0ee0) && fi.FBMSK ==0)
{
skip = 2; // Underwater black screen
}
}
return true;
}
bool GSC_DevilMayCry3(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x01800 && fi.FPSM == PSM_PSMCT16 && fi.TBP0 == 0x01000 && fi.TPSM == PSM_PSMZ16)
{
// Texture shuffle/depth not handled properly.
skip = 32;
}
if(fi.TME && fi.FBP == 0x01800 && fi.FPSM == PSM_PSMZ32 && fi.TBP0 == 0x0800 && fi.TPSM == PSM_PSMT8H)
{
skip = 16;
}
if(fi.TME && fi.FBP == 0x01800 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x0 && fi.TPSM == PSM_PSMT8H)
{
skip = 24;
}
}
return true;
}
bool GSC_BurnoutGames(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP == 0x01dc0 || fi.FBP == 0x01c00 || fi.FBP == 0x01f00 || fi.FBP == 0x01d40 || fi.FBP == 0x02200 || fi.FBP == 0x02000) && fi.FPSM == fi.TPSM && (fi.TBP0 == 0x01dc0 || fi.TBP0 == 0x01c00 || fi.TBP0 == 0x01f00 || fi.TBP0 == 0x01d40 || fi.TBP0 == 0x02200 || fi.TBP0 == 0x02000) && fi.TPSM == PSM_PSMCT32)
{
// 0x01dc0 01c00(MP) ntsc, 0x01f00 0x01d40(MP) ntsc progressive, 0x02200(MP) pal.
// Yellow stripes.
// Multiplayer tested only on Takedown.
skip = 4;
}
}
return true;
}
bool GSC_MidnightClub3(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP > 0x01d00 && fi.FBP <= 0x02a00) && fi.FPSM == PSM_PSMCT32 && (fi.FBP >= 0x01600 && fi.FBP < 0x03260) && fi.TPSM == PSM_PSMT8H)
{
// Vram usage.
// Tested: tokyo default cruise.
// Move around a bit, stop car, wait as vram goes down, start moving again, vram spike.
skip = 1;
}
}
return true;
}
bool GSC_TalesOfLegendia(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP == 0x3f80 || fi.FBP == 0x03fa0) && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT8)
{
skip = 3; // 3, 9
}
if(fi.TME && fi.FBP == 0x3800 && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMZ32)
{
skip = 2;
}
if(fi.TME && fi.FBP && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x3d80)
{
skip = 1; // Missing block 2a00 in the upper left
}
if(fi.TME && fi.FBP ==0x1c00 && (fi.TBP0==0x2e80 ||fi.TBP0==0x2d80) && fi.TPSM ==0 && fi.FBMSK == 0xff000000)
{
skip = 1; // Ghosting
}
if(!fi.TME && fi.FBP ==0x2a00 && (fi.TBP0==0x1C00 ) && fi.TPSM ==0 && fi.FBMSK == 0x00FFFFFF)
{
skip = 1; // Poisoned layer dislocation
}
}
return true;
}
bool GSC_Kunoichi(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(!fi.TME && (fi.FBP == 0x0 || fi.FBP == 0x00700 || fi.FBP == 0x00800) && fi.FPSM == PSM_PSMCT32 && fi.FBMSK == 0x00FFFFFF)
{
// Removes depth effects(shadows) not rendered correctly on all renders.
skip = 3;
}
if(fi.TME && (fi.FBP ==0x0700 || fi.FBP==0) && fi.TBP0==0x0e00 && fi.TPSM ==0 && fi.FBMSK == 0)
{
skip = 1; // Removes black screen (not needed anymore maybe)?
}
if(Aggressive && fi.TME)
{
// depth textures (bully, mgs3s1 intro, Front Mission 5)
if((fi.TPSM == PSM_PSMZ32 || fi.TPSM == PSM_PSMZ24 || fi.TPSM == PSM_PSMZ16 || fi.TPSM == PSM_PSMZ16S) ||
// General, often problematic post processing
(GSUtil::HasSharedBits(fi.FBP, fi.FPSM, fi.TBP0, fi.TPSM)) )
{
// Removes burning air effect, the effect causes major slowdowns.
skip = 1;
}
}
}
else
{
if(fi.TME && (fi.FBP == 0x0e00) && fi.FPSM == PSM_PSMCT32 && fi.FBMSK == 0xFF000000)
{
skip = 0;
}
}
return true;
}
bool GSC_ZettaiZetsumeiToshi2(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.TPSM == PSM_PSMCT16S && (fi.FBMSK >= 0x6FFFFFFF || fi.FBMSK ==0) )
{
skip = 1000;
}
else if(fi.TME && fi.TPSM == PSM_PSMCT32 && fi.FBMSK == 0xFF000000)
{
skip = 2; // Fog
}
else if((fi.FBP | fi.TBP0)&& fi.FPSM == fi.TPSM && fi.TPSM == PSM_PSMCT16 && fi.FBMSK == 0x3FFF)
{
// Note start of the effect (texture shuffle) is fixed in openGL but maybe not the extra draw
// call....
skip = 1000;
}
}
else
{
if(!fi.TME && fi.TPSM == PSM_PSMCT32 && fi.FBP==0x1180 && fi.TBP0==0x1180 && (fi.FBMSK ==0))
{
skip = 0;
}
if(fi.TME && fi.TPSM == PSM_PSMT4 && fi.FBP && (fi.TBP0!=0x3753))
{
skip = 0;
}
if(fi.TME && fi.TPSM == PSM_PSMT8H && fi.FBP ==0x22e0 && fi.TBP0 ==0x36e0 )
{
skip = 0;
}
if(!fi.TME && fi.TPSM == PSM_PSMT8H && fi.FBP ==0x22e0 )
{
skip = 0;
}
if(fi.TME && fi.TPSM == PSM_PSMT8 && (fi.FBP==0x1180 || fi.FBP==0) && (fi.TBP0 !=0x3764 && fi.TBP0!=0x370f))
{
skip = 0;
}
if(fi.TME && fi.TPSM == PSM_PSMCT16S && (fi.FBP==0x1180 ))
{
skip = 2;
}
}
return true;
}
bool GSC_SakuraWarsSoLongMyLove(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME==0 && fi.FBP != fi.TBP0 && fi.TBP0 && fi.FBMSK == 0x00FFFFFF)
{
skip = 3; // Remove darkness
}
else if(fi.TME==0 && fi.FBP == fi.TBP0 && (fi.TBP0 ==0x1200 ||fi.TBP0 ==0x1180 ||fi.TBP0 ==0) && fi.FBMSK == 0x00FFFFFF)
{
skip = 3; // Remove darkness
}
else if(fi.TME && (fi.FBP ==0 || fi.FBP ==0x1180) && fi.FPSM == PSM_PSMCT32 && fi.TBP0 ==0x3F3F && fi.TPSM == PSM_PSMT8)
{
skip = 1; // Floodlight
}
}
return true;
}
bool GSC_FightingBeautyWulong(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && fi.TME && (fi.TBP0 ==0x0700 || fi.TBP0 ==0x0a80) && (fi.TPSM == PSM_PSMCT32 || fi.TPSM == PSM_PSMCT24))
{
// Don't enable hack on native res if crc is below aggressive.
// removes glow/blur which cause ghosting and other sprite issues similar to Tekken 5
skip = 1;
}
}
return true;
}
bool GSC_GodHand(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP ==0x0) && (fi.TBP0 ==0x2800) && fi.FPSM == fi.TPSM && fi.TPSM == PSM_PSMCT32)
{
skip = 1; // Blur
}
}
return true;
}
bool GSC_KnightsOfTheTemple2(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TPSM == PSM_PSMT8H && fi.FBMSK == 0)
{
skip = 1; // Ghosting
}
else if(fi.TPSM ==0x00000 && PSM_PSMCT24 && fi.TME && (fi.FBP ==0x3400 ||fi.FBP==0x3a00))
{
skip = 1 ; // Light source
}
}
return true;
}
bool GSC_UltramanFightingEvolution(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && fi.TME && fi.FBP==0x2a00 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x1c00 && fi.TPSM == PSM_PSMZ24)
{
// Don't enable hack on native res if crc is below aggressive.
skip = 5; // blur
}
}
return true;
}
bool GSC_TalesofSymphonia(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x2bc0 || fi.TBP0 <= 0x0200) && (fi.FBMSK==0xFF000000 ||fi.FBMSK==0x00FFFFFF))
{
skip = 1; //fi.FBMSK==0 Causing an animated black screen to speed up the battle
}
if(fi.TME && (fi.TBP0==0x1180 || fi.TBP0==0x1a40 || fi.TBP0==0x2300) && fi.FBMSK>=0xFF000000)
{
skip = 1; // Afterimage
}
}
return true;
}
bool GSC_Simple2000Vol114(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && fi.TME==0 && (fi.FBP==0x1500) && (fi.TBP0==0x2c97 || fi.TBP0==0x2ace || fi.TBP0==0x03d0 || fi.TBP0==0x2448) && (fi.FBMSK == 0x0000))
{
// Don't enable hack on native res if crc is below aggressive.
// Upscaling issues, removes glow/blur effect which fixes ghosting.
skip = 1;
}
if(fi.TME && (fi.FBP==0x0e00) && (fi.TBP0==0x1000) && (fi.FBMSK == 0x0000))
{
// Depth shadows, they don't work properly on OpenGL as well.
skip = 1;
}
}
return true;
}
bool GSC_UrbanReign(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP==0x0000 && fi.TBP0==0x3980 && fi.FPSM==fi.TPSM && fi.TPSM == PSM_PSMCT32 && fi.FBMSK == 0x0)
{
skip = 1; // Black shadow
}
}
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_SteambotChronicles(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
// Author: miseru99 on forums.pcsx2.net
if(fi.TME && fi.TPSM == PSM_PSMCT16S)
{
if(fi.FBP == 0x1180)
{
skip=1; // 1 deletes some of the glitched effects
}
else if(fi.FBP == 0)
{
skip=100; // deletes most others(too high deletes the buggy sea completely;c, too low causes glitches to be visible)
}
else if(Aggressive && fi.FBP != 0) // Aggressive CRC
{
skip=19; // "speedhack", makes the game very light, vaporized water can disappear when not looked at directly, possibly some interface still, other value to try: 6 breaks menu background, possibly nothing(?) during gameplay, but it's slower, hence not much of a speedhack anymore
}
}
}
return true;
}
bool GSC_YakuzaGames(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((Aggressive || !s_nativeres) && !fi.TME && (fi.FBP == 0x1c20 || fi.FBP == 0x1e20 || fi.FBP == 0x1620) && (fi.TBP0 == 0xe00 || fi.TBP0 == 0x1000 || fi.TBP0 == 0x800) && fi.TPSM == PSM_PSMZ24 && fi.FPSM == PSM_PSMCT32
/*&& fi.FBMSK == 0xffffff && fi.TZTST && !GSUtil::HasSharedBits(fi.FBP, fi.FPSM, fi.TBP0, fi.TPSM)*/)
{
// Don't enable hack on native res if crc is below aggressive.
// Upscaling issues, removes glow/blur effect which fixes ghosting.
skip = 3;
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Correctly emulated on OpenGL but can be used as potential speed hack
////////////////////////////////////////////////////////////////////////////////
bool GSC_GetaWayGames(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if((fi.FBP == 0 || fi.FBP == 0x1180 || fi.FBP == 0x1400) && fi.TPSM == PSM_PSMT8H && fi.FBMSK == 0)
{
skip = 1; // Removes fog wall.
}
}
return true;
}
bool GSC_StarOcean3(const GSFrameInfo& fi, int& skip)
{
// The game emulate a stencil buffer with the alpha channel of the RT
// The operation of the stencil is selected with the palette
// For example -1 wrap will be [240, 16, 32, 48 ....]
// i.e. p[A>>4] = (A - 16) % 256
//
// The fastest and accurate solution will be to replace this pseudo stencil
// by a dedicated GPU draw call
// 1/ Use future GPU capabilities to do a "kind" of SW blending
// 2/ Use a real stencil/atomic image, and then compute the RT alpha value
//
// Both of those solutions will increase code complexity (and only avoid upscaling
// glitches)
if(skip == 0)
{
if(fi.TME && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT4HH)
{
skip = 1000; //
}
}
else
{
if(!(fi.TME && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT4HH))
{
skip = 0;
}
}
return true;
}
bool GSC_ValkyrieProfile2(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
/*if(fi.TME && (fi.FBP == 0x018c0 || fi.FBP == 0x02180) && fi.FPSM == fi.TPSM && fi.TBP0 >= 0x03200 && fi.TPSM == PSM_PSMCT32) //NTSC only, !(fi.TBP0 == 0x03580 || fi.TBP0 == 0x03960)
{
skip = 1; //red garbage in lost forest, removes other effects...
}
if(fi.TME && fi.FPSM == fi.TPSM && fi.TPSM == PSM_PSMCT16 && fi.FBMSK == 0x03FFF)
{
skip = 1; // //garbage in cutscenes, doesn't remove completely.
}*/
if(fi.TME && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT4HH)
{
// GH: Hack is quite similar to GSC_StarOcean3. It is potentially the same issue.
skip = 1000; //
}
}
else
{
if(!(fi.TME && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT4HH))
{
skip = 0;
}
}
return true;
}
bool GSC_RadiataStories(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT4HH)
{
// GH: Hack is quite similar to GSC_StarOcean3. It is potentially the same issue.
skip = 1000;
}
}
else
{
if(!(fi.TME && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT4HH))
{
skip = 0;
}
}
return true;
}
bool GSC_TenchuGames(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.TPSM == PSM_PSMZ16 && fi.FPSM == PSM_PSMCT16 && fi.FBMSK == 0x03FFF)
{
// Depth is fine, blending issues remain, crc hack can be adjusted to skip blend wall/fog only.
skip = 3;
}
}
return true;
}
bool GSC_SlyGames(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FPSM == fi.TPSM && (fi.FBP == 0x00000 || fi.FBP == 0x00700 || fi.FBP == 0x00800 || fi.FBP == 0x008c0 || fi.FBP == 0x00a80 || fi.FBP == 0x00e00) && fi.TPSM == PSM_PSMCT16 && fi.FBMSK == 0x03FFF)
// 0x00a80, 0x00e00 from Sly 3
{
// Upscaling issue with texture shuffle on dx and gl. Also removes shadows on gl.
skip = 1000;
}
}
else
{
if(fi.TME && fi.FPSM == fi.TPSM && fi.TPSM == PSM_PSMCT16 && fi.FBMSK == 0x03FFF)
{
skip = 3;
}
}
return true;
}
bool GSC_Grandia3(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && (fi.FBP ==0x0 || fi.FBP ==0x0e00) && (fi.TBP0 ==0x2a00 ||fi.TBP0==0x0e00 ||fi.TBP0==0) && fi.FPSM == fi.TPSM && fi.TPSM == PSM_PSMCT32)
{
skip = 1; // Blur
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Aggressive only hack
////////////////////////////////////////////////////////////////////////////////
bool GSC_AceCombat4(const GSFrameInfo& fi, int& skip)
{
// Removes clouds for a good speed boost, removes both 3D clouds(invisible with Hardware renderers, but cause slowdown) and 2D background clouds.
// Removes blur from player airplane.
// This hack also removes rockets, shows explosions(invisible without CRC hack) as garbage data,
// causes flickering issues with the HUD, and in some (night) missions removes the HUD altogether.
if (skip == 0)
{
if (fi.TME && fi.FBP == 0x02a00 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x01600 && fi.TPSM == PSM_PSMZ24)
{
skip = 71; // clouds (z, 16-bit)
}
}
return true;
}
bool GSC_BleachBladeBattlers(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x01180 && fi.FPSM == fi.TPSM && fi.TBP0 == 0x03fc0 && fi.TPSM == PSM_PSMCT32)
{
// Removes body shading. Not needed but offers a very decent speed boost.
skip = 1;
}
}
return true;
}
bool GSC_GodOfWar(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x00000 && fi.FPSM == PSM_PSMCT16 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT16 && fi.FBMSK == 0x03FFF)
{
// Can be used as a speed hack.
// Removes shadows.
skip = 1000;
}
else if(fi.TME && fi.FBP == 0x00000 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32 && fi.FBMSK == 0xff000000)
{
// Upscaling hack maybe ? Needs to be verified, move it to Aggressive state just in case.
skip = 1; // blur
}
}
else
{
if(fi.TME && fi.FBP == 0x00000 && fi.FPSM == PSM_PSMCT16)
{
skip = 3;
}
}
return true;
}
template<uptr state_addr>
bool GSC_SMTNocturneDDS(const GSFrameInfo& fi, int& skip)
{
// stop the motion blur on the main character and
// smudge filter from being drawn on USA versions of
// Nocturne, Digital Devil Saga 1 and Digital Devil Saga 2
if(g_crc_region == CRC::US && skip == 0 && fi.TBP0 == 0xE00 && fi.TME)
{
// Note: it will crash if the core doesn't allocate the EE mem in 0x2000_0000 (unlikely but possible)
// Aggressive hacks are evil anyway
// Nocturne:
// -0x5900($gp), ref at 0x100740
const int state = *(int*)(state_addr);
if (state == 23 || state == 24 || state == 25)
skip = 1;
}
return true;
}
bool GSC_SoTC(const GSFrameInfo& fi, int& skip)
{
// Not needed anymore? What did it fix anyway? (rama)
if(skip == 0)
{
if(fi.TME /*&& fi.FBP == 0x03d80*/ && fi.FPSM == 0 && fi.TBP0 == 0x03fc0 && fi.TPSM == 1)
{
skip = 48; // Removes sky bloom
}
}
return true;
}
bool GSC_FFXGames(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME)
{
// depth textures (bully, mgs3s1 intro, Front Mission 5)
if( (fi.TPSM == PSM_PSMZ32 || fi.TPSM == PSM_PSMZ24 || fi.TPSM == PSM_PSMZ16 || fi.TPSM == PSM_PSMZ16S) ||
// General, often problematic post processing
(GSUtil::HasSharedBits(fi.FBP, fi.FPSM, fi.TBP0, fi.TPSM)) )
{
skip = 1;
}
}
}
return true;
}
bool GSC_Okami(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x00e00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32)
{
skip = 1000;
}
}
else
{
if(fi.TME && fi.FBP == 0x00e00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03800 && fi.TPSM == PSM_PSMT4)
{
skip = 0;
}
}
return true;
}
bool GSC_RedDeadRevolver(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.FBP == 0x03700 && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMCT24)
{
skip = 2; // Blur
}
}
return true;
}
bool GSC_ShinOnimusha(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TME && fi.FBP == 0x001000 && (fi.TBP0 ==0 || fi.TBP0 == 0x0800) && fi.TPSM == PSM_PSMT8H && fi.FBMSK == 0x00FFFFFF)
{
skip = 0; // Water ripple not needed ?
}
else if(fi.TPSM == PSM_PSMCT24 && fi.TME && fi.FBP == 0x01000) // || fi.FBP == 0x00000
{
skip = 28; //28 30 56 64
}
else if(fi.FBP && fi.TPSM == PSM_PSMT8H && fi.FBMSK == 0xFFFFFF)
{
skip = 0; //24 33 40 9
}
else if(fi.TPSM == PSM_PSMT8H && fi.FBMSK == 0xFF000000)
{
skip = 1; // White fog when picking up things
}
else if(fi.TME && (fi.TBP0 ==0x1400 || fi.TBP0 ==0x1000 ||fi.TBP0 == 0x1200) && (fi.TPSM == PSM_PSMCT32 || fi.TPSM == PSM_PSMCT24))
{
skip = 1; // Eliminate excessive flooding, water and other light and shadow
}
}
return true;
}
bool GSC_XenosagaE3(const GSFrameInfo& fi, int& skip)
{
if(skip == 0)
{
if(fi.TPSM == PSM_PSMT8H && fi.FBMSK >= 0xEFFFFFFF)
{
skip = 73; // Animation
}
else if(fi.TME && fi.FBP ==0x03800 && fi.TBP0 && fi.TPSM ==0 && fi.FBMSK == 0)
{
skip = 1; // Ghosting
}
else
{
if(fi.TME)
{
// depth textures (bully, mgs3s1 intro, Front Mission 5)
if( (fi.TPSM == PSM_PSMZ32 || fi.TPSM == PSM_PSMZ24 || fi.TPSM == PSM_PSMZ16 || fi.TPSM == PSM_PSMZ16S) ||
// General, often problematic post processing
(GSUtil::HasSharedBits(fi.FBP, fi.FPSM, fi.TBP0, fi.TPSM)) )
{
skip = 1;
}
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
#ifdef ENABLE_DYNAMIC_CRC_HACK
#include <sys/stat.h>
/***************************************************************************
AutoReloadLibrary : Automatically reloads a dll if the file was modified.
Uses a temporary copy of the watched dll such that the original
can be modified while the copy is loaded and used.
NOTE: The API is not platform specific, but current implementation is Win32.
***************************************************************************/
class AutoReloadLibrary
{
private:
std::string m_dllPath, m_loadedDllPath;
DWORD m_minMsBetweenProbes;
time_t m_lastFileModification;
DWORD m_lastProbe;
HMODULE m_library;
std::string GetTempName()
{
std::string result = m_loadedDllPath + ".tmp"; //default name
TCHAR tmpPath[MAX_PATH], tmpName[MAX_PATH];
DWORD ret = GetTempPath(MAX_PATH, tmpPath);
if(ret && ret <= MAX_PATH && GetTempFileName(tmpPath, TEXT("GSdx"), 0, tmpName))
result = tmpName;
return result;
};
void UnloadLib()
{
if( !m_library )
return;
FreeLibrary( m_library );
m_library = NULL;
// If can't delete (might happen when GSdx closes), schedule delete on reboot
if(!DeleteFile( m_loadedDllPath.c_str() ) )
MoveFileEx( m_loadedDllPath.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT );
}
public:
AutoReloadLibrary( const std::string dllPath, const int minMsBetweenProbes=100 )
: m_minMsBetweenProbes( minMsBetweenProbes )
, m_dllPath( dllPath )
, m_lastFileModification( 0 )
, m_lastProbe( 0 )
, m_library( 0 )
{};
~AutoReloadLibrary(){ UnloadLib(); };
// If timeout has ellapsed, probe the dll for change, and reload if it was changed.
// If it returns true, then the dll was freed/reloaded, and any symbol addresse previously obtained is now invalid and needs to be re-obtained.
// Overhead is very low when when probe timeout has not ellapsed, and especially if current timestamp is supplied as argument.
// Note: there's no relation between the file modification date and currentMs value, so it need'nt neccessarily be an actual timestamp.
// Note: isChanged is guarenteed to return true at least once
// (even if the file doesn't exist, at which case the following GetSymbolAddress will return NULL)
bool isChanged( const DWORD currentMs=0 )
{
DWORD current = currentMs? currentMs : GetTickCount();
if( current >= m_lastProbe && ( current - m_lastProbe ) < m_minMsBetweenProbes )
return false;
bool firstTime = !m_lastProbe;
m_lastProbe = current;
struct stat s;
if( stat( m_dllPath.c_str(), &s ) )
{
// File doesn't exist or other error, unload dll
bool wasLoaded = m_library?true:false;
UnloadLib();
return firstTime || wasLoaded; // Changed if previously loaded or the first time accessing this method (and file doesn't exist)
}
if( m_lastFileModification == s.st_mtime )
return false;
m_lastFileModification = s.st_mtime;
// File modified, reload
UnloadLib();
if( !CopyFile( m_dllPath.c_str(), ( m_loadedDllPath = GetTempName() ).c_str(), false ) )
return true;
m_library = LoadLibrary( m_loadedDllPath.c_str() );
return true;
};
// Return value is NULL if the dll isn't loaded (failure or doesn't exist) or if the symbol isn't found.
void* GetSymbolAddress( const char* name ){ return m_library? GetProcAddress( m_library, name ) : NULL; };
};
// Use DynamicCrcHack function from a dll which can be modified while GSdx/PCSX2 is running.
// return value is true if the call succeeded or false otherwise (If the hack could not be invoked: no dll/function/etc).
// result contains the result of the hack call.
typedef uint32 (__cdecl* DynaHackType)(uint32, uint32, uint32, uint32, uint32, uint32, uint32, int32*, uint32, int32);
typedef uint32 (__cdecl* DynaHackType2)(uint32, uint32, uint32, uint32, uint32, uint32, uint32, int32*, uint32, int32, uint32); // Also accept CRC
bool IsInvokedDynamicCrcHack( GSFrameInfo &fi, int& skip, int region, bool &result, uint32 crc )
{
static AutoReloadLibrary dll( DYNA_DLL_PATH );
static DynaHackType dllFunc = NULL;
static DynaHackType2 dllFunc2 = NULL;
if( dll.isChanged() )
{
dllFunc = (DynaHackType)dll.GetSymbolAddress( "DynamicCrcHack" );
dllFunc2 = (DynaHackType2)dll.GetSymbolAddress( "DynamicCrcHack2" );
printf( "GSdx: Dynamic CRC-hacks%s: %s\n",
((dllFunc && !dllFunc2)?" [Old dynaDLL - No CRC support]":""),
dllFunc? "Loaded OK (-> overriding internal hacks)" :
"Not available (-> using internal hacks)");
}
if( !dllFunc2 && !dllFunc )
return false;
int32 skip32 = skip;
bool hasSharedBits = GSUtil::HasSharedBits(fi.FBP, fi.FPSM, fi.TBP0, fi.TPSM);
if(dllFunc2)
result = dllFunc2( fi.FBP, fi.FPSM, fi.FBMSK, fi.TBP0, fi.TPSM, fi.TZTST, (uint32)fi.TME, &skip32, (uint32)region, (uint32)(hasSharedBits?1:0), crc )?true:false;
else
result = dllFunc( fi.FBP, fi.FPSM, fi.FBMSK, fi.TBP0, fi.TPSM, fi.TZTST, (uint32)fi.TME, &skip32, (uint32)region, (uint32)(hasSharedBits?1:0) )?true:false;
skip = skip32;
return true;
}
#endif
void GSState::SetupCrcHack()
{
GetSkipCount lut[CRC::TitleCount];
s_nativeres = m_nativeres;
s_crc_hack_level = m_crc_hack_level;
memset(lut, 0, sizeof(lut));
if (Dx_and_OGL) {
lut[CRC::CrashBandicootWoC] = GSC_CrashBandicootWoC;
lut[CRC::DevilMayCry3] = GSC_DevilMayCry3;
lut[CRC::GodHand] = GSC_GodHand;
lut[CRC::KnightsOfTheTemple2] = GSC_KnightsOfTheTemple2;
lut[CRC::Kunoichi] = GSC_Kunoichi;
lut[CRC::Manhunt2] = GSC_Manhunt2;
lut[CRC::MidnightClub3] = GSC_MidnightClub3;
lut[CRC::Onimusha3] = GSC_Onimusha3;
lut[CRC::SacredBlaze] = GSC_SacredBlaze;
lut[CRC::SakuraTaisen] = GSC_SakuraTaisen;
lut[CRC::SakuraWarsSoLongMyLove] = GSC_SakuraWarsSoLongMyLove;
lut[CRC::ShadowofRome] = GSC_ShadowofRome;
lut[CRC::Simple2000Vol114] = GSC_Simple2000Vol114;
lut[CRC::Spartan] = GSC_Spartan;
lut[CRC::SFEX3] = GSC_SFEX3;
lut[CRC::TalesOfLegendia] = GSC_TalesOfLegendia;
lut[CRC::TalesofSymphonia] = GSC_TalesofSymphonia;
lut[CRC::TimeSplitters2] = GSC_TimeSplitters2;
lut[CRC::TombRaiderAnniversary] = GSC_TombRaiderAnniversary;
lut[CRC::TombRaiderLegend] = GSC_TombRaiderLegend;
lut[CRC::TombRaiderUnderworld] = GSC_TombRaiderUnderWorld;
lut[CRC::UrbanReign] = GSC_UrbanReign;
lut[CRC::WildArms4] = GSC_WildArmsGames;
lut[CRC::WildArms5] = GSC_WildArmsGames;
lut[CRC::ZettaiZetsumeiToshi2] = GSC_ZettaiZetsumeiToshi2;
// Channel Effect
lut[CRC::GiTS] = GSC_GiTS;
lut[CRC::SkyGunner] = GSC_SkyGunner; // Maybe not a channel effect
lut[CRC::SteambotChronicles] = GSC_SteambotChronicles;
// Colclip not supported
lut[CRC::LordOfTheRingsThirdAge] = GSC_LordOfTheRingsThirdAge;
// Depth Issue
lut[CRC::BurnoutDominator] = GSC_BurnoutGames;
lut[CRC::BurnoutRevenge] = GSC_BurnoutGames;
lut[CRC::BurnoutTakedown] = GSC_BurnoutGames;
// Half Screen bottom issue
lut[CRC::Tekken5] = GSC_Tekken5;
// Needs testing
lut[CRC::Genji] = GSC_Genji;
// Texture shuffle
lut[CRC::BigMuthaTruckers] = GSC_BigMuthaTruckers;
lut[CRC::DeathByDegreesTekkenNinaWilliams] = GSC_DeathByDegreesTekkenNinaWilliams; // + Upscaling issues
// Upscaling hacks
lut[CRC::Bully] = GSC_Bully;
lut[CRC::DBZBT2] = GSC_DBZBT2;
lut[CRC::DBZBT3] = GSC_DBZBT3;
lut[CRC::EvangelionJo] = GSC_EvangelionJo;
lut[CRC::FightingBeautyWulong] = GSC_FightingBeautyWulong;
lut[CRC::GodOfWar2] = GSC_GodOfWar2;
lut[CRC::IkkiTousen] = GSC_IkkiTousen;
lut[CRC::Oneechanbara2Special] = GSC_Oneechanbara2Special;
lut[CRC::UltramanFightingEvolution] = GSC_UltramanFightingEvolution;
lut[CRC::Yakuza] = GSC_YakuzaGames;
lut[CRC::Yakuza2] = GSC_YakuzaGames;
}
// Hacks that were fixed on OpenGL
if (Dx_only) {
// Accurate Blending
lut[CRC::GetaWay] = GSC_GetaWayGames; // Blending High
lut[CRC::GetaWayBlackMonday] = GSC_GetaWayGames; // Blending High
lut[CRC::TenchuFS] = GSC_TenchuGames;
lut[CRC::TenchuWoH] = GSC_TenchuGames;
lut[CRC::Sly2] = GSC_SlyGames; // SW blending on fbmask + Upscaling issue
lut[CRC::Sly3] = GSC_SlyGames; // SW blending on fbmask + Upscaling issue
// Needs testing
lut[CRC::Grandia3] = GSC_Grandia3;
// These games emulate a stencil buffer with the alpha channel of the RT (too slow to move to Aggressive)
// Needs at least Basic Blending,
// see https://github.com/PCSX2/pcsx2/pull/2921
lut[CRC::RadiataStories] = GSC_RadiataStories;
lut[CRC::StarOcean3] = GSC_StarOcean3;
lut[CRC::ValkyrieProfile2] = GSC_ValkyrieProfile2;
}
if (Aggressive) {
lut[CRC::AceCombat4] = GSC_AceCombat4;
lut[CRC::BleachBladeBattlers] = GSC_BleachBladeBattlers;
lut[CRC::FFX2] = GSC_FFXGames;
lut[CRC::FFX] = GSC_FFXGames;
lut[CRC::FFXII] = GSC_FFXGames;
lut[CRC::RedDeadRevolver] = GSC_RedDeadRevolver;
lut[CRC::ShinOnimusha] = GSC_ShinOnimusha;
lut[CRC::SMTDDS1] = GSC_SMTNocturneDDS<0x203BA820>;
lut[CRC::SMTDDS2] = GSC_SMTNocturneDDS<0x20435BF0>;
lut[CRC::SMTNocturne] = GSC_SMTNocturneDDS<0x2054E870>;
lut[CRC::SoTC] = GSC_SoTC;
lut[CRC::XenosagaE3] = GSC_XenosagaE3;
// Upscaling issues
lut[CRC::GodOfWar] = GSC_GodOfWar;
lut[CRC::Okami] = GSC_Okami;
}
m_gsc = lut[m_game.title];
g_crc_region = m_game.region;
}
#undef Dx_and_OGL
#undef Dx_only
#undef Aggressive
bool GSState::IsBadFrame()
{
GSFrameInfo fi;
fi.FBP = m_context->FRAME.Block();
fi.FPSM = m_context->FRAME.PSM;
fi.FBMSK = m_context->FRAME.FBMSK;
fi.TME = PRIM->TME;
fi.TBP0 = m_context->TEX0.TBP0;
fi.TPSM = m_context->TEX0.PSM;
fi.TZTST = m_context->TEST.ZTST;
#ifdef ENABLE_DYNAMIC_CRC_HACK
bool res=false; if(IsInvokedDynamicCrcHack(fi, m_skip, g_crc_region, res, m_crc)){ if( !res ) return false; } else
#endif
if(m_gsc && !m_gsc(fi, m_skip))
{
return false;
}
if(m_skip == 0 && (m_userhacks_skipdraw > 0) )
{
if(fi.TME)
{
// depth textures (bully, mgs3s1 intro, Front Mission 5)
// General, often problematic post processing
if (GSLocalMemory::m_psm[fi.TPSM].depth || GSUtil::HasSharedBits(fi.FBP, fi.FPSM, fi.TBP0, fi.TPSM))
{
m_skip_offset = m_userhacks_skipdraw_offset;
m_skip = std::max(m_userhacks_skipdraw, m_skip_offset);
}
}
}
if(m_skip > 0)
{
m_skip--;
if (m_skip_offset > 1)
m_skip_offset--;
else
return true;
}
return false;
}