2010-04-25 00:31:27 +00:00
/*
2009-02-09 21:15:56 +00:00
* Copyright ( C ) 2007 - 2009 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 .
2010-04-25 00:31:27 +00:00
*
2009-02-09 21:15:56 +00:00
* 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 .
2010-04-25 00:31:27 +00:00
*
2009-02-09 21:15:56 +00:00
* You should have received a copy of the GNU General Public License
* along with GNU Make ; see the file COPYING . If not , write to
2010-04-25 00:31:27 +00:00
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2009-02-09 21:15:56 +00:00
* http : //www.gnu.org/copyleft/gpl.html
*
*/
# pragma once
# include "GSRenderer.h"
# include "GSTextureCache.h"
# include "GSCrc.h"
2009-07-12 13:46:05 +00:00
# include "GSFunctionMap.h"
2009-02-09 21:15:56 +00:00
2010-04-25 00:31:27 +00:00
template < class Vertex >
2009-05-22 01:22:52 +00:00
class GSRendererHW : public GSRendererT < Vertex >
2009-02-09 21:15:56 +00:00
{
int m_width ;
int m_height ;
int m_skip ;
bool m_reset ;
2011-02-19 03:36:30 +00:00
bool m_nativeres ;
int m_upscale_multiplier ;
int m_userhacks_skipdraw ;
2009-02-09 21:15:56 +00:00
2009-07-12 13:46:05 +00:00
# pragma region hacks
2009-07-22 14:28:14 +00:00
typedef bool ( GSRendererHW : : * OI_Ptr ) ( GSTexture * rt , GSTexture * ds , GSTextureCache : : Source * t ) ;
2009-07-12 13:46:05 +00:00
typedef void ( GSRendererHW : : * OO_Ptr ) ( ) ;
typedef bool ( GSRendererHW : : * CU_Ptr ) ( ) ;
2009-07-22 14:28:14 +00:00
bool OI_FFXII ( GSTexture * rt , GSTexture * ds , GSTextureCache : : Source * t )
2009-07-12 13:46:05 +00:00
{
static uint32 * video = NULL ;
2009-07-22 14:28:14 +00:00
static int lines = 0 ;
2009-07-12 13:46:05 +00:00
2009-07-22 14:28:14 +00:00
if ( lines = = 0 )
2009-07-12 13:46:05 +00:00
{
2009-07-22 14:28:14 +00:00
if ( m_vt . m_primclass = = GS_LINE_CLASS & & ( m_count = = 448 * 2 | | m_count = = 512 * 2 ) )
{
lines = m_count / 2 ;
}
}
else
{
if ( m_vt . m_primclass = = GS_POINT_CLASS )
{
if ( m_count > = 16 * 512 )
{
// incoming pixels are stored in columns, one column is 16x512, total res 448x512 or 448x454
2009-07-12 13:46:05 +00:00
2009-07-22 14:28:14 +00:00
if ( ! video ) video = new uint32 [ 512 * 512 ] ;
2009-07-12 13:46:05 +00:00
2009-07-22 14:28:14 +00:00
int ox = m_context - > XYOFFSET . OFX ;
int oy = m_context - > XYOFFSET . OFY ;
2009-07-12 13:46:05 +00:00
2009-07-22 14:28:14 +00:00
for ( int i = 0 ; i < m_count ; i + + )
2009-07-12 13:46:05 +00:00
{
2009-07-22 14:28:14 +00:00
int x = ( ( int ) m_vertices [ i ] . p . x - ox ) > > 4 ;
int y = ( ( int ) m_vertices [ i ] . p . y - oy ) > > 4 ;
// video[y * 448 + x] = m_vertices[i].c0;
2011-02-18 01:56:05 +00:00
video [ ( y < < 8 ) + ( y < < 7 ) + ( y < < 6 ) + x ] = m_vertices [ i ] . _c0 ( ) ;
2009-07-12 13:46:05 +00:00
}
2009-07-22 14:28:14 +00:00
return false ;
}
2010-04-25 00:31:27 +00:00
else
2009-07-22 14:28:14 +00:00
{
lines = 0 ;
2009-07-12 13:46:05 +00:00
}
}
2009-07-22 14:28:14 +00:00
else if ( m_vt . m_primclass = = GS_LINE_CLASS )
{
if ( m_count = = lines * 2 )
{
// normally, this step would copy the video onto screen with 512 texture mapped horizontal lines,
// but we use the stored video data to create a new texture, and replace the lines with two triangles
2009-07-12 13:46:05 +00:00
2009-07-22 14:28:14 +00:00
m_dev - > Recycle ( t - > m_texture ) ;
2009-07-12 13:46:05 +00:00
2009-07-22 14:28:14 +00:00
t - > m_texture = m_dev - > CreateTexture ( 512 , 512 ) ;
2009-07-12 13:46:05 +00:00
2009-07-22 14:28:14 +00:00
t - > m_texture - > Update ( GSVector4i ( 0 , 0 , 448 , lines ) , video , 448 * 4 ) ;
2009-07-12 13:46:05 +00:00
2009-07-22 14:28:14 +00:00
m_vertices [ 0 ] = m_vertices [ 0 ] ;
m_vertices [ 1 ] = m_vertices [ 1 ] ;
m_vertices [ 2 ] = m_vertices [ m_count - 2 ] ;
m_vertices [ 3 ] = m_vertices [ 1 ] ;
m_vertices [ 4 ] = m_vertices [ 2 ] ;
m_vertices [ 5 ] = m_vertices [ m_count - 1 ] ;
2009-07-12 13:46:05 +00:00
2009-07-22 14:28:14 +00:00
m_count = 6 ;
2009-07-12 13:46:05 +00:00
2009-07-22 14:28:14 +00:00
m_vt . Update ( m_vertices , m_count , GS_TRIANGLE_CLASS ) ;
}
2010-04-25 00:31:27 +00:00
else
2009-07-22 14:28:14 +00:00
{
lines = 0 ;
}
}
2009-07-12 13:46:05 +00:00
}
return true ;
}
2009-07-22 14:28:14 +00:00
bool OI_FFX ( GSTexture * rt , GSTexture * ds , GSTextureCache : : Source * t )
2009-07-12 13:46:05 +00:00
{
uint32 FBP = m_context - > FRAME . Block ( ) ;
uint32 ZBP = m_context - > ZBUF . Block ( ) ;
uint32 TBP = m_context - > TEX0 . TBP0 ;
if ( ( FBP = = 0x00d00 | | FBP = = 0x00000 ) & & ZBP = = 0x02100 & & PRIM - > TME & & TBP = = 0x01a00 & & m_context - > TEX0 . PSM = = PSM_PSMCT16S )
{
// random battle transition (z buffer written directly, clear it now)
m_dev - > ClearDepth ( ds , 0 ) ;
}
return true ;
}
2009-07-22 14:28:14 +00:00
bool OI_MetalSlug6 ( GSTexture * rt , GSTexture * ds , GSTextureCache : : Source * t )
2009-07-12 13:46:05 +00:00
{
// missing red channel fix
2010-04-25 00:31:27 +00:00
2009-07-12 13:46:05 +00:00
for ( int i = 0 , j = m_count ; i < j ; i + + )
{
2011-02-18 01:56:05 +00:00
if ( m_vertices [ i ] . _r ( ) = = 0 & & m_vertices [ i ] . _g ( ) ! = 0 & & m_vertices [ i ] . _b ( ) ! = 0 )
2009-07-12 13:46:05 +00:00
{
2011-02-18 01:56:05 +00:00
m_vertices [ i ] . _r ( ) = ( m_vertices [ i ] . _g ( ) + m_vertices [ i ] . _b ( ) ) / 2 ;
2009-07-12 13:46:05 +00:00
}
}
2009-07-22 14:28:14 +00:00
m_vt . Update ( m_vertices , m_count , m_vt . m_primclass ) ;
2009-07-12 13:46:05 +00:00
return true ;
}
2009-07-22 14:28:14 +00:00
bool OI_GodOfWar2 ( GSTexture * rt , GSTexture * ds , GSTextureCache : : Source * t )
2009-07-12 13:46:05 +00:00
{
uint32 FBP = m_context - > FRAME . Block ( ) ;
uint32 FBW = m_context - > FRAME . FBW ;
uint32 FPSM = m_context - > FRAME . PSM ;
if ( ( FBP = = 0x00f00 | | FBP = = 0x00100 ) & & FPSM = = PSM_PSMZ24 ) // ntsc 0xf00, pal 0x100
{
// z buffer clear
GIFRegTEX0 TEX0 ;
TEX0 . TBP0 = FBP ;
TEX0 . TBW = FBW ;
TEX0 . PSM = FPSM ;
if ( GSTextureCache : : Target * ds = m_tc - > LookupTarget ( TEX0 , m_width , m_height , GSTextureCache : : DepthStencil , true ) )
{
m_dev - > ClearDepth ( ds - > m_texture , 0 ) ;
}
return false ;
}
return true ;
}
2009-07-22 14:28:14 +00:00
bool OI_SimpsonsGame ( GSTexture * rt , GSTexture * ds , GSTextureCache : : Source * t )
2009-07-12 13:46:05 +00:00
{
uint32 FBP = m_context - > FRAME . Block ( ) ;
uint32 FBW = m_context - > FRAME . FBW ;
uint32 FPSM = m_context - > FRAME . PSM ;
if ( FBP = = 0x01800 & & FPSM = = PSM_PSMZ24 )
{
// instead of just simply drawing a full height 512x512 sprite to clear the z buffer,
// it uses a 512x256 sprite only, yet it is still able to fill the whole surface with zeros,
// how? by using a render target that overlaps with the lower half of the z buffer...
m_dev - > ClearDepth ( ds , 0 ) ;
return false ;
}
return true ;
}
2009-07-22 14:28:14 +00:00
bool OI_RozenMaidenGebetGarden ( GSTexture * rt , GSTexture * ds , GSTextureCache : : Source * t )
2009-07-12 13:46:05 +00:00
{
if ( ! PRIM - > TME )
{
uint32 FBP = m_context - > FRAME . Block ( ) ;
uint32 ZBP = m_context - > ZBUF . Block ( ) ;
if ( FBP = = 0x008c0 & & ZBP = = 0x01a40 )
{
// frame buffer clear, atst = fail, afail = write z only, z buffer points to frame buffer
GIFRegTEX0 TEX0 ;
TEX0 . TBP0 = ZBP ;
TEX0 . TBW = m_context - > FRAME . FBW ;
TEX0 . PSM = m_context - > FRAME . PSM ;
if ( GSTextureCache : : Target * rt = m_tc - > LookupTarget ( TEX0 , m_width , m_height , GSTextureCache : : RenderTarget , true ) )
{
m_dev - > ClearRenderTarget ( rt - > m_texture , 0 ) ;
}
return false ;
}
else if ( FBP = = 0x00000 & & m_context - > ZBUF . Block ( ) = = 0x01180 )
{
// z buffer clear, frame buffer now points to the z buffer (how can they be so clever?)
GIFRegTEX0 TEX0 ;
TEX0 . TBP0 = FBP ;
TEX0 . TBW = m_context - > FRAME . FBW ;
TEX0 . PSM = m_context - > ZBUF . PSM ;
if ( GSTextureCache : : Target * ds = m_tc - > LookupTarget ( TEX0 , m_width , m_height , GSTextureCache : : DepthStencil , true ) )
{
m_dev - > ClearDepth ( ds - > m_texture , 0 ) ;
}
return false ;
}
}
return true ;
}
2009-07-22 14:28:14 +00:00
bool OI_PointListPalette ( GSTexture * rt , GSTexture * ds , GSTextureCache : : Source * t )
2009-07-12 13:46:05 +00:00
{
2009-07-22 14:28:14 +00:00
if ( m_vt . m_primclass = = GS_POINT_CLASS & & ! PRIM - > TME )
2009-07-12 13:46:05 +00:00
{
uint32 FBP = m_context - > FRAME . Block ( ) ;
uint32 FBW = m_context - > FRAME . FBW ;
if ( FBP > = 0x03f40 & & ( FBP & 0x1f ) = = 0 )
{
if ( m_count = = 16 )
{
for ( int i = 0 ; i < 16 ; i + + )
{
2011-02-18 01:56:05 +00:00
uint8 a = m_vertices [ i ] . _a ( ) ;
2009-07-12 13:46:05 +00:00
2011-02-18 01:56:05 +00:00
m_vertices [ i ] . _a ( ) = a > = 0x80 ? 0xff : a * 2 ;
m_mem . WritePixel32 ( i & 7 , i > > 3 , m_vertices [ i ] . _c0 ( ) , FBP , FBW ) ;
2009-07-12 13:46:05 +00:00
}
m_mem . m_clut . Invalidate ( ) ;
return false ;
}
else if ( m_count = = 256 )
{
for ( int i = 0 ; i < 256 ; i + + )
{
2011-02-18 01:56:05 +00:00
uint8 a = m_vertices [ i ] . _a ( ) ;
m_vertices [ i ] . _a ( ) = a > = 0x80 ? 0xff : a * 2 ;
2009-07-12 13:46:05 +00:00
2011-02-18 01:56:05 +00:00
m_mem . WritePixel32 ( i & 15 , i > > 4 , m_vertices [ i ] . _c0 ( ) , FBP , FBW ) ;
2009-07-12 13:46:05 +00:00
}
m_mem . m_clut . Invalidate ( ) ;
return false ;
}
else
{
ASSERT ( 0 ) ;
}
}
}
return true ;
}
void OO_DBZBT2 ( )
{
// palette readback (cannot detect yet, when fetching the texture later)
uint32 FBP = m_context - > FRAME . Block ( ) ;
uint32 TBP0 = m_context - > TEX0 . TBP0 ;
if ( PRIM - > TME & & ( FBP = = 0x03c00 & & TBP0 = = 0x03c80 | | FBP = = 0x03ac0 & & TBP0 = = 0x03b40 ) )
{
GIFRegBITBLTBUF BITBLTBUF ;
BITBLTBUF . SBP = FBP ;
BITBLTBUF . SBW = 1 ;
BITBLTBUF . SPSM = PSM_PSMCT32 ;
InvalidateLocalMem ( BITBLTBUF , GSVector4i ( 0 , 0 , 64 , 64 ) ) ;
}
}
void OO_MajokkoALaMode2 ( )
{
// palette readback
uint32 FBP = m_context - > FRAME . Block ( ) ;
if ( ! PRIM - > TME & & FBP = = 0x03f40 )
{
GIFRegBITBLTBUF BITBLTBUF ;
BITBLTBUF . SBP = FBP ;
BITBLTBUF . SBW = 1 ;
BITBLTBUF . SPSM = PSM_PSMCT32 ;
InvalidateLocalMem ( BITBLTBUF , GSVector4i ( 0 , 0 , 16 , 16 ) ) ;
}
}
bool CU_DBZBT2 ( )
{
// palette should stay 64 x 64
uint32 FBP = m_context - > FRAME . Block ( ) ;
return FBP ! = 0x03c00 & & FBP ! = 0x03ac0 ;
}
bool CU_MajokkoALaMode2 ( )
{
// palette should stay 16 x 16
uint32 FBP = m_context - > FRAME . Block ( ) ;
return FBP ! = 0x03f40 ;
}
bool CU_TalesOfAbyss ( )
{
// full image blur and brightening
uint32 FBP = m_context - > FRAME . Block ( ) ;
return FBP ! = 0x036e0 & & FBP ! = 0x03560 & & FBP ! = 0x038e0 ;
}
class Hacks
{
2010-04-25 00:31:27 +00:00
template < class T > struct HackEntry
2009-07-12 13:46:05 +00:00
{
2010-04-25 00:31:27 +00:00
CRC : : Title title ;
CRC : : Region region ;
2009-07-12 13:46:05 +00:00
T func ;
struct HackEntry ( CRC : : Title t , CRC : : Region r , T f )
{
title = t ;
region = r ;
func = f ;
}
} ;
2010-04-25 00:31:27 +00:00
template < class T > class FunctionMap : public GSFunctionMap < uint32 , T >
2009-07-12 13:46:05 +00:00
{
list < HackEntry < T > > & m_tbl ;
T GetDefaultFunction ( uint32 key )
{
CRC : : Title title = ( CRC : : Title ) ( key & 0xffffff ) ;
CRC : : Region region = ( CRC : : Region ) ( key > > 24 ) ;
for ( list < HackEntry < T > > : : iterator i = m_tbl . begin ( ) ; i ! = m_tbl . end ( ) ; i + + )
{
if ( i - > title = = title & & ( i - > region = = CRC : : RegionCount | | i - > region = = region ) )
{
return i - > func ;
}
}
return NULL ;
}
public :
FunctionMap ( list < HackEntry < T > > & tbl ) : m_tbl ( tbl ) { }
} ;
list < HackEntry < OI_Ptr > > m_oi_list ;
list < HackEntry < OO_Ptr > > m_oo_list ;
list < HackEntry < CU_Ptr > > m_cu_list ;
FunctionMap < OI_Ptr > m_oi_map ;
FunctionMap < OO_Ptr > m_oo_map ;
FunctionMap < CU_Ptr > m_cu_map ;
public :
OI_Ptr m_oi ;
OO_Ptr m_oo ;
CU_Ptr m_cu ;
2010-04-25 00:31:27 +00:00
Hacks ( )
2009-07-12 13:46:05 +00:00
: m_oi_map ( m_oi_list )
, m_oo_map ( m_oo_list )
, m_cu_map ( m_cu_list )
2010-04-25 00:31:27 +00:00
, m_oi ( NULL )
, m_oo ( NULL )
2009-07-12 13:46:05 +00:00
, m_cu ( NULL )
{
m_oi_list . push_back ( HackEntry < OI_Ptr > ( CRC : : FFXII , CRC : : EU , & GSRendererHW : : OI_FFXII ) ) ;
m_oi_list . push_back ( HackEntry < OI_Ptr > ( CRC : : FFX , CRC : : RegionCount , & GSRendererHW : : OI_FFX ) ) ;
m_oi_list . push_back ( HackEntry < OI_Ptr > ( CRC : : MetalSlug6 , CRC : : RegionCount , & GSRendererHW : : OI_MetalSlug6 ) ) ;
m_oi_list . push_back ( HackEntry < OI_Ptr > ( CRC : : GodOfWar2 , CRC : : RegionCount , & GSRendererHW : : OI_GodOfWar2 ) ) ;
m_oi_list . push_back ( HackEntry < OI_Ptr > ( CRC : : SimpsonsGame , CRC : : RegionCount , & GSRendererHW : : OI_SimpsonsGame ) ) ;
m_oi_list . push_back ( HackEntry < OI_Ptr > ( CRC : : RozenMaidenGebetGarden , CRC : : RegionCount , & GSRendererHW : : OI_RozenMaidenGebetGarden ) ) ;
m_oo_list . push_back ( HackEntry < OO_Ptr > ( CRC : : DBZBT2 , CRC : : RegionCount , & GSRendererHW : : OO_DBZBT2 ) ) ;
m_oo_list . push_back ( HackEntry < OO_Ptr > ( CRC : : MajokkoALaMode2 , CRC : : RegionCount , & GSRendererHW : : OO_MajokkoALaMode2 ) ) ;
m_cu_list . push_back ( HackEntry < CU_Ptr > ( CRC : : DBZBT2 , CRC : : RegionCount , & GSRendererHW : : CU_DBZBT2 ) ) ;
m_cu_list . push_back ( HackEntry < CU_Ptr > ( CRC : : MajokkoALaMode2 , CRC : : RegionCount , & GSRendererHW : : CU_MajokkoALaMode2 ) ) ;
m_cu_list . push_back ( HackEntry < CU_Ptr > ( CRC : : TalesOfAbyss , CRC : : RegionCount , & GSRendererHW : : CU_TalesOfAbyss ) ) ;
}
void SetGame ( const CRC : : Game & game )
{
uint32 hash = ( uint32 ) ( ( game . region < < 24 ) | game . title ) ;
m_oi = m_oi_map [ hash ] ;
m_oo = m_oo_map [ hash ] ;
m_cu = m_cu_map [ hash ] ;
if ( game . flags & CRC : : PointListPalette )
{
ASSERT ( m_oi = = NULL ) ;
m_oi = & GSRendererHW : : OI_PointListPalette ;
}
}
} m_hacks ;
# pragma endregion
2009-02-09 21:15:56 +00:00
protected :
2009-05-22 01:22:52 +00:00
GSTextureCache * m_tc ;
2010-04-25 00:31:27 +00:00
void Reset ( )
2009-02-09 21:15:56 +00:00
{
// TODO: GSreset can come from the main thread too => crash
2010-05-23 17:26:37 +00:00
// m_tc->RemoveAll();
2009-02-09 21:15:56 +00:00
m_reset = true ;
__super : : Reset ( ) ;
}
void VSync ( int field )
{
__super : : VSync ( field ) ;
2010-04-25 00:31:27 +00:00
m_tc - > IncAge ( ) ;
2010-05-23 15:33:50 +00:00
m_dev - > AgePool ( ) ;
2009-02-09 21:15:56 +00:00
m_skip = 0 ;
if ( m_reset )
{
m_tc - > RemoveAll ( ) ;
m_reset = false ;
}
}
2010-05-23 15:33:50 +00:00
void InvalidateTextureCache ( )
{
m_tc - > RemoveAll ( ) ;
}
2010-04-25 00:31:27 +00:00
void ResetDevice ( )
2009-02-09 21:15:56 +00:00
{
2009-09-18 00:16:52 +00:00
__super : : ResetDevice ( ) ;
2009-02-09 21:15:56 +00:00
}
2009-05-22 01:22:52 +00:00
GSTexture * GetOutput ( int i )
2009-02-09 21:15:56 +00:00
{
2009-03-31 03:19:21 +00:00
const GSRegDISPFB & DISPFB = m_regs - > DISP [ i ] . DISPFB ;
2009-02-09 21:15:56 +00:00
GIFRegTEX0 TEX0 ;
2009-03-31 03:19:21 +00:00
TEX0 . TBP0 = DISPFB . Block ( ) ;
TEX0 . TBW = DISPFB . FBW ;
TEX0 . PSM = DISPFB . PSM ;
2009-02-09 21:15:56 +00:00
2009-05-22 23:23:38 +00:00
// TRACE(_T("[%d] GetOutput %d %05x (%d)\n"), (int)m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM);
2009-02-09 21:15:56 +00:00
2009-05-22 01:22:52 +00:00
GSTexture * t = NULL ;
2009-07-31 23:59:06 +00:00
if ( GSTextureCache : : Target * rt = m_tc - > LookupTarget ( TEX0 , m_width , m_height ) )
2009-02-09 21:15:56 +00:00
{
t = rt - > m_texture ;
if ( s_dump )
{
2010-04-25 00:31:27 +00:00
if ( s_save & & s_n > = s_saven )
2009-05-11 08:18:00 +00:00
{
2011-02-19 03:36:30 +00:00
t - > Save ( format ( " c: \\ temp2 \\ _%05d_f%lld_fr%d_%05x_%d.bmp " , s_n , m_perfmon . GetFrame ( ) , i , ( int ) TEX0 . TBP0 , ( int ) TEX0 . PSM ) ) ;
2009-05-11 08:18:00 +00:00
}
s_n + + ;
2009-02-09 21:15:56 +00:00
}
}
2009-05-22 01:22:52 +00:00
return t ;
2009-02-09 21:15:56 +00:00
}
2009-05-14 16:41:52 +00:00
void InvalidateVideoMem ( const GIFRegBITBLTBUF & BITBLTBUF , const GSVector4i & r )
2009-02-09 21:15:56 +00:00
{
2009-06-03 12:09:04 +00:00
// printf("[%d] InvalidateVideoMem %d,%d - %d,%d %05x (%d)\n", (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.DBP, (int)BITBLTBUF.DPSM);
2009-02-09 21:15:56 +00:00
2009-07-22 03:55:28 +00:00
m_tc - > InvalidateVideoMem ( m_mem . GetOffset ( BITBLTBUF . DBP , BITBLTBUF . DBW , BITBLTBUF . DPSM ) , r ) ;
2009-02-09 21:15:56 +00:00
}
2009-05-14 16:41:52 +00:00
void InvalidateLocalMem ( const GIFRegBITBLTBUF & BITBLTBUF , const GSVector4i & r )
2009-02-09 21:15:56 +00:00
{
2009-06-03 12:09:04 +00:00
// printf("[%d] InvalidateLocalMem %d,%d - %d,%d %05x (%d)\n", (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.SBP, (int)BITBLTBUF.SPSM);
2009-02-09 21:15:56 +00:00
2009-07-22 03:55:28 +00:00
m_tc - > InvalidateLocalMem ( m_mem . GetOffset ( BITBLTBUF . SBP , BITBLTBUF . SBW , BITBLTBUF . SPSM ) , r ) ;
2009-02-09 21:15:56 +00:00
}
void Draw ( )
{
2011-02-19 03:36:30 +00:00
if ( IsBadFrame ( m_skip , m_userhacks_skipdraw ) ) return ;
2010-04-25 00:31:27 +00:00
2009-02-09 21:15:56 +00:00
GSDrawingEnvironment & env = m_env ;
GSDrawingContext * context = m_context ;
GIFRegTEX0 TEX0 ;
TEX0 . TBP0 = context - > FRAME . Block ( ) ;
TEX0 . TBW = context - > FRAME . FBW ;
TEX0 . PSM = context - > FRAME . PSM ;
2009-06-27 03:32:33 +00:00
GSTextureCache : : Target * rt = m_tc - > LookupTarget ( TEX0 , m_width , m_height , GSTextureCache : : RenderTarget , true ) ;
2009-02-09 21:15:56 +00:00
TEX0 . TBP0 = context - > ZBUF . Block ( ) ;
TEX0 . TBW = context - > FRAME . FBW ;
TEX0 . PSM = context - > ZBUF . PSM ;
2009-06-27 03:32:33 +00:00
GSTextureCache : : Target * ds = m_tc - > LookupTarget ( TEX0 , m_width , m_height , GSTextureCache : : DepthStencil , m_context - > DepthWrite ( ) ) ;
2009-02-09 21:15:56 +00:00
2009-06-27 03:32:33 +00:00
GSTextureCache : : Source * tex = NULL ;
2009-02-09 21:15:56 +00:00
if ( PRIM - > TME )
{
2009-06-23 04:12:32 +00:00
m_mem . m_clut . Read32 ( context - > TEX0 , env . TEXA ) ;
GSVector4i r ;
2009-06-27 03:32:33 +00:00
GetTextureMinMax ( r , IsLinear ( ) ) ;
2009-06-23 04:12:32 +00:00
2009-06-27 03:32:33 +00:00
tex = m_tc - > LookupSource ( context - > TEX0 , env . TEXA , r ) ;
2009-02-09 21:15:56 +00:00
if ( ! tex ) return ;
}
if ( s_dump )
{
2009-05-15 11:11:26 +00:00
uint64 frame = m_perfmon . GetFrame ( ) ;
2009-05-11 08:18:00 +00:00
string s ;
2010-04-25 00:31:27 +00:00
if ( s_save & & s_n > = s_saven & & tex )
2009-05-11 08:18:00 +00:00
{
2011-02-19 03:36:30 +00:00
s = format ( " c: \\ temp2 \\ _%05d_f%lld_tex_%05x_%d_%d%d_%02x_%02x_%02x_%02x.dds " ,
2009-05-11 08:18:00 +00:00
s_n , frame , ( int ) context - > TEX0 . TBP0 , ( int ) context - > TEX0 . PSM ,
2010-04-25 00:31:27 +00:00
( int ) context - > CLAMP . WMS , ( int ) context - > CLAMP . WMT ,
( int ) context - > CLAMP . MINU , ( int ) context - > CLAMP . MAXU ,
2009-05-11 08:18:00 +00:00
( int ) context - > CLAMP . MINV , ( int ) context - > CLAMP . MAXV ) ;
2009-05-22 01:22:52 +00:00
tex - > m_texture - > Save ( s , true ) ;
2009-05-11 08:18:00 +00:00
if ( tex - > m_palette )
{
2011-02-19 03:36:30 +00:00
s = format ( " c: \\ temp2 \\ _%05d_f%lld_tpx_%05x_%d.dds " , s_n , frame , context - > TEX0 . CBP , context - > TEX0 . CPSM ) ;
2009-05-11 08:18:00 +00:00
2009-05-22 01:22:52 +00:00
tex - > m_palette - > Save ( s , true ) ;
2009-05-11 08:18:00 +00:00
}
}
s_n + + ;
2009-07-05 12:58:59 +00:00
if ( s_save & & s_n > = s_saven )
2009-05-11 08:18:00 +00:00
{
2011-02-19 03:36:30 +00:00
s = format ( " c: \\ temp2 \\ _%05d_f%lld_rt0_%05x_%d.bmp " , s_n , frame , context - > FRAME . Block ( ) , context - > FRAME . PSM ) ;
2009-05-11 08:18:00 +00:00
2009-05-22 01:22:52 +00:00
rt - > m_texture - > Save ( s ) ;
2009-05-11 08:18:00 +00:00
}
2009-07-05 12:58:59 +00:00
if ( s_savez & & s_n > = s_saven )
2009-05-11 08:18:00 +00:00
{
2011-02-19 03:36:30 +00:00
s = format ( " c: \\ temp2 \\ _%05d_f%lld_rz0_%05x_%d.bmp " , s_n , frame , context - > ZBUF . Block ( ) , context - > ZBUF . PSM ) ;
2009-05-11 08:18:00 +00:00
2009-05-22 01:22:52 +00:00
ds - > m_texture - > Save ( s ) ;
2009-05-11 08:18:00 +00:00
}
s_n + + ;
2009-02-09 21:15:56 +00:00
}
2009-07-22 14:28:14 +00:00
if ( m_hacks . m_oi & & ! ( this - > * m_hacks . m_oi ) ( rt - > m_texture , ds - > m_texture , tex ) )
2009-02-09 21:15:56 +00:00
{
return ;
}
2009-06-23 04:12:32 +00:00
// skip alpha test if possible
GIFRegTEST TEST = context - > TEST ;
GIFRegFRAME FRAME = context - > FRAME ;
GIFRegZBUF ZBUF = context - > ZBUF ;
uint32 fm = context - > FRAME . FBMSK ;
uint32 zm = context - > ZBUF . ZMSK | | context - > TEST . ZTE = = 0 ? 0xffffffff : 0 ;
if ( context - > TEST . ATE & & context - > TEST . ATST ! = ATST_ALWAYS )
{
if ( TryAlphaTest ( fm , zm ) )
{
2009-07-26 15:30:25 +00:00
context - > TEST . ATST = ATST_ALWAYS ;
2009-06-23 04:12:32 +00:00
}
}
context - > FRAME . FBMSK = fm ;
context - > ZBUF . ZMSK = zm ! = 0 ;
//
2009-07-22 03:55:28 +00:00
Draw ( rt - > m_texture , ds - > m_texture , tex ) ;
2009-06-23 04:12:32 +00:00
//
context - > TEST = TEST ;
context - > FRAME = FRAME ;
context - > ZBUF = ZBUF ;
//
2009-02-09 21:15:56 +00:00
2009-06-27 03:32:33 +00:00
GSVector4i r = GSVector4i ( m_vt . m_min . p . xyxy ( m_vt . m_max . p ) ) . rintersect ( GSVector4i ( m_context - > scissor . in ) ) ;
if ( fm ! = 0xffffffff )
{
2009-07-12 13:46:05 +00:00
rt - > m_valid = rt - > m_valid . runion ( r ) ;
2009-07-22 03:55:28 +00:00
m_tc - > InvalidateVideoMem ( m_context - > offset . fb , r , false ) ;
2009-06-27 03:32:33 +00:00
}
if ( zm ! = 0xffffffff )
{
2009-07-12 13:46:05 +00:00
ds - > m_valid = ds - > m_valid . runion ( r ) ;
2009-07-22 03:55:28 +00:00
m_tc - > InvalidateVideoMem ( m_context - > offset . zb , r , false ) ;
2009-06-27 03:32:33 +00:00
}
//
2009-07-12 13:46:05 +00:00
if ( m_hacks . m_oo )
{
( this - > * m_hacks . m_oo ) ( ) ;
}
2009-02-09 21:15:56 +00:00
if ( s_dump )
{
2009-05-15 11:11:26 +00:00
uint64 frame = m_perfmon . GetFrame ( ) ;
2009-05-11 08:18:00 +00:00
string s ;
2009-07-05 12:58:59 +00:00
if ( s_save & & s_n > = s_saven )
2009-05-11 08:18:00 +00:00
{
2011-02-19 03:36:30 +00:00
s = format ( " c: \\ temp2 \\ _%05d_f%lld_rt1_%05x_%d.bmp " , s_n , frame , context - > FRAME . Block ( ) , context - > FRAME . PSM ) ;
2009-05-11 08:18:00 +00:00
2009-05-22 01:22:52 +00:00
rt - > m_texture - > Save ( s ) ;
2009-05-11 08:18:00 +00:00
}
2009-07-05 12:58:59 +00:00
if ( s_savez & & s_n > = s_saven )
2009-05-11 08:18:00 +00:00
{
2011-02-19 03:36:30 +00:00
s = format ( " c: \\ temp2 \\ _%05d_f%lld_rz1_%05x_%d.bmp " , s_n , frame , context - > ZBUF . Block ( ) , context - > ZBUF . PSM ) ;
2009-05-11 08:18:00 +00:00
2009-05-22 01:22:52 +00:00
ds - > m_texture - > Save ( s ) ;
2009-05-11 08:18:00 +00:00
}
s_n + + ;
2009-02-09 21:15:56 +00:00
}
}
2009-07-22 03:55:28 +00:00
virtual void Draw ( GSTexture * rt , GSTexture * ds , GSTextureCache : : Source * tex ) = 0 ;
2009-02-09 21:15:56 +00:00
bool CanUpscale ( )
{
2009-07-12 13:46:05 +00:00
if ( m_hacks . m_cu & & ! ( this - > * m_hacks . m_cu ) ( ) )
2009-02-09 21:15:56 +00:00
{
2009-07-12 13:46:05 +00:00
return false ;
2009-02-09 21:15:56 +00:00
}
2011-02-19 03:36:30 +00:00
return ! m_nativeres & & m_regs - > PMODE . EN ! = 0 ; // upscale ratio depends on the display size, with no output it may not be set correctly (ps2 logo to game transition)
}
int GetUpscaleMultiplier ( )
{
return m_upscale_multiplier ;
2009-02-09 21:15:56 +00:00
}
public :
2009-09-18 19:54:56 +00:00
GSRendererHW ( GSTextureCache * tc )
: GSRendererT < Vertex > ( )
2009-05-22 23:23:38 +00:00
, m_tc ( tc )
2009-02-09 21:15:56 +00:00
, m_width ( 1024 )
, m_height ( 1024 )
, m_skip ( 0 )
, m_reset ( false )
2011-02-19 03:36:30 +00:00
, m_upscale_multiplier ( 1 )
2009-02-09 21:15:56 +00:00
{
2011-02-19 03:36:30 +00:00
m_nativeres = ! ! theApp . GetConfig ( " nativeres " , 0 ) ;
m_upscale_multiplier = theApp . GetConfig ( " upscale_multiplier " , 1 ) ;
m_userhacks_skipdraw = theApp . GetConfig ( " UserHacks_SkipDraw " , 0 ) ;
if ( m_nativeres )
{
m_filter = 2 ;
}
else
2009-02-09 21:15:56 +00:00
{
2009-05-18 11:08:04 +00:00
m_width = theApp . GetConfig ( " resx " , m_width ) ;
m_height = theApp . GetConfig ( " resy " , m_height ) ;
2011-02-19 03:36:30 +00:00
2009-10-26 15:52:45 +00:00
m_upscale_multiplier = theApp . GetConfig ( " upscale_multiplier " , m_upscale_multiplier ) ;
2011-02-19 03:36:30 +00:00
if ( m_upscale_multiplier > 6 )
{
m_upscale_multiplier = 1 ; // use the normal upscale math
}
else if ( m_upscale_multiplier > 1 )
2009-10-21 22:57:20 +00:00
{
2011-02-19 03:36:30 +00:00
m_width = 640 * m_upscale_multiplier ; // 512 is also common, but this is not always detected right.
m_height = 512 * m_upscale_multiplier ; // 448 is also common, but this is not always detected right.
2009-10-21 22:57:20 +00:00
}
2009-02-09 21:15:56 +00:00
}
}
virtual ~ GSRendererHW ( )
{
delete m_tc ;
}
2009-05-14 16:41:52 +00:00
void SetGameCRC ( uint32 crc , int options )
2009-02-09 21:15:56 +00:00
{
__super : : SetGameCRC ( crc , options ) ;
2009-07-12 13:46:05 +00:00
m_hacks . SetGame ( m_game ) ;
2009-02-09 21:15:56 +00:00
if ( m_game . title = = CRC : : JackieChanAdv )
{
m_width = 1280 ; // TODO: uses a 1280px wide 16 bit render target, but this only fixes half of the problem
}
}
2010-04-25 00:31:27 +00:00
} ;