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 .
*
* 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 , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
* http : //www.gnu.org/copyleft/gpl.html
*
*/
# include "StdAfx.h"
# include "GSRenderer.h"
2009-05-22 01:22:52 +00:00
2009-09-18 19:54:56 +00:00
GSRenderer : : GSRenderer ( )
: GSState ( )
2009-10-12 19:58:03 +00:00
, m_tex_buff ( ( uint8 * ) _aligned_malloc ( 1024 * 1024 * sizeof ( uint32 ) , 16 ) )
, m_vt ( this )
2009-09-17 07:40:38 +00:00
, m_dev ( NULL )
2009-05-22 23:23:38 +00:00
, m_shader ( 0 )
2009-05-22 01:22:52 +00:00
{
2009-05-22 23:23:38 +00:00
m_interlace = theApp . GetConfig ( " interlace " , 0 ) ;
m_aspectratio = theApp . GetConfig ( " aspectratio " , 1 ) ;
m_filter = theApp . GetConfig ( " filter " , 1 ) ;
m_vsync = ! ! theApp . GetConfig ( " vsync " , 0 ) ;
m_nativeres = ! ! theApp . GetConfig ( " nativeres " , 0 ) ;
2009-10-21 22:57:20 +00:00
2009-10-26 15:52:45 +00:00
m_upscale_multiplier = theApp . GetConfig ( " upscale_multiplier " , 1 ) ;
if ( m_nativeres ) m_upscale_multiplier = 1 ;
else if ( m_upscale_multiplier > 4 ) m_upscale_multiplier = 1 ;
2009-10-21 22:57:20 +00:00
2009-05-22 23:23:38 +00:00
m_aa1 = ! ! theApp . GetConfig ( " aa1 " , 0 ) ;
2009-05-22 01:22:52 +00:00
2009-06-19 13:03:59 +00:00
if ( m_nativeres ) m_filter = 2 ;
2009-05-22 01:22:52 +00:00
s_n = 0 ;
s_dump = ! ! theApp . GetConfig ( " dump " , 0 ) ;
s_save = ! ! theApp . GetConfig ( " save " , 0 ) ;
s_savez = ! ! theApp . GetConfig ( " savez " , 0 ) ;
2009-07-05 12:58:59 +00:00
s_saven = theApp . GetConfig ( " saven " , 0 ) ;
2009-05-22 01:22:52 +00:00
}
GSRenderer : : ~ GSRenderer ( )
{
2009-09-18 18:45:37 +00:00
/*if(m_dev)
2009-07-04 22:54:57 +00:00
{
m_dev - > Reset ( 1 , 1 , GSDevice : : Windowed ) ;
2009-09-18 18:45:37 +00:00
} */
2009-07-04 22:54:57 +00:00
2009-10-12 19:58:03 +00:00
_aligned_free ( m_tex_buff ) ;
2009-05-22 01:22:52 +00:00
delete m_dev ;
}
2009-09-17 07:40:38 +00:00
bool GSRenderer : : CreateWnd ( const string & title , int w , int h )
2009-05-22 01:22:52 +00:00
{
2009-07-17 23:45:32 +00:00
if ( ! m_wnd . Create ( title . c_str ( ) , w , h ) )
2009-05-22 01:22:52 +00:00
{
return false ;
}
2009-09-17 07:40:38 +00:00
return true ;
}
2009-05-22 01:22:52 +00:00
2009-09-17 07:40:38 +00:00
bool GSRenderer : : CreateDevice ( GSDevice * dev )
{
ASSERT ( dev ) ;
ASSERT ( ! m_dev ) ;
2009-05-22 01:22:52 +00:00
2009-10-31 01:06:23 +00:00
if ( ! dev - > Create ( & m_wnd ) )
2009-05-22 01:22:52 +00:00
{
return false ;
}
2009-09-17 07:40:38 +00:00
m_dev = dev ;
2009-10-31 01:06:23 +00:00
m_dev - > SetVsync ( m_vsync & & m_framelimit ) ;
2009-05-22 01:22:52 +00:00
return true ;
}
bool GSRenderer : : Merge ( int field )
{
bool en [ 2 ] ;
GSVector4i fr [ 2 ] ;
GSVector4i dr [ 2 ] ;
int baseline = INT_MAX ;
for ( int i = 0 ; i < 2 ; i + + )
{
en [ i ] = IsEnabled ( i ) ;
if ( en [ i ] )
{
fr [ i ] = GetFrameRect ( i ) ;
dr [ i ] = GetDisplayRect ( i ) ;
baseline = min ( dr [ i ] . top , baseline ) ;
// printf("[%d]: %d %d %d %d, %d %d %d %d\n", i, fr[i], dr[i]);
}
}
if ( ! en [ 0 ] & & ! en [ 1 ] )
{
return false ;
}
// try to avoid fullscreen blur, could be nice on tv but on a monitor it's like double vision, hurts my eyes (persona 4, guitar hero)
//
// NOTE: probably the technique explained in graphtip.pdf (Antialiasing by Supersampling / 4. Reading Odd/Even Scan Lines Separately with the PCRTC then Blending)
bool samesrc =
en [ 0 ] & & en [ 1 ] & &
m_regs - > DISP [ 0 ] . DISPFB . FBP = = m_regs - > DISP [ 1 ] . DISPFB . FBP & &
m_regs - > DISP [ 0 ] . DISPFB . FBW = = m_regs - > DISP [ 1 ] . DISPFB . FBW & &
m_regs - > DISP [ 0 ] . DISPFB . PSM = = m_regs - > DISP [ 1 ] . DISPFB . PSM ;
bool blurdetected = false ;
2009-11-10 13:05:56 +00:00
if ( samesrc /*&& m_regs->PMODE.SLBG == 0 && m_regs->PMODE.MMOD == 1 && m_regs->PMODE.ALP == 0x80*/ )
2009-05-22 01:22:52 +00:00
{
if ( fr [ 0 ] . eq ( fr [ 1 ] + GSVector4i ( 0 , - 1 , 0 , 0 ) ) & & dr [ 0 ] . eq ( dr [ 1 ] + GSVector4i ( 0 , 0 , 0 , 1 ) )
| | fr [ 1 ] . eq ( fr [ 0 ] + GSVector4i ( 0 , - 1 , 0 , 0 ) ) & & dr [ 1 ] . eq ( dr [ 0 ] + GSVector4i ( 0 , 0 , 0 , 1 ) ) )
{
// persona 4:
//
// fr[0] = 0 0 640 448
// fr[1] = 0 1 640 448
// dr[0] = 159 50 779 498
// dr[1] = 159 50 779 497
//
// second image shifted up by 1 pixel and blended over itself
//
// god of war:
//
// fr[0] = 0 1 512 448
// fr[1] = 0 0 512 448
// dr[0] = 127 50 639 497
// dr[1] = 127 50 639 498
//
// same just the first image shifted
int top = min ( fr [ 0 ] . top , fr [ 1 ] . top ) ;
int bottom = max ( dr [ 0 ] . bottom , dr [ 1 ] . bottom ) ;
fr [ 0 ] . top = top ;
fr [ 1 ] . top = top ;
dr [ 0 ] . bottom = bottom ;
dr [ 1 ] . bottom = bottom ;
blurdetected = true ;
}
else if ( dr [ 0 ] . eq ( dr [ 1 ] ) & & ( fr [ 0 ] . eq ( fr [ 1 ] + GSVector4i ( 0 , 1 , 0 , 1 ) ) | | fr [ 1 ] . eq ( fr [ 0 ] + GSVector4i ( 0 , 1 , 0 , 1 ) ) ) )
{
// dq5:
//
// fr[0] = 0 1 512 445
// fr[1] = 0 0 512 444
// dr[0] = 127 50 639 494
// dr[1] = 127 50 639 494
int top = min ( fr [ 0 ] . top , fr [ 1 ] . top ) ;
int bottom = min ( fr [ 0 ] . bottom , fr [ 1 ] . bottom ) ;
fr [ 0 ] . top = fr [ 1 ] . top = top ;
fr [ 0 ] . bottom = fr [ 1 ] . bottom = bottom ;
blurdetected = true ;
}
2009-11-10 13:05:56 +00:00
//printf("samesrc = %d blurdetected = %d\n",samesrc,blurdetected);
2009-05-22 01:22:52 +00:00
}
GSVector2i fs ( 0 , 0 ) ;
GSVector2i ds ( 0 , 0 ) ;
GSTexture * tex [ 2 ] = { NULL , NULL } ;
if ( samesrc & & fr [ 0 ] . bottom = = fr [ 1 ] . bottom )
{
tex [ 0 ] = GetOutput ( 0 ) ;
tex [ 1 ] = tex [ 0 ] ; // saves one texture fetch
}
else
{
if ( en [ 0 ] ) tex [ 0 ] = GetOutput ( 0 ) ;
if ( en [ 1 ] ) tex [ 1 ] = GetOutput ( 1 ) ;
}
GSVector4 src [ 2 ] ;
GSVector4 dst [ 2 ] ;
for ( int i = 0 ; i < 2 ; i + + )
{
if ( ! en [ i ] | | ! tex [ i ] ) continue ;
GSVector4i r = fr [ i ] ;
// overscan hack
if ( dr [ i ] . height ( ) > 512 ) // hmm
{
int y = GetDeviceSize ( i ) . y ;
if ( m_regs - > SMODE2 . INT & & m_regs - > SMODE2 . FFMD ) y / = 2 ;
r . bottom = r . top + y ;
}
2010-02-19 19:05:35 +00:00
// Breaks the blur filter, and actually makes games blurry again.
// This might have to do with earlier changes to device size detection.
/*if(blurdetected && i == 1)
2009-05-22 01:22:52 +00:00
{
r + = GSVector4i ( 0 , 1 ) . xyxy ( ) ;
2010-02-19 19:05:35 +00:00
} */
2009-05-22 01:22:52 +00:00
2009-08-02 23:07:30 +00:00
GSVector4 scale = GSVector4 ( tex [ i ] - > GetScale ( ) ) . xyxy ( ) ;
2009-05-22 01:22:52 +00:00
src [ i ] = GSVector4 ( r ) * scale / GSVector4 ( tex [ i ] - > GetSize ( ) ) . xyxy ( ) ;
2009-11-28 15:46:51 +00:00
2009-05-22 01:22:52 +00:00
GSVector2 o ( 0 , 0 ) ;
if ( dr [ i ] . top - baseline > = 4 ) // 2?
{
2009-08-02 23:07:30 +00:00
o . y = tex [ i ] - > GetScale ( ) . y * ( dr [ i ] . top - baseline ) ;
2009-05-22 01:22:52 +00:00
if ( m_regs - > SMODE2 . INT & & m_regs - > SMODE2 . FFMD )
{
o . y / = 2 ;
}
}
dst [ i ] = GSVector4 ( o ) . xyxy ( ) + scale * GSVector4 ( r . rsize ( ) ) ;
fs . x = max ( fs . x , ( int ) ( dst [ i ] . z + 0.5f ) ) ;
fs . y = max ( fs . y , ( int ) ( dst [ i ] . w + 0.5f ) ) ;
}
ds = fs ;
if ( m_regs - > SMODE2 . INT & & m_regs - > SMODE2 . FFMD )
{
ds . y * = 2 ;
}
bool slbg = m_regs - > PMODE . SLBG ;
bool mmod = m_regs - > PMODE . MMOD ;
if ( tex [ 0 ] | | tex [ 1 ] )
{
GSVector4 c = GSVector4 ( ( int ) m_regs - > BGCOLOR . R , ( int ) m_regs - > BGCOLOR . G , ( int ) m_regs - > BGCOLOR . B , ( int ) m_regs - > PMODE . ALP ) / 255 ;
m_dev - > Merge ( tex , src , dst , fs , slbg , mmod , c ) ;
if ( m_regs - > SMODE2 . INT & & m_interlace > 0 )
{
int field2 = 1 - ( ( m_interlace - 1 ) & 1 ) ;
int mode = ( m_interlace - 1 ) > > 1 ;
2009-08-02 23:07:30 +00:00
m_dev - > Interlace ( ds , field ^ field2 , mode , tex [ 1 ] ? tex [ 1 ] - > GetScale ( ) . y : tex [ 0 ] - > GetScale ( ) . y ) ;
2009-05-22 01:22:52 +00:00
}
}
return true ;
}
2009-10-31 01:06:23 +00:00
void GSRenderer : : SetFrameLimit ( bool limit )
{
m_framelimit = limit ;
if ( m_dev ) m_dev - > SetVsync ( m_vsync & & m_framelimit ) ;
}
2009-12-01 05:59:43 +00:00
void GSRenderer : : SetVsync ( bool enabled )
{
m_vsync = enabled ;
2009-12-04 04:50:49 +00:00
if ( m_dev ) m_dev - > SetVsync ( m_vsync ) ;
2009-12-01 05:59:43 +00:00
}
2009-05-22 01:22:52 +00:00
void GSRenderer : : VSync ( int field )
{
GSPerfMonAutoTimer pmat ( m_perfmon ) ;
m_perfmon . Put ( GSPerfMon : : Frame ) ;
Flush ( ) ;
2009-07-04 15:14:04 +00:00
if ( ! m_dev - > IsLost ( true ) )
{
if ( ! Merge ( field ? 1 : 0 ) )
{
return ;
}
}
else
{
ResetDevice ( ) ;
}
2009-05-22 01:22:52 +00:00
// osd
2010-01-28 02:53:10 +00:00
if ( ( m_perfmon . GetFrame ( ) & 0x1f ) = = 0 & & m_wnd . IsManaged ( ) )
2009-05-22 01:22:52 +00:00
{
m_perfmon . Update ( ) ;
double fps = 1000.0f / m_perfmon . Get ( GSPerfMon : : Frame ) ;
2009-06-03 12:09:04 +00:00
string s2 = m_regs - > SMODE2 . INT ? ( string ( " Interlaced " ) + ( m_regs - > SMODE2 . FFMD ? " (frame) " : " (field) " ) ) : " Progressive " ;
2009-05-22 01:22:52 +00:00
GSVector4i r = GetDisplayRect ( ) ;
2009-06-03 12:09:04 +00:00
string s = format (
2009-05-22 01:22:52 +00:00
" %I64d | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d/%d/%d | %d%% CPU | %.2f | %.2f " ,
m_perfmon . GetFrame ( ) , r . width ( ) , r . height ( ) , fps , ( int ) ( 100.0 * fps / GetFPS ( ) ) ,
2009-06-03 12:09:04 +00:00
s2 . c_str ( ) ,
2009-05-22 01:22:52 +00:00
GSSettingsDlg : : g_interlace [ m_interlace ] . name ,
GSSettingsDlg : : g_aspectratio [ m_aspectratio ] . name ,
( int ) m_perfmon . Get ( GSPerfMon : : Quad ) ,
( int ) m_perfmon . Get ( GSPerfMon : : Prim ) ,
( int ) m_perfmon . Get ( GSPerfMon : : Draw ) ,
m_perfmon . CPU ( ) ,
m_perfmon . Get ( GSPerfMon : : Swizzle ) / 1024 ,
m_perfmon . Get ( GSPerfMon : : Unswizzle ) / 1024
) ;
double fillrate = m_perfmon . Get ( GSPerfMon : : Fillrate ) ;
if ( fillrate > 0 )
{
2009-06-03 12:09:04 +00:00
s + = format ( " | %.2f mpps " , fps * fillrate / ( 1024 * 1024 ) ) ;
2009-05-22 01:22:52 +00:00
}
if ( m_capture . IsCapturing ( ) )
{
2009-06-03 12:09:04 +00:00
s + = " | Recording... " ;
2009-05-22 01:22:52 +00:00
}
2010-01-28 02:53:10 +00:00
m_wnd . SetWindowText ( s . c_str ( ) ) ;
}
else
{
// [TODO]
// We don't have window title rights, or the window has no title,
// so let's use actual OSD!
2009-05-22 01:22:52 +00:00
}
if ( m_frameskip )
{
return ;
}
// present
2009-10-31 01:06:23 +00:00
m_dev - > Present ( m_wnd . GetClientRect ( ) . fit ( m_aspectratio ) , m_shader ) ;
2009-05-22 01:22:52 +00:00
// snapshot
if ( ! m_snapshot . empty ( ) )
{
if ( ! m_dump & & ( : : GetAsyncKeyState ( VK_SHIFT ) & 0x8000 ) )
{
GSFreezeData fd ;
fd . size = 0 ;
fd . data = NULL ;
Freeze ( & fd , true ) ;
fd . data = new uint8 [ fd . size ] ;
Freeze ( & fd , false ) ;
m_dump . Open ( m_snapshot , m_crc , fd , m_regs ) ;
delete [ ] fd . data ;
}
if ( GSTexture * t = m_dev - > GetCurrent ( ) )
{
t - > Save ( m_snapshot + " .bmp " ) ;
}
m_snapshot . clear ( ) ;
}
else
{
if ( m_dump )
{
m_dump . VSync ( field , ! ( : : GetAsyncKeyState ( VK_CONTROL ) & 0x8000 ) , m_regs ) ;
}
}
// capture
if ( m_capture . IsCapturing ( ) )
{
if ( GSTexture * current = m_dev - > GetCurrent ( ) )
{
GSVector2i size = m_capture . GetSize ( ) ;
if ( GSTexture * offscreen = m_dev - > CopyOffscreen ( current , GSVector4 ( 0 , 0 , 1 , 1 ) , size . x , size . y ) )
{
2009-06-12 19:09:17 +00:00
GSTexture : : GSMap m ;
2009-05-22 01:22:52 +00:00
2009-06-12 19:09:17 +00:00
if ( offscreen - > Map ( m ) )
2009-05-22 01:22:52 +00:00
{
2009-08-16 16:45:26 +00:00
m_capture . DeliverFrame ( m . bits , m . pitch , ! m_dev - > IsRBSwapped ( ) ) ;
2009-05-22 01:22:52 +00:00
offscreen - > Unmap ( ) ;
}
m_dev - > Recycle ( offscreen ) ;
}
}
}
}
2009-06-03 12:09:04 +00:00
bool GSRenderer : : MakeSnapshot ( const string & path )
{
if ( m_snapshot . empty ( ) )
{
time_t t = time ( NULL ) ;
char buff [ 16 ] ;
if ( strftime ( buff , sizeof ( buff ) , " %Y%m%d%H%M%S " , localtime ( & t ) ) )
{
m_snapshot = format ( " %s_%s " , path . c_str ( ) , buff ) ;
}
}
return true ;
}
2009-12-30 13:29:24 +00:00
2009-08-16 16:45:26 +00:00
void GSRenderer : : KeyEvent ( GSKeyEventData * e , int param )
2009-05-22 01:22:52 +00:00
{
if ( e - > type = = KEYPRESS )
{
// TODO: linux
int step = ( : : GetAsyncKeyState ( VK_SHIFT ) & 0x8000 ) ? - 1 : 1 ;
switch ( e - > key )
{
case VK_F5 :
m_interlace = ( m_interlace + 7 + step ) % 7 ;
return ;
case VK_F6 :
2009-12-30 13:29:24 +00:00
m_aspectratio = ( m_aspectratio + 3 + step ) % 3 ;
2009-05-22 01:22:52 +00:00
return ;
case VK_F7 :
2009-05-22 23:23:38 +00:00
m_shader = ( m_shader + 3 + step ) % 3 ;
2009-05-22 01:22:52 +00:00
return ;
case VK_F12 :
2009-08-16 16:45:26 +00:00
if ( param ) m_capture . BeginCapture ( GetFPS ( ) ) ;
else m_capture . EndCapture ( ) ;
2009-05-22 01:22:52 +00:00
return ;
case VK_DELETE :
m_aa1 = ! m_aa1 ;
return ;
}
}
}
2009-06-27 03:32:33 +00:00
void GSRenderer : : GetTextureMinMax ( GSVector4i & r , bool linear )
2009-06-23 04:12:32 +00:00
{
const GSDrawingContext * context = m_context ;
int tw = context - > TEX0 . TW ;
int th = context - > TEX0 . TH ;
int w = 1 < < tw ;
int h = 1 < < th ;
GSVector4i tr ( 0 , 0 , w , h ) ;
int wms = context - > CLAMP . WMS ;
int wmt = context - > CLAMP . WMT ;
int minu = ( int ) context - > CLAMP . MINU ;
int minv = ( int ) context - > CLAMP . MINV ;
int maxu = ( int ) context - > CLAMP . MAXU ;
int maxv = ( int ) context - > CLAMP . MAXV ;
GSVector4i vr = tr ;
switch ( wms )
{
case CLAMP_REPEAT :
break ;
case CLAMP_CLAMP :
break ;
case CLAMP_REGION_CLAMP :
if ( vr . x < minu ) vr . x = minu ;
if ( vr . z > maxu + 1 ) vr . z = maxu + 1 ;
break ;
case CLAMP_REGION_REPEAT :
vr . x = maxu ;
vr . z = vr . x + ( minu + 1 ) ;
break ;
default :
__assume ( 0 ) ;
}
switch ( wmt )
{
case CLAMP_REPEAT :
break ;
case CLAMP_CLAMP :
break ;
case CLAMP_REGION_CLAMP :
if ( vr . y < minv ) vr . y = minv ;
if ( vr . w > maxv + 1 ) vr . w = maxv + 1 ;
break ;
case CLAMP_REGION_REPEAT :
vr . y = maxv ;
vr . w = vr . y + ( minv + 1 ) ;
break ;
default :
__assume ( 0 ) ;
}
if ( wms + wmt < 6 )
{
GSVector4 st = m_vt . m_min . t . xyxy ( m_vt . m_max . t ) ;
2009-06-27 03:32:33 +00:00
if ( linear )
2009-06-23 04:12:32 +00:00
{
st + = GSVector4 ( - 0x8000 , 0x8000 ) . xxyy ( ) ;
}
GSVector4i uv = GSVector4i ( st ) . sra32 ( 16 ) ;
GSVector4i u , v ;
int mask = 0 ;
if ( wms = = CLAMP_REPEAT | | wmt = = CLAMP_REPEAT )
{
u = uv & GSVector4i : : xffffffff ( ) . srl32 ( 32 - tw ) ;
v = uv & GSVector4i : : xffffffff ( ) . srl32 ( 32 - th ) ;
GSVector4i uu = uv . sra32 ( tw ) ;
GSVector4i vv = uv . sra32 ( th ) ;
mask = ( uu . upl32 ( vv ) = = uu . uph32 ( vv ) ) . mask ( ) ;
}
uv = uv . rintersect ( tr ) ;
switch ( wms )
{
case CLAMP_REPEAT :
if ( mask & 0x000f ) { if ( vr . x < u . x ) vr . x = u . x ; if ( vr . z > u . z + 1 ) vr . z = u . z + 1 ; }
break ;
case CLAMP_CLAMP :
case CLAMP_REGION_CLAMP :
if ( vr . x < uv . x ) vr . x = uv . x ;
if ( vr . z > uv . z + 1 ) vr . z = uv . z + 1 ;
break ;
case CLAMP_REGION_REPEAT : // TODO
break ;
default :
__assume ( 0 ) ;
}
switch ( wmt )
{
case CLAMP_REPEAT :
if ( mask & 0xf000 ) { if ( vr . y < v . y ) vr . y = v . y ; if ( vr . w > v . w + 1 ) vr . w = v . w + 1 ; }
break ;
case CLAMP_CLAMP :
case CLAMP_REGION_CLAMP :
if ( vr . y < uv . y ) vr . y = uv . y ;
if ( vr . w > uv . w + 1 ) vr . w = uv . w + 1 ;
break ;
case CLAMP_REGION_REPEAT : // TODO
2009-11-24 22:25:50 +00:00
//Xenosaga 2 and 3 use it
//printf("gsdx: CLAMP_REGION_REPEAT not implemented, please report\n");
2009-06-23 04:12:32 +00:00
break ;
default :
__assume ( 0 ) ;
}
}
2009-07-22 03:55:28 +00:00
r = vr . rintersect ( tr ) ;
2009-06-23 04:12:32 +00:00
}
void GSRenderer : : GetAlphaMinMax ( )
{
if ( m_vt . m_alpha . valid )
{
return ;
}
const GSDrawingEnvironment & env = m_env ;
const GSDrawingContext * context = m_context ;
GSVector4i a = m_vt . m_min . c . uph32 ( m_vt . m_max . c ) . zzww ( ) ;
if ( PRIM - > TME & & context - > TEX0 . TCC )
{
2009-07-16 21:36:07 +00:00
switch ( GSLocalMemory : : m_psm [ context - > TEX0 . PSM ] . fmt )
2009-06-23 04:12:32 +00:00
{
2009-07-16 21:36:07 +00:00
case 0 :
2009-06-23 04:12:32 +00:00
a . y = 0 ;
a . w = 0xff ;
2009-07-16 21:36:07 +00:00
break ;
case 1 :
2009-06-23 04:12:32 +00:00
a . y = env . TEXA . AEM ? 0 : env . TEXA . TA0 ;
a . w = env . TEXA . TA0 ;
2009-07-16 21:36:07 +00:00
break ;
case 2 :
2009-06-23 04:12:32 +00:00
a . y = env . TEXA . AEM ? 0 : min ( env . TEXA . TA0 , env . TEXA . TA1 ) ;
a . w = max ( env . TEXA . TA0 , env . TEXA . TA1 ) ;
2009-07-16 21:36:07 +00:00
break ;
case 3 :
2009-06-23 04:12:32 +00:00
m_mem . m_clut . GetAlphaMinMax32 ( a . y , a . w ) ;
2009-07-16 21:36:07 +00:00
break ;
default :
__assume ( 0 ) ;
2009-06-23 04:12:32 +00:00
}
switch ( context - > TEX0 . TFX )
{
case TFX_MODULATE :
a . x = ( a . x * a . y ) > > 7 ;
a . z = ( a . z * a . w ) > > 7 ;
if ( a . x > 0xff ) a . x = 0xff ;
if ( a . z > 0xff ) a . z = 0xff ;
break ;
case TFX_DECAL :
a . x = a . y ;
a . z = a . w ;
break ;
case TFX_HIGHLIGHT :
a . x = a . x + a . y ;
a . z = a . z + a . w ;
if ( a . x > 0xff ) a . x = 0xff ;
if ( a . z > 0xff ) a . z = 0xff ;
break ;
case TFX_HIGHLIGHT2 :
a . x = a . y ;
a . z = a . w ;
break ;
default :
__assume ( 0 ) ;
}
}
m_vt . m_alpha . min = a . x ;
m_vt . m_alpha . max = a . z ;
m_vt . m_alpha . valid = true ;
}
bool GSRenderer : : TryAlphaTest ( uint32 & fm , uint32 & zm )
{
const GSDrawingContext * context = m_context ;
bool pass = true ;
if ( context - > TEST . ATST = = ATST_NEVER )
{
pass = false ;
}
else if ( context - > TEST . ATST ! = ATST_ALWAYS )
{
GetAlphaMinMax ( ) ;
int amin = m_vt . m_alpha . min ;
int amax = m_vt . m_alpha . max ;
int aref = context - > TEST . AREF ;
switch ( context - > TEST . ATST )
{
case ATST_NEVER :
pass = false ;
break ;
case ATST_ALWAYS :
pass = true ;
break ;
case ATST_LESS :
if ( amax < aref ) pass = true ;
else if ( amin > = aref ) pass = false ;
else return false ;
break ;
case ATST_LEQUAL :
if ( amax < = aref ) pass = true ;
else if ( amin > aref ) pass = false ;
else return false ;
break ;
case ATST_EQUAL :
if ( amin = = aref & & amax = = aref ) pass = true ;
else if ( amin > aref | | amax < aref ) pass = false ;
else return false ;
break ;
case ATST_GEQUAL :
if ( amin > = aref ) pass = true ;
else if ( amax < aref ) pass = false ;
else return false ;
break ;
case ATST_GREATER :
if ( amin > aref ) pass = true ;
else if ( amax < = aref ) pass = false ;
else return false ;
break ;
case ATST_NOTEQUAL :
if ( amin = = aref & & amax = = aref ) pass = false ;
else if ( amin > aref | | amax < aref ) pass = true ;
else return false ;
break ;
default :
__assume ( 0 ) ;
}
}
if ( ! pass )
{
switch ( context - > TEST . AFAIL )
{
case AFAIL_KEEP : fm = zm = 0xffffffff ; break ;
case AFAIL_FB_ONLY : zm = 0xffffffff ; break ;
case AFAIL_ZB_ONLY : fm = 0xffffffff ; break ;
case AFAIL_RGB_ONLY : fm | = 0xff000000 ; zm = 0xffffffff ; break ;
default : __assume ( 0 ) ;
}
}
return true ;
}
2009-06-27 03:32:33 +00:00
bool GSRenderer : : IsLinear ( )
{
2009-07-16 21:36:07 +00:00
const GIFRegTEX1 & TEX1 = m_context - > TEX1 ;
bool mmin = TEX1 . IsMinLinear ( ) ;
bool mmag = TEX1 . IsMagLinear ( ) ;
2009-07-26 15:30:25 +00:00
if ( mmag = = mmin | | TEX1 . MXL = = 0 ) // MXL == 0 => MMIN ignored, tested it on ps2
{
return mmag ;
}
2009-11-23 23:58:25 +00:00
// if FST => assume Q = 1.0f (should not, but Q is very often bogus, 0 or DEN)
// Fixme : Why should Q be bogus?
2009-12-07 09:46:33 +00:00
if ( ! TEX1 . LCM & & ! PRIM - > FST )
2009-06-27 03:32:33 +00:00
{
2009-07-22 03:55:28 +00:00
float K = ( float ) TEX1 . K / 16 ;
2009-07-16 21:36:07 +00:00
float f = ( float ) ( 1 < < TEX1 . L ) / log ( 2.0f ) ;
2009-06-27 03:32:33 +00:00
2009-07-22 03:55:28 +00:00
// TODO: abs(Qmin) may not be <= abs(Qmax), check the sign
float LODmin = K + log ( 1.0f / abs ( m_vt . m_max . t . z ) ) * f ;
float LODmax = K + log ( 1.0f / abs ( m_vt . m_min . t . z ) ) * f ;
2009-06-27 03:32:33 +00:00
2009-07-22 03:55:28 +00:00
return LODmax < = 0 ? mmag : LODmin > 0 ? mmin : mmag | | mmin ;
}
else
{
return TEX1 . K < = 0 ? mmag : TEX1 . K > 0 ? mmin : mmag | | mmin ;
}
2009-06-27 03:32:33 +00:00
}
2009-06-23 04:12:32 +00:00
bool GSRenderer : : IsOpaque ( )
{
if ( PRIM - > AA1 )
{
return false ;
}
if ( ! PRIM - > ABE )
{
return true ;
}
const GSDrawingContext * context = m_context ;
int amin = 0 , amax = 0xff ;
if ( context - > ALPHA . A ! = context - > ALPHA . B )
{
if ( context - > ALPHA . C = = 0 )
{
GetAlphaMinMax ( ) ;
amin = m_vt . m_alpha . min ;
amax = m_vt . m_alpha . max ;
}
else if ( context - > ALPHA . C = = 1 )
{
if ( context - > FRAME . PSM = = PSM_PSMCT24 | | context - > FRAME . PSM = = PSM_PSMZ24 )
{
amin = amax = 0x80 ;
}
}
2009-07-26 15:30:25 +00:00
else if ( context - > ALPHA . C = = 2 )
2009-06-23 04:12:32 +00:00
{
amin = amax = context - > ALPHA . FIX ;
}
}
return context - > ALPHA . IsOpaque ( amin , amax ) ;
}