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
*
*/
2011-02-19 03:36:30 +00:00
# include "stdafx.h"
2009-02-09 21:15:56 +00:00
# include "GSRendererSW.h"
2012-01-18 11:47:31 +00:00
# define LOG 0
static FILE * s_fp = LOG ? fopen ( " c: \\ temp1 \\ _.txt " , " w " ) : NULL ;
2009-02-09 21:15:56 +00:00
const GSVector4 g_pos_scale ( 1.0f / 16 , 1.0f / 16 , 1.0f , 128.0f ) ;
2009-05-22 01:22:52 +00:00
2011-02-17 03:24:37 +00:00
GSRendererSW : : GSRendererSW ( int threads )
2012-01-19 04:53:36 +00:00
: m_fzb ( NULL )
2009-05-22 01:22:52 +00:00
{
2012-01-08 17:10:00 +00:00
m_nativeres = true ; // ignore ini, sw is always native
2011-02-18 01:56:05 +00:00
2009-05-22 01:22:52 +00:00
m_tc = new GSTextureCacheSW ( this ) ;
memset ( m_texture , 0 , sizeof ( m_texture ) ) ;
2011-12-22 01:48:16 +00:00
m_rl = GSRasterizerList : : Create < GSDrawScanline > ( threads , & m_perfmon ) ;
2011-02-19 03:36:30 +00:00
m_output = ( uint8 * ) _aligned_malloc ( 1024 * 1024 * sizeof ( uint32 ) , 32 ) ;
2011-12-18 21:57:48 +00:00
memset ( m_fzb_pages , 0 , sizeof ( m_fzb_pages ) ) ;
2011-12-23 15:53:53 +00:00
memset ( m_tex_pages , 0 , sizeof ( m_tex_pages ) ) ;
2009-05-22 01:22:52 +00:00
}
GSRendererSW : : ~ GSRendererSW ( )
{
delete m_tc ;
2009-07-04 22:54:57 +00:00
for ( int i = 0 ; i < countof ( m_texture ) ; i + + )
{
delete m_texture [ i ] ;
}
2011-02-19 03:36:30 +00:00
2011-12-18 08:13:20 +00:00
delete m_rl ;
2011-02-19 03:36:30 +00:00
_aligned_free ( m_output ) ;
2009-05-22 01:22:52 +00:00
}
2010-04-25 00:31:27 +00:00
void GSRendererSW : : Reset ( )
2009-05-22 01:22:52 +00:00
{
2012-01-18 11:47:31 +00:00
Sync ( - 1 ) ;
2009-05-22 01:22:52 +00:00
2012-01-18 11:47:31 +00:00
m_tc - > RemoveAll ( ) ;
2009-05-22 01:22:52 +00:00
2012-01-05 02:40:24 +00:00
GSRenderer : : Reset ( ) ;
2009-05-22 01:22:52 +00:00
}
void GSRendererSW : : VSync ( int field )
{
2011-12-22 14:36:54 +00:00
Sync ( 0 ) ; // IncAge might delete a cached texture in use
2011-12-28 14:10:20 +00:00
2012-01-18 11:47:31 +00:00
if ( LOG )
{
fprintf ( s_fp , " %lld \n " , m_perfmon . GetFrame ( ) ) ;
GSVector4i dr = GetDisplayRect ( ) ;
GSVector4i fr = GetFrameRect ( ) ;
GSVector2i ds = GetDeviceSize ( ) ;
fprintf ( s_fp , " dr %d %d %d %d, fr %d %d %d %d, ds %d %d \n " ,
dr . x , dr . y , dr . z , dr . w ,
fr . x , fr . y , fr . z , fr . w ,
ds . x , ds . y ) ;
for ( int i = 0 ; i < 2 ; i + + )
{
if ( i = = 0 & & ! m_regs - > PMODE . EN1 ) continue ;
if ( i = = 1 & & ! m_regs - > PMODE . EN2 ) continue ;
fprintf ( s_fp , " DISPFB[%d] BP=%05x BW=%d PSM=%d DBX=%d DBY=%d \n " ,
i ,
m_regs - > DISP [ i ] . DISPFB . Block ( ) ,
m_regs - > DISP [ i ] . DISPFB . FBW ,
m_regs - > DISP [ i ] . DISPFB . PSM ,
m_regs - > DISP [ i ] . DISPFB . DBX ,
m_regs - > DISP [ i ] . DISPFB . DBY
) ;
fprintf ( s_fp , " DISPLAY[%d] DX=%d DY=%d DW=%d DH=%d MAGH=%d MAGV=%d \n " ,
i ,
m_regs - > DISP [ i ] . DISPLAY . DX ,
m_regs - > DISP [ i ] . DISPLAY . DY ,
m_regs - > DISP [ i ] . DISPLAY . DW ,
m_regs - > DISP [ i ] . DISPLAY . DH ,
m_regs - > DISP [ i ] . DISPLAY . MAGH ,
m_regs - > DISP [ i ] . DISPLAY . MAGV
) ;
}
fprintf ( s_fp , " PMODE EN1=%d EN2=%d CRTMD=%d MMOD=%d AMOD=%d SLBG=%d ALP=%d \n " ,
m_regs - > PMODE . EN1 ,
m_regs - > PMODE . EN2 ,
m_regs - > PMODE . CRTMD ,
m_regs - > PMODE . MMOD ,
m_regs - > PMODE . AMOD ,
m_regs - > PMODE . SLBG ,
m_regs - > PMODE . ALP
) ;
fprintf ( s_fp , " SMODE1 %08x_%08x \n " ,
m_regs - > SMODE1 . u32 [ 0 ] ,
m_regs - > SMODE1 . u32 [ 1 ]
) ;
fprintf ( s_fp , " SMODE2 INT=%d FFMD=%d DPMS=%d \n " ,
m_regs - > SMODE2 . INT ,
m_regs - > SMODE2 . FFMD ,
m_regs - > SMODE2 . DPMS
) ;
fprintf ( s_fp , " SRFSH %08x_%08x \n " ,
m_regs - > SRFSH . u32 [ 0 ] ,
m_regs - > SRFSH . u32 [ 1 ]
) ;
fprintf ( s_fp , " SYNCH1 %08x_%08x \n " ,
m_regs - > SYNCH1 . u32 [ 0 ] ,
m_regs - > SYNCH1 . u32 [ 1 ]
) ;
fprintf ( s_fp , " SYNCH2 %08x_%08x \n " ,
m_regs - > SYNCH2 . u32 [ 0 ] ,
m_regs - > SYNCH2 . u32 [ 1 ]
) ;
fprintf ( s_fp , " SYNCV %08x_%08x \n " ,
m_regs - > SYNCV . u32 [ 0 ] ,
m_regs - > SYNCV . u32 [ 1 ]
) ;
fprintf ( s_fp , " CSR %08x_%08x \n " ,
m_regs - > CSR . u32 [ 0 ] ,
m_regs - > CSR . u32 [ 1 ]
) ;
fflush ( s_fp ) ;
}
2011-12-22 01:48:16 +00:00
/*
2011-12-28 14:10:20 +00:00
int draw [ 8 ] , sum = 0 ;
for ( int i = 0 ; i < countof ( draw ) ; i + + )
{
draw [ i ] = m_perfmon . CPU ( GSPerfMon : : WorkerDraw0 + i ) ;
sum + = draw [ i ] ;
}
printf ( " CPU %d Sync %d W %d %d %d %d %d %d %d %d (%d) \n " ,
2011-12-22 01:48:16 +00:00
m_perfmon . CPU ( GSPerfMon : : Main ) ,
m_perfmon . CPU ( GSPerfMon : : Sync ) ,
2011-12-28 14:10:20 +00:00
draw [ 0 ] , draw [ 1 ] , draw [ 2 ] , draw [ 3 ] , draw [ 4 ] , draw [ 5 ] , draw [ 6 ] , draw [ 7 ] , sum ) ;
2011-12-22 01:48:16 +00:00
//
2012-01-13 18:10:05 +00:00
*/
2012-01-18 11:47:31 +00:00
2012-01-05 02:40:24 +00:00
GSRenderer : : VSync ( field ) ;
2011-12-18 08:13:20 +00:00
2009-05-22 01:22:52 +00:00
m_tc - > IncAge ( ) ;
2011-03-27 03:14:15 +00:00
// if((m_perfmon.GetFrame() & 255) == 0) m_rl.PrintStats();
2009-05-22 01:22:52 +00:00
}
2010-04-25 00:31:27 +00:00
void GSRendererSW : : ResetDevice ( )
2009-05-22 01:22:52 +00:00
{
for ( int i = 0 ; i < countof ( m_texture ) ; i + + )
{
delete m_texture [ i ] ;
m_texture [ i ] = NULL ;
}
}
GSTexture * GSRendererSW : : GetOutput ( int i )
{
2011-12-22 14:36:54 +00:00
Sync ( 1 ) ;
2011-12-18 08:13:20 +00:00
2009-05-22 01:22:52 +00:00
const GSRegDISPFB & DISPFB = m_regs - > DISP [ i ] . DISPFB ;
2009-07-22 03:55:28 +00:00
int w = DISPFB . FBW * 64 ;
2009-07-04 15:14:04 +00:00
int h = GetFrameRect ( i ) . bottom ;
2009-05-22 01:22:52 +00:00
// TODO: round up bottom
2009-07-04 15:14:04 +00:00
if ( m_dev - > ResizeTexture ( & m_texture [ i ] , w , h ) )
2009-05-22 01:22:52 +00:00
{
2009-07-04 15:14:04 +00:00
static int pitch = 1024 * 4 ;
2009-05-22 01:22:52 +00:00
2009-07-04 15:14:04 +00:00
GSVector4i r ( 0 , 0 , w , h ) ;
2009-05-22 01:22:52 +00:00
2009-07-22 03:55:28 +00:00
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ DISPFB . PSM ] ;
2011-03-12 22:10:58 +00:00
( m_mem . * psm . rtx ) ( m_mem . GetOffset ( DISPFB . Block ( ) , DISPFB . FBW , DISPFB . PSM ) , r . ralign < Align_Outside > ( psm . bs ) , m_output , pitch , m_env . TEXA ) ;
2009-05-22 01:22:52 +00:00
2011-02-19 03:36:30 +00:00
m_texture [ i ] - > Update ( r , m_output , pitch ) ;
2009-05-22 01:22:52 +00:00
2009-07-04 15:14:04 +00:00
if ( s_dump )
2009-05-22 01:22:52 +00:00
{
2009-07-05 12:58:59 +00:00
if ( s_save & & s_n > = s_saven )
2009-07-04 15:14:04 +00:00
{
2011-02-19 03:36:30 +00:00
m_texture [ i ] - > Save ( format ( " c: \\ temp1 \\ _%05d_f%lld_fr%d_%05x_%d.bmp " , s_n , m_perfmon . GetFrame ( ) , i , ( int ) DISPFB . Block ( ) , ( int ) DISPFB . PSM ) ) ;
2009-07-04 15:14:04 +00:00
}
2009-05-22 01:22:52 +00:00
2009-07-04 15:14:04 +00:00
s_n + + ;
}
2009-05-22 01:22:52 +00:00
}
return m_texture [ i ] ;
}
2012-01-19 04:53:36 +00:00
void GSRendererSW : : Draw ( )
2009-05-22 01:22:52 +00:00
{
2012-01-19 04:53:36 +00:00
SharedData * sd = new SharedData ( this ) ;
2012-01-06 00:17:52 +00:00
2012-01-19 04:53:36 +00:00
shared_ptr < GSRasterizerData > data ( sd ) ;
2012-01-08 17:10:00 +00:00
2012-01-19 04:53:36 +00:00
sd - > primclass = m_vt . m_primclass ;
sd - > buff = ( uint8 * ) _aligned_malloc ( sizeof ( GSVertexSW ) * m_vertex . next + sizeof ( uint32 ) * m_index . tail , 32 ) ;
sd - > vertex = ( GSVertexSW * ) sd - > buff ;
sd - > vertex_count = m_vertex . next ;
sd - > index = ( uint32 * ) ( sd - > buff + sizeof ( GSVertexSW ) * m_vertex . next ) ;
sd - > index_count = m_index . tail ;
2009-05-22 01:22:52 +00:00
2012-01-19 04:53:36 +00:00
{
// TODO: template, JIT
2011-12-27 09:15:35 +00:00
2012-01-19 04:53:36 +00:00
GSVertex * RESTRICT s = m_vertex . buff ;
GSVertexSW * RESTRICT d = sd - > vertex ;
2012-01-06 00:17:52 +00:00
2012-01-19 04:53:36 +00:00
GSVector4i o = ( GSVector4i ) m_context - > XYOFFSET ;
GSVector4 tsize = GSVector4 ( 0x10000 < < m_context - > TEX0 . TW , 0x10000 < < m_context - > TEX0 . TH ) ;
2011-12-27 09:15:35 +00:00
2012-01-19 04:53:36 +00:00
for ( size_t i = 0 ; i < m_vertex . next ; i + + , s + + , d + + )
2012-01-05 02:40:24 +00:00
{
2012-01-19 04:53:36 +00:00
uint32 z = s - > XYZ . Z ;
2009-05-22 01:22:52 +00:00
2012-01-19 04:53:36 +00:00
GSVector4i xy = GSVector4i : : load ( ( int ) s - > XYZ . u32 [ 0 ] ) . upl16 ( ) - o ;
GSVector4i zf = GSVector4i ( ( int ) std : : min < uint32 > ( z , 0xffffff00 ) , s - > FOG ) ; // NOTE: larger values of z may roll over to 0 when converting back to uint32 later
2012-01-06 00:17:52 +00:00
2012-01-19 04:53:36 +00:00
GSVector4 p , t , c ;
2012-01-05 02:40:24 +00:00
2012-01-19 04:53:36 +00:00
p = GSVector4 ( xy ) . xyxy ( GSVector4 ( zf ) + ( GSVector4 : : m_x4f800000 & GSVector4 : : cast ( zf . sra32 ( 31 ) ) ) ) * g_pos_scale ;
2012-01-08 17:10:00 +00:00
2012-01-19 04:53:36 +00:00
if ( PRIM - > TME )
{
if ( PRIM - > FST )
{
t = GSVector4 ( GSVector4i : : load ( s - > UV ) . upl16 ( ) < < ( 16 - 4 ) ) ;
}
else
{
t = GSVector4 ( s - > ST . S , s - > ST . T ) * tsize ;
t = t . xyxy ( GSVector4 : : load ( s - > RGBAQ . Q ) ) ;
}
}
2012-01-05 02:40:24 +00:00
2012-01-19 04:53:36 +00:00
c = GSVector4 : : rgba32 ( s - > RGBAQ . u32 [ 0 ] , 7 ) ;
2012-01-05 02:40:24 +00:00
2012-01-19 04:53:36 +00:00
d - > p = p ;
d - > c = c ;
d - > t = t ;
2012-01-05 02:40:24 +00:00
2012-01-19 04:53:36 +00:00
if ( sd - > primclass = = GS_SPRITE_CLASS )
{
d - > t . u32 [ 3 ] = z ;
}
}
}
2012-01-05 02:40:24 +00:00
2012-01-13 18:10:05 +00:00
memcpy ( sd - > index , m_index . buff , sizeof ( uint32 ) * m_index . tail ) ;
2012-01-05 02:40:24 +00:00
2012-01-13 18:10:05 +00:00
// TODO: delay texture update, do it later along with the syncing on the dispatcher thread, then this thread does not have to wait and can continue assembling more jobs
// TODO: if(any texture page is used as a target) GSRasterizerData::syncpoint = true;
// TODO: virtual void GSRasterizerData::Update() {texture[all levels]->Update();}, call it from the dispatcher thread before sending to workers
// TODO: m_tc->InvalidatePages must be called after texture->Update, move that inside GSRasterizerData::Update too
if ( ! GetScanlineGlobalData ( sd ) ) return ;
2012-01-05 02:40:24 +00:00
//
2012-01-08 17:10:00 +00:00
const GSDrawingContext * context = m_context ;
2009-05-22 01:22:52 +00:00
2012-01-08 17:10:00 +00:00
GSScanlineGlobalData & gd = sd - > global ;
2011-12-28 14:10:20 +00:00
2012-01-05 02:40:24 +00:00
GSVector4i scissor = GSVector4i ( context - > scissor . in ) ;
2012-01-19 04:53:36 +00:00
GSVector4i bbox = GSVector4i ( m_vt . m_min . p . floor ( ) . xyxy ( m_vt . m_max . p . ceil ( ) ) ) ;
2012-01-05 02:40:24 +00:00
scissor . z = std : : min < int > ( scissor . z , ( int ) context - > FRAME . FBW * 64 ) ; // TODO: find a game that overflows and check which one is the right behaviour
2012-01-13 18:10:05 +00:00
sd - > scissor = scissor ;
sd - > bbox = bbox ;
sd - > frame = m_perfmon . GetFrame ( ) ;
2011-12-18 08:13:20 +00:00
2011-12-25 07:26:42 +00:00
//
2012-01-05 02:40:24 +00:00
uint32 * fb_pages = NULL ;
uint32 * zb_pages = NULL ;
GSVector4i r = bbox . rintersect ( scissor ) ;
2011-12-28 20:21:32 +00:00
2012-01-08 17:10:00 +00:00
if ( gd . sel . fwrite )
2011-12-25 07:26:42 +00:00
{
2012-01-08 17:10:00 +00:00
fb_pages = context - > offset . fb - > GetPages ( r ) ;
2011-12-28 20:21:32 +00:00
2012-01-08 17:10:00 +00:00
m_tc - > InvalidatePages ( fb_pages , context - > offset . fb - > psm ) ;
2011-12-25 07:26:42 +00:00
}
2012-01-08 17:10:00 +00:00
if ( gd . sel . zwrite )
2011-12-25 07:26:42 +00:00
{
2012-01-08 17:10:00 +00:00
zb_pages = context - > offset . zb - > GetPages ( r ) ;
2011-12-28 20:21:32 +00:00
2012-01-08 17:10:00 +00:00
m_tc - > InvalidatePages ( zb_pages , context - > offset . zb - > psm ) ;
2011-12-25 07:26:42 +00:00
}
2012-01-18 11:47:31 +00:00
if ( CheckTargetPages ( fb_pages , zb_pages , r ) )
2011-12-25 07:26:42 +00:00
{
2012-01-18 11:47:31 +00:00
sd - > syncpoint = true ;
2011-12-25 07:26:42 +00:00
}
2009-05-22 01:22:52 +00:00
2012-01-08 17:10:00 +00:00
sd - > UseTargetPages ( fb_pages , zb_pages ) ;
2011-12-27 09:15:35 +00:00
2012-01-18 11:47:31 +00:00
if ( LOG ) { fprintf ( s_fp , " queue %05x %d %05x %d %05x %d %dx%d | %d %d %d \n " ,
m_context - > FRAME . Block ( ) , m_context - > FRAME . PSM ,
m_context - > ZBUF . Block ( ) , m_context - > ZBUF . PSM ,
PRIM - > TME ? m_context - > TEX0 . TBP0 : 0xfffff , m_context - > TEX0 . PSM , ( int ) m_context - > TEX0 . TW , ( int ) m_context - > TEX0 . TH ,
PRIM - > PRIM , sd - > vertex_count , sd - > index_count ) ; fflush ( s_fp ) ; }
2009-05-22 01:22:52 +00:00
2011-12-20 14:33:28 +00:00
if ( s_dump )
2011-12-18 21:57:48 +00:00
{
2011-12-22 14:36:54 +00:00
Sync ( 3 ) ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
uint64 frame = m_perfmon . GetFrame ( ) ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
string s ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
if ( s_save & & s_n > = s_saven & & PRIM - > TME )
{
s = format ( " c: \\ temp1 \\ _%05d_f%lld_tex_%05x_%d.bmp " , s_n , frame , ( int ) m_context - > TEX0 . TBP0 , ( int ) m_context - > TEX0 . PSM ) ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
m_mem . SaveBMP ( s , m_context - > TEX0 . TBP0 , m_context - > TEX0 . TBW , m_context - > TEX0 . PSM , 1 < < m_context - > TEX0 . TW , 1 < < m_context - > TEX0 . TH ) ;
}
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
s_n + + ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
if ( s_save & & s_n > = s_saven )
{
s = format ( " c: \\ temp1 \\ _%05d_f%lld_rt0_%05x_%d.bmp " , s_n , frame , m_context - > FRAME . Block ( ) , m_context - > FRAME . PSM ) ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
m_mem . SaveBMP ( s , m_context - > FRAME . Block ( ) , m_context - > FRAME . FBW , m_context - > FRAME . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
}
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
if ( s_savez & & s_n > = s_saven )
{
s = format ( " c: \\ temp1 \\ _%05d_f%lld_rz0_%05x_%d.bmp " , s_n , frame , m_context - > ZBUF . Block ( ) , m_context - > ZBUF . PSM ) ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
m_mem . SaveBMP ( s , m_context - > ZBUF . Block ( ) , m_context - > FRAME . FBW , m_context - > ZBUF . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
2011-12-18 21:57:48 +00:00
}
2011-12-20 14:33:28 +00:00
s_n + + ;
m_rl - > Queue ( data ) ;
2011-12-18 21:57:48 +00:00
2011-12-22 14:36:54 +00:00
Sync ( 4 ) ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
if ( s_save & & s_n > = s_saven )
2011-12-18 21:57:48 +00:00
{
2011-12-20 14:33:28 +00:00
s = format ( " c: \\ temp1 \\ _%05d_f%lld_rt1_%05x_%d.bmp " , s_n , frame , m_context - > FRAME . Block ( ) , m_context - > FRAME . PSM ) ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
m_mem . SaveBMP ( s , m_context - > FRAME . Block ( ) , m_context - > FRAME . FBW , m_context - > FRAME . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
}
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
if ( s_savez & & s_n > = s_saven )
{
s = format ( " c: \\ temp1 \\ _%05d_f%lld_rz1_%05x_%d.bmp " , s_n , frame , m_context - > ZBUF . Block ( ) , m_context - > ZBUF . PSM ) ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
m_mem . SaveBMP ( s , m_context - > ZBUF . Block ( ) , m_context - > FRAME . FBW , m_context - > ZBUF . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
2011-12-18 21:57:48 +00:00
}
2011-12-20 14:33:28 +00:00
s_n + + ;
2011-12-18 21:57:48 +00:00
}
else
{
m_rl - > Queue ( data ) ;
}
2009-05-22 01:22:52 +00:00
2011-12-18 08:13:20 +00:00
/*
2009-05-22 01:22:52 +00:00
if ( 0 ) //stats.ticks > 5000000)
{
2011-02-19 03:36:30 +00:00
printf ( " * [%lld | %012llx] ticks %lld prims %d (%d) pixels %d (%d) \n " ,
2011-12-18 08:13:20 +00:00
m_perfmon . GetFrame ( ) , gd - > sel . key ,
2010-04-25 00:31:27 +00:00
stats . ticks ,
stats . prims , stats . prims > 0 ? ( int ) ( stats . ticks / stats . prims ) : - 1 ,
2009-05-22 01:22:52 +00:00
stats . pixels , stats . pixels > 0 ? ( int ) ( stats . ticks / stats . pixels ) : - 1 ) ;
}
2011-12-18 08:13:20 +00:00
*/
}
2011-12-22 14:36:54 +00:00
void GSRendererSW : : Sync ( int reason )
2011-12-18 08:13:20 +00:00
{
2011-12-22 14:36:54 +00:00
//printf("sync %d\n", reason);
2011-12-18 21:57:48 +00:00
2011-12-22 01:48:16 +00:00
GSPerfMonAutoTimer pmat ( & m_perfmon , GSPerfMon : : Sync ) ;
2012-01-13 18:10:05 +00:00
uint64 t = __rdtsc ( ) ;
2011-12-18 08:13:20 +00:00
m_rl - > Sync ( ) ;
2012-01-08 17:10:00 +00:00
2012-01-18 11:47:31 +00:00
if ( 0 )
{
std : : string s = format ( " c: \\ temp1 \\ _%05d_f%lld_rt1_%05x_%d.bmp " , s_n , m_perfmon . GetFrame ( ) , m_context - > FRAME . Block ( ) , m_context - > FRAME . PSM ) ;
m_mem . SaveBMP ( s , m_context - > FRAME . Block ( ) , m_context - > FRAME . FBW , m_context - > FRAME . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
s_n + + ;
}
2012-01-13 18:10:05 +00:00
t = __rdtsc ( ) - t ;
2012-01-18 11:47:31 +00:00
int pixels = m_rl - > GetPixels ( ) ;
if ( LOG ) { fprintf ( s_fp , " sync n=%d r=%d t=%lld p=%d %c \n " , s_n , reason , t , pixels , t > 10000000 ? ' * ' : ' ' ) ; fflush ( s_fp ) ; }
2012-01-13 18:10:05 +00:00
2012-01-18 11:47:31 +00:00
m_perfmon . Put ( GSPerfMon : : Fillrate , pixels ) ;
2009-05-22 01:22:52 +00:00
}
void GSRendererSW : : InvalidateVideoMem ( const GIFRegBITBLTBUF & BITBLTBUF , const GSVector4i & r )
{
2011-12-18 21:57:48 +00:00
GSOffset * o = m_mem . GetOffset ( BITBLTBUF . DBP , BITBLTBUF . DBW , BITBLTBUF . DPSM ) ;
2012-01-18 11:47:31 +00:00
o - > GetPages ( r , m_tmp_pages ) ;
2011-12-18 21:57:48 +00:00
2011-12-25 07:26:42 +00:00
// check if the changing pages either used as a texture or a target
2011-12-18 21:57:48 +00:00
2012-01-18 11:47:31 +00:00
if ( ! m_rl - > IsSynced ( ) )
2011-12-18 21:57:48 +00:00
{
2012-01-18 11:47:31 +00:00
for ( uint32 * RESTRICT p = m_tmp_pages ; * p ! = GSOffset : : EOP ; p + + )
2011-12-18 21:57:48 +00:00
{
2012-01-18 11:47:31 +00:00
if ( m_fzb_pages [ * p ] | m_tex_pages [ * p ] )
{
Sync ( 5 ) ;
2011-12-18 21:57:48 +00:00
2012-01-18 11:47:31 +00:00
break ;
}
2011-12-18 21:57:48 +00:00
}
}
2012-01-13 18:10:05 +00:00
m_tc - > InvalidatePages ( m_tmp_pages , o - > psm ) ; // if texture update runs on a thread and Sync(5) happens then this must come later
2011-12-18 21:57:48 +00:00
}
2011-12-23 15:53:53 +00:00
void GSRendererSW : : InvalidateLocalMem ( const GIFRegBITBLTBUF & BITBLTBUF , const GSVector4i & r , bool clut )
2011-12-18 21:57:48 +00:00
{
2012-01-18 11:47:31 +00:00
if ( ! m_rl - > IsSynced ( ) )
2011-12-18 21:57:48 +00:00
{
2012-01-18 11:47:31 +00:00
GSOffset * o = m_mem . GetOffset ( BITBLTBUF . SBP , BITBLTBUF . SBW , BITBLTBUF . SPSM ) ;
o - > GetPages ( r , m_tmp_pages ) ;
2011-12-28 14:10:20 +00:00
2012-01-18 11:47:31 +00:00
for ( uint32 * RESTRICT p = m_tmp_pages ; * p ! = GSOffset : : EOP ; p + + )
2011-12-18 21:57:48 +00:00
{
2012-01-18 11:47:31 +00:00
if ( m_fzb_pages [ * p ] )
{
Sync ( 6 ) ;
2011-12-18 21:57:48 +00:00
2012-01-18 11:47:31 +00:00
break ;
}
2011-12-18 21:57:48 +00:00
}
}
}
2012-01-05 02:40:24 +00:00
void GSRendererSW : : UsePages ( const uint32 * pages , int type )
2011-12-18 21:57:48 +00:00
{
2011-12-28 14:10:20 +00:00
if ( type < 2 )
2011-12-23 15:53:53 +00:00
{
2012-01-05 02:40:24 +00:00
for ( const uint32 * p = pages ; * p ! = GSOffset : : EOP ; p + + )
2011-12-28 14:10:20 +00:00
{
2012-01-05 02:40:24 +00:00
ASSERT ( ( ( short * ) & m_fzb_pages [ * p ] ) [ type ] < SHRT_MAX ) ;
2011-12-25 07:26:42 +00:00
2012-01-05 02:40:24 +00:00
_InterlockedIncrement16 ( ( short * ) & m_fzb_pages [ * p ] + type ) ;
2011-12-28 14:10:20 +00:00
}
2011-12-23 15:53:53 +00:00
}
2011-12-28 14:10:20 +00:00
else
2011-12-18 21:57:48 +00:00
{
2012-01-18 11:47:31 +00:00
if ( ! m_rl - > IsSynced ( ) )
2011-12-28 14:10:20 +00:00
{
2012-01-18 11:47:31 +00:00
for ( const uint32 * p = pages ; * p ! = GSOffset : : EOP ; p + + )
2011-12-28 14:10:20 +00:00
{
2012-01-18 11:47:31 +00:00
if ( m_fzb_pages [ * p ] ) // currently being drawn to? => sync
{
Sync ( 7 ) ;
2011-12-28 14:10:20 +00:00
2012-01-18 11:47:31 +00:00
break ;
}
2011-12-28 14:10:20 +00:00
}
}
2012-01-05 02:40:24 +00:00
for ( const uint32 * p = pages ; * p ! = GSOffset : : EOP ; p + + )
2011-12-28 14:10:20 +00:00
{
2012-01-05 02:40:24 +00:00
ASSERT ( m_tex_pages [ * p ] < SHRT_MAX ) ;
2011-12-28 14:10:20 +00:00
2012-01-05 02:40:24 +00:00
_InterlockedIncrement16 ( ( short * ) & m_tex_pages [ * p ] ) ; // remember which texture pages are used
2011-12-28 14:10:20 +00:00
}
2011-12-23 15:53:53 +00:00
}
}
2011-12-18 21:57:48 +00:00
2012-01-05 02:40:24 +00:00
void GSRendererSW : : ReleasePages ( const uint32 * pages , int type )
2011-12-23 15:53:53 +00:00
{
2011-12-28 14:10:20 +00:00
if ( type < 2 )
2011-12-23 15:53:53 +00:00
{
2012-01-05 02:40:24 +00:00
for ( const uint32 * p = pages ; * p ! = GSOffset : : EOP ; p + + )
2011-12-18 21:57:48 +00:00
{
2012-01-05 02:40:24 +00:00
ASSERT ( ( ( short * ) & m_fzb_pages [ * p ] ) [ type ] > 0 ) ;
2011-12-18 21:57:48 +00:00
2012-01-05 02:40:24 +00:00
_InterlockedDecrement16 ( ( short * ) & m_fzb_pages [ * p ] + type ) ;
2011-12-18 21:57:48 +00:00
}
}
2011-12-28 14:10:20 +00:00
else
2011-12-23 15:53:53 +00:00
{
2012-01-05 02:40:24 +00:00
for ( const uint32 * p = pages ; * p ! = GSOffset : : EOP ; p + + )
2011-12-28 14:10:20 +00:00
{
2012-01-05 02:40:24 +00:00
ASSERT ( m_tex_pages [ * p ] > 0 ) ;
2011-12-28 14:10:20 +00:00
2012-01-05 02:40:24 +00:00
_InterlockedDecrement16 ( ( short * ) & m_tex_pages [ * p ] ) ;
2011-12-28 14:10:20 +00:00
}
2011-12-23 15:53:53 +00:00
}
2009-05-22 01:22:52 +00:00
}
2012-01-18 11:47:31 +00:00
bool GSRendererSW : : CheckTargetPages ( const uint32 * fb_pages , const uint32 * zb_pages , const GSVector4i & r )
2012-01-13 18:10:05 +00:00
{
2012-01-18 11:47:31 +00:00
bool synced = m_rl - > IsSynced ( ) ;
if ( m_fzb ! = m_context - > offset . fzb4 )
2012-01-13 18:10:05 +00:00
{
2012-01-18 11:47:31 +00:00
// targets changed, check everything
m_fzb = m_context - > offset . fzb4 ;
m_fzb_bbox = r ;
if ( fb_pages = = NULL ) fb_pages = m_context - > offset . fb - > GetPages ( r ) ;
if ( zb_pages = = NULL ) zb_pages = m_context - > offset . zb - > GetPages ( r ) ;
memset ( m_fzb_cur_pages , 0 , sizeof ( m_fzb_cur_pages ) ) ;
uint32 used = 0 ;
for ( const uint32 * p = fb_pages ; * p ! = GSOffset : : EOP ; p + + )
{
uint32 i = * p ;
uint32 row = i > > 5 ;
uint32 col = 1 < < ( i & 31 ) ;
m_fzb_cur_pages [ row ] | = col ;
used | = m_fzb_pages [ i ] ;
}
for ( const uint32 * p = zb_pages ; * p ! = GSOffset : : EOP ; p + + )
2012-01-13 18:10:05 +00:00
{
2012-01-18 11:47:31 +00:00
uint32 i = * p ;
uint32 row = i > > 5 ;
uint32 col = 1 < < ( i & 31 ) ;
m_fzb_cur_pages [ row ] | = col ;
used | = m_fzb_pages [ i ] ;
}
if ( ! synced )
{
if ( used )
{
if ( LOG ) { fprintf ( s_fp , " syncpoint 0 \n " ) ; fflush ( s_fp ) ; }
return true ;
}
if ( LOG ) { fprintf ( s_fp , " no syncpoint * \n " ) ; fflush ( s_fp ) ; }
}
}
else
{
// same target, only check new areas and cross-rendering between frame and z-buffer
GSVector4i bbox = m_fzb_bbox . runion ( r ) ;
bool check = ! m_fzb_bbox . eq ( bbox ) ;
m_fzb_bbox = bbox ;
if ( check )
{
// drawing area is larger than previous time, check new parts only to avoid false positives (m_fzb_cur_pages guards)
if ( fb_pages = = NULL ) fb_pages = m_context - > offset . fb - > GetPages ( r ) ;
if ( zb_pages = = NULL ) zb_pages = m_context - > offset . zb - > GetPages ( r ) ;
uint32 used = 0 ;
for ( const uint32 * p = fb_pages ; * p ! = GSOffset : : EOP ; p + + )
{
uint32 i = * p ;
uint32 row = i > > 5 ;
uint32 col = 1 < < ( i & 31 ) ;
if ( ( m_fzb_cur_pages [ row ] & col ) = = 0 )
{
m_fzb_cur_pages [ row ] | = col ;
used | = m_fzb_pages [ i ] ;
}
}
for ( const uint32 * p = zb_pages ; * p ! = GSOffset : : EOP ; p + + )
{
uint32 i = * p ;
uint32 row = i > > 5 ;
uint32 col = 1 < < ( i & 31 ) ;
if ( ( m_fzb_cur_pages [ row ] & col ) = = 0 )
{
m_fzb_cur_pages [ row ] | = col ;
used | = m_fzb_pages [ i ] ;
}
}
if ( ! synced )
{
if ( used )
{
if ( LOG ) { fprintf ( s_fp , " syncpoint 1 \n " ) ; fflush ( s_fp ) ; }
return true ;
}
}
}
if ( ! synced )
{
// chross-check frame and z-buffer pages, they cannot overlap with eachother and with previous batches in queue,
// have to be careful when the two buffers are mutually enabled/disabled and alternating (Bully FBP/ZBP = 0x2300)
if ( fb_pages )
{
for ( const uint32 * p = fb_pages ; * p ! = GSOffset : : EOP ; p + + )
{
if ( m_fzb_pages [ * p ] & 0xffff0000 )
{
if ( LOG ) { fprintf ( s_fp , " syncpoint 2 \n " ) ; fflush ( s_fp ) ; }
return true ;
}
}
}
if ( zb_pages )
{
for ( const uint32 * p = zb_pages ; * p ! = GSOffset : : EOP ; p + + )
{
if ( m_fzb_pages [ * p ] & 0x0000ffff )
{
if ( LOG ) { fprintf ( s_fp , " syncpoint 3 \n " ) ; fflush ( s_fp ) ; }
return true ;
}
}
}
2012-01-13 18:10:05 +00:00
}
}
return false ;
}
2011-03-17 02:55:20 +00:00
# include "GSTextureSW.h"
2012-01-08 17:10:00 +00:00
bool GSRendererSW : : GetScanlineGlobalData ( SharedData * data )
2009-05-22 01:22:52 +00:00
{
2012-01-08 17:10:00 +00:00
GSScanlineGlobalData & gd = data - > global ;
2011-12-28 14:10:20 +00:00
2009-05-22 01:22:52 +00:00
const GSDrawingEnvironment & env = m_env ;
const GSDrawingContext * context = m_context ;
2012-01-19 04:53:36 +00:00
const GS_PRIM_CLASS primclass = m_vt . m_primclass ;
2009-05-22 01:22:52 +00:00
2011-02-17 03:24:37 +00:00
gd . vm = m_mem . m_vm8 ;
2009-05-22 01:22:52 +00:00
2011-02-17 03:24:37 +00:00
gd . fbr = context - > offset . fb - > pixel . row ;
gd . zbr = context - > offset . zb - > pixel . row ;
gd . fbc = context - > offset . fb - > pixel . col [ 0 ] ;
gd . zbc = context - > offset . zb - > pixel . col [ 0 ] ;
2012-01-18 11:47:31 +00:00
gd . fzbr = context - > offset . fzb4 - > row ;
gd . fzbc = context - > offset . fzb4 - > col ;
2009-05-22 01:22:52 +00:00
2011-02-17 03:24:37 +00:00
gd . sel . key = 0 ;
2009-05-22 01:22:52 +00:00
2011-02-17 03:24:37 +00:00
gd . sel . fpsm = 3 ;
gd . sel . zpsm = 3 ;
gd . sel . atst = ATST_ALWAYS ;
gd . sel . tfx = TFX_NONE ;
gd . sel . ababcd = 255 ;
2012-01-05 02:40:24 +00:00
gd . sel . prim = primclass ;
2009-05-22 01:22:52 +00:00
2011-02-17 03:24:37 +00:00
uint32 fm = context - > FRAME . FBMSK ;
uint32 zm = context - > ZBUF . ZMSK | | context - > TEST . ZTE = = 0 ? 0xffffffff : 0 ;
2009-05-22 01:22:52 +00:00
if ( context - > TEST . ZTE & & context - > TEST . ZTST = = ZTST_NEVER )
{
2011-02-17 03:24:37 +00:00
fm = 0xffffffff ;
zm = 0xffffffff ;
2009-05-22 01:22:52 +00:00
}
if ( PRIM - > TME )
{
m_mem . m_clut . Read32 ( context - > TEX0 , env . TEXA ) ;
}
if ( context - > TEST . ATE )
{
2011-02-17 03:24:37 +00:00
if ( ! TryAlphaTest ( fm , zm ) )
2009-05-22 01:22:52 +00:00
{
2011-02-17 03:24:37 +00:00
gd . sel . atst = context - > TEST . ATST ;
gd . sel . afail = context - > TEST . AFAIL ;
gd . aref = GSVector4i ( ( int ) context - > TEST . AREF ) ;
switch ( gd . sel . atst )
{
case ATST_LESS :
gd . sel . atst = ATST_LEQUAL ;
gd . aref - = GSVector4i : : x00000001 ( ) ;
break ;
case ATST_GREATER :
gd . sel . atst = ATST_GEQUAL ;
gd . aref + = GSVector4i : : x00000001 ( ) ;
break ;
}
2009-05-22 01:22:52 +00:00
}
}
2011-02-17 03:24:37 +00:00
bool fwrite = fm ! = 0xffffffff ;
bool ftest = gd . sel . atst ! = ATST_ALWAYS | | context - > TEST . DATE & & context - > FRAME . PSM ! = PSM_PSMCT24 ;
2009-05-22 01:22:52 +00:00
2011-12-18 08:13:20 +00:00
bool zwrite = zm ! = 0xffffffff ;
bool ztest = context - > TEST . ZTE & & context - > TEST . ZTST > ZTST_ALWAYS ;
2011-12-31 15:41:07 +00:00
/*
printf ( " %05x %d %05x %d %05x %d %dx%d \n " ,
fwrite | | ftest ? m_context - > FRAME . Block ( ) : 0xfffff , m_context - > FRAME . PSM ,
zwrite | | ztest ? m_context - > ZBUF . Block ( ) : 0xfffff , m_context - > ZBUF . PSM ,
PRIM - > TME ? m_context - > TEX0 . TBP0 : 0xfffff , m_context - > TEX0 . PSM , ( int ) m_context - > TEX0 . TW , ( int ) m_context - > TEX0 . TH ) ;
*/
2011-12-18 08:13:20 +00:00
if ( ! fwrite & & ! zwrite ) return false ;
2011-02-17 03:24:37 +00:00
gd . sel . fwrite = fwrite ;
gd . sel . ftest = ftest ;
2009-05-22 01:22:52 +00:00
if ( fwrite | | ftest )
{
2011-02-17 03:24:37 +00:00
gd . sel . fpsm = GSLocalMemory : : m_psm [ context - > FRAME . PSM ] . fmt ;
2009-05-22 01:22:52 +00:00
2012-01-19 04:53:36 +00:00
if ( ( primclass = = GS_LINE_CLASS | | primclass = = GS_TRIANGLE_CLASS ) & & m_vt . m_eq . rgba ! = 0xffff )
2009-05-22 01:22:52 +00:00
{
2011-02-17 03:24:37 +00:00
gd . sel . iip = PRIM - > IIP ;
2009-05-22 01:22:52 +00:00
}
if ( PRIM - > TME )
{
2011-02-17 03:24:37 +00:00
gd . sel . tfx = context - > TEX0 . TFX ;
gd . sel . tcc = context - > TEX0 . TCC ;
gd . sel . fst = PRIM - > FST ;
2012-01-19 04:53:36 +00:00
gd . sel . ltf = m_vt . IsLinear ( ) ;
2011-12-18 08:13:20 +00:00
if ( GSLocalMemory : : m_psm [ context - > TEX0 . PSM ] . pal > 0 )
{
gd . sel . tlu = 1 ;
gd . clut = ( uint32 * ) _aligned_malloc ( sizeof ( uint32 ) * 256 , 32 ) ; // FIXME: might address uninitialized data of the texture (0xCD) that is not in 0-15 range for 4-bpp formats
memcpy ( gd . clut , ( const uint32 * ) m_mem . m_clut , sizeof ( uint32 ) * GSLocalMemory : : m_psm [ context - > TEX0 . PSM ] . pal ) ;
}
2011-02-17 03:24:37 +00:00
gd . sel . wms = context - > CLAMP . WMS ;
gd . sel . wmt = context - > CLAMP . WMT ;
2012-01-19 04:53:36 +00:00
if ( gd . sel . tfx = = TFX_MODULATE & & gd . sel . tcc & & m_vt . m_eq . rgba = = 0xffff & & m_vt . m_min . c . eq ( GSVector4i ( 128 ) ) )
2009-05-22 01:22:52 +00:00
{
2009-06-23 04:12:32 +00:00
// modulate does not do anything when vertex color is 0x80
2009-05-22 01:22:52 +00:00
2011-02-17 03:24:37 +00:00
gd . sel . tfx = TFX_DECAL ;
2009-05-22 01:22:52 +00:00
}
2011-12-18 08:13:20 +00:00
GSTextureCacheSW : : Texture * t = m_tc - > Lookup ( context - > TEX0 , env . TEXA ) ;
if ( t = = NULL ) { ASSERT ( 0 ) ; return false ; }
2012-01-08 17:10:00 +00:00
data - > UseSourcePages ( t , 0 ) ;
2011-12-18 08:13:20 +00:00
2011-03-17 02:55:20 +00:00
GSVector4i r ;
2009-05-22 01:22:52 +00:00
2011-03-17 02:55:20 +00:00
GetTextureMinMax ( r , context - > TEX0 , context - > CLAMP , gd . sel . ltf ) ;
2009-05-22 01:22:52 +00:00
2011-12-18 08:13:20 +00:00
if ( ! t - > Update ( r ) ) { ASSERT ( 0 ) ; return false ; }
2009-05-22 01:22:52 +00:00
2012-01-19 04:53:36 +00:00
if ( s_dump ) // && m_context->TEX1.MXL > 0 && m_context->TEX1.MMIN >= 2 && m_context->TEX1.MMIN <= 5 && m_vt.m_lod.x > 0)
2011-07-25 11:16:01 +00:00
{
uint64 frame = m_perfmon . GetFrame ( ) ;
string s ;
2011-12-24 15:02:48 +00:00
if ( s_save & & s_n > = s_saven )
2011-07-25 11:16:01 +00:00
{
s = format ( " c: \\ temp1 \\ _%05d_f%lld_tex32_%05x_%d.bmp " , s_n , frame , ( int ) m_context - > TEX0 . TBP0 , ( int ) m_context - > TEX0 . PSM ) ;
t - > Save ( s ) ;
}
}
2011-03-17 02:55:20 +00:00
gd . tex [ 0 ] = t - > m_buff ;
gd . sel . tw = t - > m_tw - 3 ;
2011-03-12 22:10:58 +00:00
2012-01-19 04:53:36 +00:00
if ( m_mipmap & & context - > TEX1 . MXL > 0 & & context - > TEX1 . MMIN > = 2 & & context - > TEX1 . MMIN < = 5 & & m_vt . m_lod . y > 0 )
2011-03-12 22:10:58 +00:00
{
2011-03-19 00:54:03 +00:00
// TEX1.MMIN
// 000 p
// 001 l
// 010 p round
// 011 p tri
// 100 l round
// 101 l tri
2011-12-19 01:20:55 +00:00
2012-01-19 04:53:36 +00:00
if ( m_vt . m_lod . x > 0 )
2011-03-19 00:54:03 +00:00
{
2011-03-19 03:54:22 +00:00
gd . sel . ltf = context - > TEX1 . MMIN > > 2 ;
2011-03-19 00:54:03 +00:00
}
else
{
2012-01-19 04:53:36 +00:00
// TODO: isbilinear(mmag) != isbilinear(mmin) && m_vt.m_lod.x <= 0 && m_vt.m_lod.y > 0
2011-03-19 00:54:03 +00:00
}
gd . sel . mmin = ( context - > TEX1 . MMIN & 1 ) + 1 ; // 1: round, 2: tri
2011-03-14 03:32:28 +00:00
gd . sel . lcm = context - > TEX1 . LCM ;
2011-03-19 00:54:03 +00:00
int mxl = ( std : : min < int > ( ( int ) context - > TEX1 . MXL , 6 ) < < 16 ) ;
2011-03-17 02:55:20 +00:00
int k = context - > TEX1 . K < < 12 ;
2012-01-19 04:53:36 +00:00
if ( ( int ) m_vt . m_lod . x > = ( int ) context - > TEX1 . MXL )
2011-03-28 04:15:36 +00:00
{
2012-01-19 04:53:36 +00:00
k = ( int ) m_vt . m_lod . x < < 16 ; // set lod to max level
2011-03-28 04:15:36 +00:00
gd . sel . lcm = 1 ; // lod is constant
gd . sel . mmin = 1 ; // tri-linear is meaningless
}
2011-03-19 00:54:03 +00:00
if ( gd . sel . mmin = = 2 )
{
2011-03-27 03:12:12 +00:00
mxl - - ; // don't sample beyond the last level (TODO: add a dummy level instead?)
2011-03-19 00:54:03 +00:00
}
2011-03-19 03:54:22 +00:00
if ( gd . sel . fst )
{
ASSERT ( gd . sel . lcm = = 1 ) ;
2012-01-19 04:53:36 +00:00
ASSERT ( ( ( m_vt . m_min . t . uph ( m_vt . m_max . t ) = = GSVector4 : : zero ( ) ) . mask ( ) & 3 ) = = 3 ) ; // ratchet and clank (menu)
2011-03-19 03:54:22 +00:00
gd . sel . lcm = 1 ;
}
2011-03-17 02:55:20 +00:00
if ( gd . sel . lcm )
{
2011-03-19 03:54:22 +00:00
int lod = std : : max < int > ( std : : min < int > ( k , mxl ) , 0 ) ;
if ( gd . sel . mmin = = 1 )
{
lod = ( lod + 0x8000 ) & 0xffff0000 ; // rounding
}
2011-03-17 02:55:20 +00:00
gd . lod . i = GSVector4i ( lod > > 16 ) ;
gd . lod . f = GSVector4i ( lod & 0xffff ) . xxxxl ( ) . xxzz ( ) ;
2011-03-14 03:32:28 +00:00
2011-03-17 02:55:20 +00:00
// TODO: lot to optimize when lod is constant
}
2011-03-27 03:12:12 +00:00
else
{
gd . mxl = GSVector4 ( ( float ) mxl ) ;
gd . l = GSVector4 ( ( float ) ( - 0x10000 < < context - > TEX1 . L ) ) ;
gd . k = GSVector4 ( ( float ) k ) ;
}
2011-03-12 22:10:58 +00:00
2011-03-17 02:55:20 +00:00
GIFRegTEX0 MIP_TEX0 = context - > TEX0 ;
GIFRegCLAMP MIP_CLAMP = context - > CLAMP ;
2011-03-12 22:10:58 +00:00
2012-01-19 04:53:36 +00:00
GSVector4 tmin = m_vt . m_min . t ;
GSVector4 tmax = m_vt . m_max . t ;
2011-03-12 22:10:58 +00:00
2011-03-19 03:54:22 +00:00
static int s_counter = 0 ;
2011-03-17 02:55:20 +00:00
2011-04-04 11:05:54 +00:00
if ( 0 )
//if(context->TEX0.TH > context->TEX0.TW)
//if(s_n >= s_saven && s_n < s_saven + 3)
//if(context->TEX0.TBP0 >= 0x2b80 && context->TEX0.TBW == 2 && context->TEX0.PSM == PSM_PSMT4)
t - > Save ( format ( " c:/temp1/%08d_%05x_0.bmp " , s_counter , context - > TEX0 . TBP0 ) ) ;
2011-03-17 02:55:20 +00:00
for ( int i = 1 , j = std : : min < int > ( ( int ) context - > TEX1 . MXL , 6 ) ; i < = j ; i + + )
{
switch ( i )
2011-03-12 22:10:58 +00:00
{
2011-12-19 01:20:55 +00:00
case 1 :
MIP_TEX0 . TBP0 = context - > MIPTBP1 . TBP1 ;
MIP_TEX0 . TBW = context - > MIPTBP1 . TBW1 ;
2011-03-12 22:10:58 +00:00
break ;
2011-12-19 01:20:55 +00:00
case 2 :
MIP_TEX0 . TBP0 = context - > MIPTBP1 . TBP2 ;
MIP_TEX0 . TBW = context - > MIPTBP1 . TBW2 ;
2011-03-12 22:10:58 +00:00
break ;
2011-12-19 01:20:55 +00:00
case 3 :
MIP_TEX0 . TBP0 = context - > MIPTBP1 . TBP3 ;
MIP_TEX0 . TBW = context - > MIPTBP1 . TBW3 ;
2011-03-12 22:10:58 +00:00
break ;
2011-12-19 01:20:55 +00:00
case 4 :
MIP_TEX0 . TBP0 = context - > MIPTBP2 . TBP4 ;
MIP_TEX0 . TBW = context - > MIPTBP2 . TBW4 ;
2011-03-12 22:10:58 +00:00
break ;
2011-12-19 01:20:55 +00:00
case 5 :
MIP_TEX0 . TBP0 = context - > MIPTBP2 . TBP5 ;
MIP_TEX0 . TBW = context - > MIPTBP2 . TBW5 ;
2011-03-12 22:10:58 +00:00
break ;
2011-12-19 01:20:55 +00:00
case 6 :
MIP_TEX0 . TBP0 = context - > MIPTBP2 . TBP6 ;
MIP_TEX0 . TBW = context - > MIPTBP2 . TBW6 ;
2011-03-12 22:10:58 +00:00
break ;
default :
__assume ( 0 ) ;
}
2011-03-17 02:55:20 +00:00
if ( MIP_TEX0 . TW > 0 ) MIP_TEX0 . TW - - ;
if ( MIP_TEX0 . TH > 0 ) MIP_TEX0 . TH - - ;
2011-03-12 22:10:58 +00:00
2011-03-17 02:55:20 +00:00
MIP_CLAMP . MINU > > = 1 ;
MIP_CLAMP . MINV > > = 1 ;
MIP_CLAMP . MAXU > > = 1 ;
MIP_CLAMP . MAXV > > = 1 ;
2011-03-12 22:10:58 +00:00
2012-01-19 04:53:36 +00:00
m_vt . m_min . t * = 0.5f ;
m_vt . m_max . t * = 0.5f ;
2011-03-12 22:10:58 +00:00
2011-12-18 08:13:20 +00:00
GSTextureCacheSW : : Texture * t = m_tc - > Lookup ( MIP_TEX0 , env . TEXA , gd . sel . tw + 3 ) ;
if ( t = = NULL ) { ASSERT ( 0 ) ; return false ; }
2012-01-08 17:10:00 +00:00
data - > UseSourcePages ( t , i ) ;
2011-12-18 08:13:20 +00:00
2011-03-17 02:55:20 +00:00
GSVector4i r ;
2011-03-12 22:10:58 +00:00
2011-03-17 02:55:20 +00:00
GetTextureMinMax ( r , MIP_TEX0 , MIP_CLAMP , gd . sel . ltf ) ;
2011-03-12 22:10:58 +00:00
2011-12-18 08:13:20 +00:00
if ( ! t - > Update ( r ) ) { ASSERT ( 0 ) ; return false ; }
2011-03-12 22:10:58 +00:00
2011-03-17 02:55:20 +00:00
gd . tex [ i ] = t - > m_buff ;
2011-03-12 22:10:58 +00:00
2011-04-04 11:05:54 +00:00
if ( 0 )
//if(context->TEX0.TH > context->TEX0.TW)
//if(s_n >= s_saven && s_n < s_saven + 3)
//if(context->TEX0.TBP0 >= 0x2b80 && context->TEX0.TBW == 2 && context->TEX0.PSM == PSM_PSMT4)
{
t - > Save ( format ( " c:/temp1/%08d_%05x_%d.bmp " , s_counter , context - > TEX0 . TBP0 , i ) ) ;
/*
GIFRegTEX0 TEX0 = MIP_TEX0 ;
TEX0 . TBP0 = context - > TEX0 . TBP0 ;
do
{
TEX0 . TBP0 + + ;
const GSTextureCacheSW : : Texture * t = m_tc - > Lookup ( TEX0 , env . TEXA , r , gd . sel . tw + 3 ) ;
if ( t = = NULL ) { ASSERT ( 0 ) ; return false ; }
t - > Save ( format ( " c:/temp1/%08d_%05x_%d.bmp " , s_counter , TEX0 . TBP0 , i ) ) ;
}
while ( TEX0 . TBP0 < 0x3fff ) ;
*/
int i = 0 ;
}
2011-03-17 02:55:20 +00:00
}
2011-03-12 22:10:58 +00:00
2011-03-19 03:54:22 +00:00
s_counter + + ;
2011-03-17 02:55:20 +00:00
2012-01-19 04:53:36 +00:00
m_vt . m_min . t = tmin ;
m_vt . m_max . t = tmax ;
2011-03-17 02:55:20 +00:00
}
else
{
if ( gd . sel . fst = = 0 )
{
// skip per pixel division if q is constant
2012-01-13 18:10:05 +00:00
GSVertexSW * RESTRICT v = data - > vertex ;
2011-03-17 02:55:20 +00:00
2012-01-19 04:53:36 +00:00
if ( m_vt . m_eq . q )
2011-03-12 22:10:58 +00:00
{
2011-03-17 02:55:20 +00:00
gd . sel . fst = 1 ;
2011-03-12 22:10:58 +00:00
2012-01-13 18:10:05 +00:00
const GSVector4 & t = v [ data - > index [ 0 ] ] . t ;
2012-01-05 02:40:24 +00:00
if ( t . z ! = 1.0f )
2011-03-17 02:55:20 +00:00
{
2012-01-05 02:40:24 +00:00
GSVector4 w = t . zzzz ( ) . rcpnr ( ) ;
2011-03-17 02:55:20 +00:00
2012-01-13 18:10:05 +00:00
for ( int i = 0 , j = data - > vertex_count ; i < j ; i + + )
2011-03-17 02:55:20 +00:00
{
2011-12-01 17:08:10 +00:00
GSVector4 t = v [ i ] . t ;
v [ i ] . t = ( t * w ) . xyzw ( t ) ;
2011-03-17 02:55:20 +00:00
}
}
}
else if ( primclass = = GS_SPRITE_CLASS )
{
gd . sel . fst = 1 ;
2012-01-13 18:10:05 +00:00
for ( int i = 0 , j = data - > vertex_count ; i < j ; i + = 2 )
2011-03-12 22:10:58 +00:00
{
2011-12-01 17:08:10 +00:00
GSVector4 t0 = v [ i + 0 ] . t ;
GSVector4 t1 = v [ i + 1 ] . t ;
GSVector4 w = t1 . zzzz ( ) . rcpnr ( ) ;
2011-03-17 02:55:20 +00:00
2011-12-01 17:08:10 +00:00
v [ i + 0 ] . t = ( t0 * w ) . xyzw ( t0 ) ;
v [ i + 1 ] . t = ( t1 * w ) . xyzw ( t1 ) ;
2011-03-12 22:10:58 +00:00
}
}
}
2011-03-17 02:55:20 +00:00
if ( gd . sel . ltf & & gd . sel . fst )
2009-05-22 01:22:52 +00:00
{
2009-06-23 04:12:32 +00:00
// if q is constant we can do the half pel shift for bilinear sampling on the vertices
2009-05-22 01:22:52 +00:00
2011-03-17 02:55:20 +00:00
// TODO: but not when mipmapping is used!!!
2011-03-08 01:48:15 +00:00
GSVector4 half ( 0x8000 , 0x8000 ) ;
2012-01-13 18:10:05 +00:00
GSVertexSW * RESTRICT v = data - > vertex ;
2009-05-22 01:22:52 +00:00
2012-01-13 18:10:05 +00:00
for ( int i = 0 , j = data - > vertex_count ; i < j ; i + + )
2009-05-22 01:22:52 +00:00
{
2011-12-01 17:08:10 +00:00
GSVector4 t = v [ i ] . t ;
v [ i ] . t = ( t - half ) . xyzw ( t ) ;
2009-05-22 01:22:52 +00:00
}
}
}
2011-03-17 02:55:20 +00:00
uint16 tw = 1u < < context - > TEX0 . TW ;
uint16 th = 1u < < context - > TEX0 . TH ;
2011-02-17 03:24:37 +00:00
2011-03-17 02:55:20 +00:00
switch ( context - > CLAMP . WMS )
2011-02-17 03:24:37 +00:00
{
case CLAMP_REPEAT :
2011-03-17 02:55:20 +00:00
gd . t . min . u16 [ 0 ] = gd . t . minmax . u16 [ 0 ] = tw - 1 ;
gd . t . max . u16 [ 0 ] = gd . t . minmax . u16 [ 2 ] = 0 ;
2011-02-17 03:24:37 +00:00
gd . t . mask . u32 [ 0 ] = 0xffffffff ;
break ;
case CLAMP_CLAMP :
2011-03-17 02:55:20 +00:00
gd . t . min . u16 [ 0 ] = gd . t . minmax . u16 [ 0 ] = 0 ;
gd . t . max . u16 [ 0 ] = gd . t . minmax . u16 [ 2 ] = tw - 1 ;
2011-02-17 03:24:37 +00:00
gd . t . mask . u32 [ 0 ] = 0 ;
break ;
case CLAMP_REGION_CLAMP :
2011-03-17 02:55:20 +00:00
gd . t . min . u16 [ 0 ] = gd . t . minmax . u16 [ 0 ] = std : : min < uint16 > ( context - > CLAMP . MINU , tw - 1 ) ;
gd . t . max . u16 [ 0 ] = gd . t . minmax . u16 [ 2 ] = std : : min < uint16 > ( context - > CLAMP . MAXU , tw - 1 ) ;
2011-02-17 03:24:37 +00:00
gd . t . mask . u32 [ 0 ] = 0 ;
break ;
case CLAMP_REGION_REPEAT :
2011-03-17 02:55:20 +00:00
gd . t . min . u16 [ 0 ] = gd . t . minmax . u16 [ 0 ] = context - > CLAMP . MINU ;
gd . t . max . u16 [ 0 ] = gd . t . minmax . u16 [ 2 ] = context - > CLAMP . MAXU ;
2011-02-17 03:24:37 +00:00
gd . t . mask . u32 [ 0 ] = 0xffffffff ;
break ;
default :
__assume ( 0 ) ;
}
2011-02-12 21:45:16 +00:00
2011-03-17 02:55:20 +00:00
switch ( context - > CLAMP . WMT )
2011-02-17 03:24:37 +00:00
{
case CLAMP_REPEAT :
2011-03-17 02:55:20 +00:00
gd . t . min . u16 [ 4 ] = gd . t . minmax . u16 [ 1 ] = th - 1 ;
gd . t . max . u16 [ 4 ] = gd . t . minmax . u16 [ 3 ] = 0 ;
2011-02-17 03:24:37 +00:00
gd . t . mask . u32 [ 2 ] = 0xffffffff ;
break ;
case CLAMP_CLAMP :
2011-03-17 02:55:20 +00:00
gd . t . min . u16 [ 4 ] = gd . t . minmax . u16 [ 1 ] = 0 ;
gd . t . max . u16 [ 4 ] = gd . t . minmax . u16 [ 3 ] = th - 1 ;
2011-02-17 03:24:37 +00:00
gd . t . mask . u32 [ 2 ] = 0 ;
break ;
case CLAMP_REGION_CLAMP :
2011-03-17 02:55:20 +00:00
gd . t . min . u16 [ 4 ] = gd . t . minmax . u16 [ 1 ] = std : : min < uint16 > ( context - > CLAMP . MINV , th - 1 ) ;
gd . t . max . u16 [ 4 ] = gd . t . minmax . u16 [ 3 ] = std : : min < uint16 > ( context - > CLAMP . MAXV , th - 1 ) ; // ffx anima summon scene, when the anchor appears (th = 256, maxv > 256)
2011-02-17 03:24:37 +00:00
gd . t . mask . u32 [ 2 ] = 0 ;
break ;
case CLAMP_REGION_REPEAT :
2011-03-17 02:55:20 +00:00
gd . t . min . u16 [ 4 ] = gd . t . minmax . u16 [ 1 ] = context - > CLAMP . MINV ;
gd . t . max . u16 [ 4 ] = gd . t . minmax . u16 [ 3 ] = context - > CLAMP . MAXV ;
2011-02-17 03:24:37 +00:00
gd . t . mask . u32 [ 2 ] = 0xffffffff ;
break ;
default :
__assume ( 0 ) ;
}
gd . t . min = gd . t . min . xxxxlh ( ) ;
gd . t . max = gd . t . max . xxxxlh ( ) ;
gd . t . mask = gd . t . mask . xxzz ( ) ;
gd . t . invmask = ~ gd . t . mask ;
2009-05-22 01:22:52 +00:00
}
2011-02-17 03:24:37 +00:00
if ( PRIM - > FGE )
{
gd . sel . fge = 1 ;
gd . frb = GSVector4i ( ( int ) env . FOGCOL . u32 [ 0 ] & 0x00ff00ff ) ;
gd . fga = GSVector4i ( ( int ) ( env . FOGCOL . u32 [ 0 ] > > 8 ) & 0x00ff00ff ) ;
}
2009-05-22 01:22:52 +00:00
if ( context - > FRAME . PSM ! = PSM_PSMCT24 )
{
2011-02-17 03:24:37 +00:00
gd . sel . date = context - > TEST . DATE ;
gd . sel . datm = context - > TEST . DATM ;
2009-05-22 01:22:52 +00:00
}
2009-06-23 04:12:32 +00:00
if ( ! IsOpaque ( ) )
2009-05-22 01:22:52 +00:00
{
2011-02-17 03:24:37 +00:00
gd . sel . abe = PRIM - > ABE ;
gd . sel . ababcd = context - > ALPHA . u32 [ 0 ] ;
2009-05-22 01:22:52 +00:00
if ( env . PABE . PABE )
{
2011-02-17 03:24:37 +00:00
gd . sel . pabe = 1 ;
2009-05-22 01:22:52 +00:00
}
2009-08-07 21:11:27 +00:00
if ( m_aa1 & & PRIM - > AA1 & & ( primclass = = GS_LINE_CLASS | | primclass = = GS_TRIANGLE_CLASS ) )
2009-05-22 01:22:52 +00:00
{
2011-02-17 03:24:37 +00:00
gd . sel . aa1 = 1 ;
2009-05-22 01:22:52 +00:00
}
2011-02-17 03:24:37 +00:00
gd . afix = GSVector4i ( ( int ) context - > ALPHA . FIX < < 7 ) . xxzzlh ( ) ;
2009-05-22 01:22:52 +00:00
}
2011-02-17 03:24:37 +00:00
if ( gd . sel . date
| | gd . sel . aba = = 1 | | gd . sel . abb = = 1 | | gd . sel . abc = = 1 | | gd . sel . abd = = 1
| | gd . sel . atst ! = ATST_ALWAYS & & gd . sel . afail = = AFAIL_RGB_ONLY
| | gd . sel . fpsm = = 0 & & fm ! = 0 & & fm ! = 0xffffffff
| | gd . sel . fpsm = = 1 & & ( fm & 0x00ffffff ) ! = 0 & & ( fm & 0x00ffffff ) ! = 0x00ffffff
| | gd . sel . fpsm = = 2 & & ( fm & 0x80f8f8f8 ) ! = 0 & & ( fm & 0x80f8f8f8 ) ! = 0x80f8f8f8 )
2009-05-22 01:22:52 +00:00
{
2011-02-17 03:24:37 +00:00
gd . sel . rfb = 1 ;
2009-05-22 01:22:52 +00:00
}
2011-02-17 03:24:37 +00:00
gd . sel . colclamp = env . COLCLAMP . CLAMP ;
gd . sel . fba = context - > FBA . FBA ;
2009-05-22 01:22:52 +00:00
2011-12-18 08:13:20 +00:00
if ( env . DTHE . DTHE )
{
gd . sel . dthe = 1 ;
gd . dimx = ( GSVector4i * ) _aligned_malloc ( sizeof ( env . dimx ) , 32 ) ;
memcpy ( gd . dimx , env . dimx , sizeof ( env . dimx ) ) ;
}
}
2009-05-22 01:22:52 +00:00
2011-02-17 03:24:37 +00:00
gd . sel . zwrite = zwrite ;
gd . sel . ztest = ztest ;
2009-05-22 01:22:52 +00:00
if ( zwrite | | ztest )
{
2011-02-17 03:24:37 +00:00
gd . sel . zpsm = GSLocalMemory : : m_psm [ context - > ZBUF . PSM ] . fmt ;
gd . sel . ztst = ztest ? context - > TEST . ZTST : ZTST_ALWAYS ;
2012-01-19 04:53:36 +00:00
gd . sel . zoverflow = GSVector4i ( m_vt . m_max . p ) . z = = 0x80000000 ;
2011-02-17 03:24:37 +00:00
}
gd . fm = GSVector4i ( fm ) ;
gd . zm = GSVector4i ( zm ) ;
if ( gd . sel . fpsm = = 1 )
{
gd . fm | = GSVector4i : : xff000000 ( ) ;
}
else if ( gd . sel . fpsm = = 2 )
{
GSVector4i rb = gd . fm & 0x00f800f8 ;
GSVector4i ga = gd . fm & 0x8000f800 ;
gd . fm = ( ga > > 16 ) | ( rb > > 9 ) | ( ga > > 6 ) | ( rb > > 3 ) | GSVector4i : : xffff0000 ( ) ;
}
if ( gd . sel . zpsm = = 1 )
{
gd . zm | = GSVector4i : : xff000000 ( ) ;
}
else if ( gd . sel . zpsm = = 2 )
{
gd . zm | = GSVector4i : : xffff0000 ( ) ;
2009-05-22 01:22:52 +00:00
}
2011-03-19 19:29:30 +00:00
return true ;
2009-05-22 01:22:52 +00:00
}
2012-01-08 17:10:00 +00:00
GSRendererSW : : SharedData : : SharedData ( GSRendererSW * parent )
2011-12-28 14:10:20 +00:00
: m_parent ( parent )
, m_fb_pages ( NULL )
, m_zb_pages ( NULL )
, m_using_pages ( false )
{
2012-01-08 17:10:00 +00:00
m_tex_pages [ 0 ] = NULL ;
2011-12-28 14:10:20 +00:00
2012-01-08 17:10:00 +00:00
global . sel . key = 0 ;
2011-12-28 14:10:20 +00:00
2012-01-08 17:10:00 +00:00
global . clut = NULL ;
global . dimx = NULL ;
2011-12-28 14:10:20 +00:00
}
2012-01-08 17:10:00 +00:00
GSRendererSW : : SharedData : : ~ SharedData ( )
2011-12-28 14:10:20 +00:00
{
if ( m_using_pages )
{
2012-01-08 17:10:00 +00:00
if ( global . sel . fwrite )
2011-12-28 14:10:20 +00:00
{
m_parent - > ReleasePages ( m_fb_pages , 0 ) ;
}
2012-01-08 17:10:00 +00:00
if ( global . sel . zwrite )
2011-12-28 14:10:20 +00:00
{
m_parent - > ReleasePages ( m_zb_pages , 1 ) ;
}
}
2012-01-18 11:47:31 +00:00
delete [ ] m_fb_pages ;
delete [ ] m_zb_pages ;
2012-01-13 18:10:05 +00:00
2011-12-28 14:10:20 +00:00
for ( size_t i = 0 ; i < countof ( m_tex_pages ) & & m_tex_pages [ i ] ! = NULL ; i + + )
{
m_parent - > ReleasePages ( m_tex_pages [ i ] , 2 ) ;
}
2012-01-13 18:10:05 +00:00
2012-01-08 17:10:00 +00:00
if ( global . clut ) _aligned_free ( global . clut ) ;
if ( global . dimx ) _aligned_free ( global . dimx ) ;
2011-12-28 14:10:20 +00:00
}
2012-01-08 17:10:00 +00:00
void GSRendererSW : : SharedData : : UseTargetPages ( const uint32 * fb_pages , const uint32 * zb_pages )
2011-12-28 14:10:20 +00:00
{
if ( m_using_pages ) return ;
m_fb_pages = fb_pages ;
m_zb_pages = zb_pages ;
2012-01-08 17:10:00 +00:00
if ( global . sel . fwrite )
2011-12-28 14:10:20 +00:00
{
m_parent - > UsePages ( fb_pages , 0 ) ;
}
2012-01-08 17:10:00 +00:00
if ( global . sel . zwrite )
2011-12-28 14:10:20 +00:00
{
m_parent - > UsePages ( zb_pages , 1 ) ;
}
m_using_pages = true ;
}
2012-01-08 17:10:00 +00:00
void GSRendererSW : : SharedData : : UseSourcePages ( GSTextureCacheSW : : Texture * t , int level )
2011-12-28 14:10:20 +00:00
{
ASSERT ( m_tex_pages [ level ] = = NULL ) ;
2012-01-18 11:47:31 +00:00
const uint32 * pages = t - > m_pages . n ;
m_tex_pages [ level ] = pages ;
2012-01-08 17:10:00 +00:00
m_tex_pages [ level + 1 ] = NULL ;
2011-12-28 14:10:20 +00:00
2012-01-18 11:47:31 +00:00
m_parent - > UsePages ( pages , 2 ) ;
2011-12-28 14:10:20 +00:00
}