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"
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 )
2009-05-22 01:22:52 +00:00
{
2011-02-18 01:56:05 +00:00
InitVertexKick ( GSRendererSW ) ;
2009-05-22 01:22:52 +00:00
m_tc = new GSTextureCacheSW ( this ) ;
memset ( m_texture , 0 , sizeof ( m_texture ) ) ;
2011-02-17 18:22:47 +00:00
m_rl . Create < GSDrawScanline > ( threads ) ;
2011-02-19 03:36:30 +00:00
m_output = ( uint8 * ) _aligned_malloc ( 1024 * 1024 * sizeof ( uint32 ) , 32 ) ;
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
_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
{
// TODO: GSreset can come from the main thread too => crash
// m_tc->RemoveAll();
m_reset = true ;
2011-02-19 03:36:30 +00:00
GSRendererT < GSVertexSW > : : Reset ( ) ;
2009-05-22 01:22:52 +00:00
}
void GSRendererSW : : VSync ( int field )
{
2011-02-19 03:36:30 +00:00
GSRendererT < GSVertexSW > : : VSync ( field ) ;
2009-05-22 01:22:52 +00:00
m_tc - > IncAge ( ) ;
if ( m_reset )
{
m_tc - > RemoveAll ( ) ;
m_reset = false ;
}
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 )
{
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 ] ;
}
void GSRendererSW : : Draw ( )
{
2010-04-25 00:31:27 +00:00
if ( m_dump )
2009-05-22 01:22:52 +00:00
{
2009-07-22 03:55:28 +00:00
m_dump . Object ( m_vertices , m_count , m_vt . m_primclass ) ;
2009-05-22 01:22:52 +00:00
}
2011-02-17 03:24:37 +00:00
GSScanlineGlobalData gd ;
2009-05-22 01:22:52 +00:00
2011-03-19 19:29:30 +00:00
if ( ! GetScanlineGlobalData ( gd ) )
{
return ;
}
2009-05-22 01:22:52 +00:00
2011-02-17 03:24:37 +00:00
if ( ! gd . sel . fwrite & & ! gd . sel . zwrite )
2009-05-22 01:22:52 +00:00
{
return ;
}
2011-03-12 22:10:58 +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)
2009-05-22 01:22:52 +00:00
{
uint64 frame = m_perfmon . GetFrame ( ) ;
string s ;
2010-04-25 00:31:27 +00:00
if ( s_save & & s_n > = s_saven & & PRIM - > TME )
2009-05-22 01:22:52 +00:00
{
2011-02-28 11:08:52 +00:00
s = format ( " c: \\ temp1 \\ _%05d_f%lld_tex_%05x_%d.bmp " , s_n , frame , ( int ) m_context - > TEX0 . TBP0 , ( int ) m_context - > TEX0 . PSM ) ;
2009-05-22 01:22:52 +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 ) ;
}
s_n + + ;
2009-07-05 12:58:59 +00:00
if ( s_save & & s_n > = s_saven )
2009-05-22 01:22:52 +00:00
{
2011-02-19 03:36:30 +00:00
s = format ( " c: \\ temp1 \\ _%05d_f%lld_rt0_%05x_%d.bmp " , s_n , frame , m_context - > FRAME . Block ( ) , m_context - > FRAME . PSM ) ;
2009-05-22 01:22:52 +00:00
m_mem . SaveBMP ( s , m_context - > FRAME . Block ( ) , m_context - > FRAME . FBW , m_context - > FRAME . PSM , GetFrameRect ( ) . width ( ) , 512 ) ; //GetFrameSize(1).cy);
}
2009-07-05 12:58:59 +00:00
if ( s_savez & & s_n > = s_saven )
2009-05-22 01:22:52 +00:00
{
2011-02-19 03:36:30 +00:00
s = format ( " c: \\ temp1 \\ _%05d_f%lld_rz0_%05x_%d.bmp " , s_n , frame , m_context - > ZBUF . Block ( ) , m_context - > ZBUF . PSM ) ;
2009-05-22 01:22:52 +00:00
m_mem . SaveBMP ( s , m_context - > ZBUF . Block ( ) , m_context - > FRAME . FBW , m_context - > ZBUF . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
}
s_n + + ;
}
2011-03-27 03:12:12 +00:00
GSVector4i scissor ( m_context - > scissor . in ) ;
GSVector4i bbox = GSVector4i ( m_vt . m_min . p . xyxy ( m_vt . m_max . p ) ) ;
GSVector4i r = bbox . rintersect ( scissor ) ;
2009-05-22 01:22:52 +00:00
GSRasterizerData data ;
2011-03-27 03:12:12 +00:00
data . scissor = scissor ;
data . scissor . z = std : : min < int > ( data . scissor . z , ( int ) m_context - > FRAME . FBW * 64 ) ; // TODO: find a game that overflows and check which one is the right behaviour
data . scissor_test = ! bbox . eq ( r ) ;
2009-07-22 03:55:28 +00:00
data . primclass = m_vt . m_primclass ;
2009-05-22 01:22:52 +00:00
data . vertices = m_vertices ;
data . count = m_count ;
2011-02-17 03:24:37 +00:00
data . frame = m_perfmon . GetFrame ( ) ;
data . param = & gd ;
2009-05-22 01:22:52 +00:00
2011-02-17 18:22:47 +00:00
m_rl . Draw ( & data , r . width ( ) , r . height ( ) ) ;
2011-02-17 03:24:37 +00:00
if ( gd . sel . fwrite )
2009-05-22 01:22:52 +00:00
{
2009-07-22 03:55:28 +00:00
m_tc - > InvalidateVideoMem ( m_context - > offset . fb , r ) ;
2009-05-22 01:22:52 +00:00
}
2011-02-17 03:24:37 +00:00
if ( gd . sel . zwrite )
2009-05-22 01:22:52 +00:00
{
2009-07-22 03:55:28 +00:00
m_tc - > InvalidateVideoMem ( m_context - > offset . zb , r ) ;
2009-05-22 01:22:52 +00:00
}
2011-02-18 01:56:05 +00:00
// By only syncing here we can do the two InvalidateVideoMem calls free if the other threads finish
2011-02-16 03:19:36 +00:00
// their drawings later than this one (they usually do because they start on an event).
2011-02-18 01:56:05 +00:00
m_rl . Sync ( ) ;
2011-02-16 03:19:36 +00:00
GSRasterizerStats stats ;
m_rl . GetStats ( stats ) ;
m_perfmon . Put ( GSPerfMon : : Prim , stats . prims ) ;
m_perfmon . Put ( GSPerfMon : : Fillrate , stats . pixels ) ;
2011-03-12 22:10:58 +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)
2009-05-22 01:22:52 +00:00
{
uint64 frame = m_perfmon . GetFrame ( ) ;
string s ;
2009-07-05 12:58:59 +00:00
if ( s_save & & s_n > = s_saven )
2009-05-22 01:22:52 +00:00
{
2011-02-19 03:36:30 +00:00
s = format ( " c: \\ temp1 \\ _%05d_f%lld_rt1_%05x_%d.bmp " , s_n , frame , m_context - > FRAME . Block ( ) , m_context - > FRAME . PSM ) ;
2009-05-22 01:22:52 +00:00
m_mem . SaveBMP ( s , m_context - > FRAME . Block ( ) , m_context - > FRAME . FBW , m_context - > FRAME . PSM , GetFrameRect ( ) . width ( ) , 512 ) ; //GetFrameSize(1).cy);
}
2009-07-05 12:58:59 +00:00
if ( s_savez & & s_n > = s_saven )
2009-05-22 01:22:52 +00:00
{
2011-02-19 03:36:30 +00:00
s = format ( " c: \\ temp1 \\ _%05d_f%lld_rz1_%05x_%d.bmp " , s_n , frame , m_context - > ZBUF . Block ( ) , m_context - > ZBUF . PSM ) ;
2009-05-22 01:22:52 +00:00
m_mem . SaveBMP ( s , m_context - > ZBUF . Block ( ) , m_context - > FRAME . FBW , m_context - > ZBUF . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
}
s_n + + ;
}
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-02-17 03:24:37 +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 ) ;
}
}
void GSRendererSW : : InvalidateVideoMem ( const GIFRegBITBLTBUF & BITBLTBUF , const GSVector4i & r )
{
2009-07-22 03:55:28 +00:00
m_tc - > InvalidateVideoMem ( m_mem . GetOffset ( BITBLTBUF . DBP , BITBLTBUF . DBW , BITBLTBUF . DPSM ) , r ) ;
2009-05-22 01:22:52 +00:00
}
2011-03-17 02:55:20 +00:00
# include "GSTextureSW.h"
2011-03-19 19:29:30 +00:00
bool GSRendererSW : : GetScanlineGlobalData ( GSScanlineGlobalData & gd )
2009-05-22 01:22:52 +00:00
{
const GSDrawingEnvironment & env = m_env ;
const GSDrawingContext * context = m_context ;
2011-02-17 03:24:37 +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 ;
gd . dimx = env . dimx ;
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 ] ;
gd . fzbr = context - > offset . fzb - > row ;
gd . fzbc = context - > offset . fzb - > 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 ;
gd . sel . sprite = primclass = = GS_SPRITE_CLASS ? 1 : 0 ;
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-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
2009-06-23 04:12:32 +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-03-17 02:55:20 +00:00
gd . clut = m_mem . m_clut ;
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 ;
2011-03-12 22:10:58 +00:00
gd . sel . ltf = m_vt . IsLinear ( ) ;
2011-02-17 03:24:37 +00:00
gd . sel . tlu = GSLocalMemory : : m_psm [ context - > TEX0 . PSM ] . pal > 0 ;
gd . sel . wms = context - > CLAMP . WMS ;
gd . sel . wmt = context - > CLAMP . WMT ;
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-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-03-17 02:55:20 +00:00
const GSTextureCacheSW : : Texture * t = m_tc - > Lookup ( context - > TEX0 , env . TEXA , r ) ;
2009-05-22 01:22:52 +00:00
2011-03-19 19:29:30 +00:00
if ( t = = NULL ) { ASSERT ( 0 ) ; return false ; }
2009-05-22 01:22:52 +00:00
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
2011-03-17 02:55:20 +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
if ( m_vt . m_lod . x > 0 )
{
2011-03-19 03:54:22 +00:00
gd . sel . ltf = context - > TEX1 . MMIN > > 2 ;
2011-03-19 00:54:03 +00:00
}
else
{
// TODO: isbilinear(mmag) != isbilinear(mmin) && m_vt.m_lod.x <= 0 && m_vt.m_lod.y > 0
}
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 ;
2011-03-28 04:15:36 +00:00
if ( ( int ) m_vt . m_lod . x > = ( int ) context - > TEX1 . MXL )
{
2011-04-04 11:05:54 +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 ) ;
ASSERT ( ( ( m_vt . m_min . t . uph ( m_vt . m_max . t ) = = GSVector4 : : zero ( ) ) . mask ( ) & 3 ) = = 3 ) ; // ratchet and clank (menu)
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
2011-03-17 02:55:20 +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
{
case 1 :
MIP_TEX0 . TBP0 = context - > MIPTBP1 . TBP1 ;
MIP_TEX0 . TBW = context - > MIPTBP1 . TBW1 ;
break ;
case 2 :
MIP_TEX0 . TBP0 = context - > MIPTBP1 . TBP2 ;
MIP_TEX0 . TBW = context - > MIPTBP1 . TBW2 ;
break ;
case 3 :
MIP_TEX0 . TBP0 = context - > MIPTBP1 . TBP3 ;
MIP_TEX0 . TBW = context - > MIPTBP1 . TBW3 ;
break ;
case 4 :
MIP_TEX0 . TBP0 = context - > MIPTBP2 . TBP4 ;
MIP_TEX0 . TBW = context - > MIPTBP2 . TBW4 ;
break ;
case 5 :
MIP_TEX0 . TBP0 = context - > MIPTBP2 . TBP5 ;
MIP_TEX0 . TBW = context - > MIPTBP2 . TBW5 ;
break ;
case 6 :
MIP_TEX0 . TBP0 = context - > MIPTBP2 . TBP6 ;
MIP_TEX0 . TBW = context - > MIPTBP2 . TBW6 ;
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
2011-03-17 02:55:20 +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-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-03-17 02:55:20 +00:00
const GSTextureCacheSW : : Texture * t = m_tc - > Lookup ( MIP_TEX0 , env . TEXA , r , gd . sel . tw + 3 ) ;
2011-03-12 22:10:58 +00:00
2011-03-19 19:29:30 +00:00
if ( t = = NULL ) { 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
m_vt . m_min . t = tmin ;
m_vt . m_max . t = tmax ;
}
else
{
if ( gd . sel . fst = = 0 )
{
// skip per pixel division if q is constant
GSVertexSW * v = m_vertices ;
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
2011-03-17 02:55:20 +00:00
if ( v [ 0 ] . t . z ! = 1.0f )
{
GSVector4 w = v [ 0 ] . t . zzzz ( ) . rcpnr ( ) ;
for ( int i = 0 , j = m_count ; i < j ; i + + )
{
v [ i ] . t * = w ;
}
}
}
else if ( primclass = = GS_SPRITE_CLASS )
{
gd . sel . fst = 1 ;
for ( int i = 0 , j = m_count ; i < j ; i + = 2 )
2011-03-12 22:10:58 +00:00
{
2011-03-17 02:55:20 +00:00
GSVector4 w = v [ i + 1 ] . t . zzzz ( ) . rcpnr ( ) ;
v [ i + 0 ] . t * = w ;
v [ i + 1 ] . t * = w ;
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 ) ;
2009-05-22 01:22:52 +00:00
GSVertexSW * v = m_vertices ;
for ( int i = 0 , j = m_count ; i < j ; i + + )
{
v [ i ] . t - = half ;
}
}
}
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 ;
gd . sel . dthe = env . DTHE . DTHE ;
2009-05-22 01:22:52 +00:00
}
2011-02-17 03:24:37 +00:00
bool zwrite = zm ! = 0xffffffff ;
2009-07-16 21:36:07 +00:00
bool ztest = context - > TEST . ZTE & & context - > TEST . ZTST > ZTST_ALWAYS ;
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 ;
gd . sel . zoverflow = GSVector4i ( m_vt . m_max . p ) . z = = 0x80000000 ;
}
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
}
2011-02-18 01:56:05 +00:00
template < uint32 prim , uint32 tme , uint32 fst >
2011-02-07 01:59:05 +00:00
void GSRendererSW : : VertexKick ( bool skip )
2009-05-26 03:40:31 +00:00
{
2011-02-07 01:59:05 +00:00
const GSDrawingContext * context = m_context ;
2009-05-26 03:40:31 +00:00
2011-04-04 11:05:54 +00:00
GSVertexSW & dst = m_vl . AddTail ( ) ;
2009-05-26 03:40:31 +00:00
2011-04-04 11:05:54 +00:00
GSVector4i xy = GSVector4i : : load ( ( int ) m_v . XYZ . u32 [ 0 ] ) . upl16 ( ) - context - > XYOFFSET ;
GSVector4i zf = GSVector4i ( ( int ) std : : min < uint32 > ( m_v . XYZ . Z , 0xffffff00 ) , m_v . FOG . F ) ;
2009-05-26 03:40:31 +00:00
2011-04-04 11:05:54 +00:00
dst . p = GSVector4 ( xy ) . xyxy ( GSVector4 ( zf ) + ( GSVector4 : : m_x4f800000 & GSVector4 : : cast ( zf . sra32 ( 31 ) ) ) ) * g_pos_scale ;
2009-05-26 03:40:31 +00:00
if ( tme )
{
2011-04-04 11:05:54 +00:00
GSVector4 t ;
2009-05-26 03:40:31 +00:00
if ( fst )
{
2011-04-04 11:05:54 +00:00
t = GSVector4 ( ( ( GSVector4i ) m_v . UV ) . upl16 ( ) < < ( 16 - 4 ) ) ;
2009-05-26 03:40:31 +00:00
}
else
{
2011-04-04 11:05:54 +00:00
t = GSVector4 ( m_v . ST . S , m_v . ST . T ) * GSVector4 ( 0x10000 < < context - > TEX0 . TW , 0x10000 < < context - > TEX0 . TH ) ;
t = t . xyxy ( GSVector4 : : load ( m_v . RGBAQ . Q ) ) ;
2009-05-26 03:40:31 +00:00
}
2011-04-04 11:05:54 +00:00
dst . t = t ;
2009-05-26 03:40:31 +00:00
}
2011-04-04 11:05:54 +00:00
dst . c = GSVector4 : : rgba32 ( m_v . RGBAQ . u32 [ 0 ] , 7 ) ;
2010-04-25 00:31:27 +00:00
2011-02-07 01:59:05 +00:00
int count = 0 ;
2011-02-18 01:56:05 +00:00
2011-02-07 01:59:05 +00:00
if ( GSVertexSW * v = DrawingKick < prim > ( skip , count ) )
2009-05-26 03:40:31 +00:00
{
2011-02-07 01:59:05 +00:00
if ( ! m_dump )
{
2009-05-26 03:40:31 +00:00
GSVector4 pmin , pmax ;
switch ( prim )
{
case GS_POINTLIST :
pmin = v [ 0 ] . p ;
pmax = v [ 0 ] . p ;
break ;
case GS_LINELIST :
case GS_LINESTRIP :
case GS_SPRITE :
2009-07-04 15:14:04 +00:00
pmin = v [ 0 ] . p . min ( v [ 1 ] . p ) ;
pmax = v [ 0 ] . p . max ( v [ 1 ] . p ) ;
2009-05-26 03:40:31 +00:00
break ;
case GS_TRIANGLELIST :
case GS_TRIANGLESTRIP :
case GS_TRIANGLEFAN :
2009-07-04 15:14:04 +00:00
pmin = v [ 0 ] . p . min ( v [ 1 ] . p ) . min ( v [ 2 ] . p ) ;
pmax = v [ 0 ] . p . max ( v [ 1 ] . p ) . max ( v [ 2 ] . p ) ;
2009-05-26 03:40:31 +00:00
break ;
}
2011-02-07 01:59:05 +00:00
GSVector4 scissor = context - > scissor . ex ;
2009-05-26 03:40:31 +00:00
GSVector4 test = ( pmax < scissor ) | ( pmin > scissor . zwxy ( ) ) ;
switch ( prim )
{
case GS_TRIANGLELIST :
case GS_TRIANGLESTRIP :
case GS_TRIANGLEFAN :
case GS_SPRITE :
test | = pmin . ceil ( ) = = pmax . ceil ( ) ;
break ;
}
switch ( prim )
{
case GS_TRIANGLELIST :
case GS_TRIANGLESTRIP :
case GS_TRIANGLEFAN :
// are in line or just two of them are the same (cross product == 0)
GSVector4 tmp = ( v [ 1 ] . p - v [ 0 ] . p ) * ( v [ 2 ] . p - v [ 0 ] . p ) . yxwz ( ) ;
test | = tmp = = tmp . yxwz ( ) ;
break ;
}
2011-02-18 01:56:05 +00:00
2009-05-26 03:40:31 +00:00
if ( test . mask ( ) & 3 )
{
return ;
}
2011-02-07 01:59:05 +00:00
}
2009-05-26 03:40:31 +00:00
switch ( prim )
{
2011-02-07 01:59:05 +00:00
case GS_POINTLIST :
break ;
case GS_LINELIST :
case GS_LINESTRIP :
if ( PRIM - > IIP = = 0 ) { v [ 0 ] . c = v [ 1 ] . c ; }
break ;
case GS_TRIANGLELIST :
2009-05-26 03:40:31 +00:00
case GS_TRIANGLESTRIP :
case GS_TRIANGLEFAN :
2011-02-07 01:59:05 +00:00
if ( PRIM - > IIP = = 0 ) { v [ 0 ] . c = v [ 2 ] . c ; v [ 1 ] . c = v [ 2 ] . c ; }
break ;
case GS_SPRITE :
2009-05-26 03:40:31 +00:00
break ;
}
2011-02-07 01:59:05 +00:00
if ( m_count < 30 & & m_count > = 3 )
2009-05-26 03:40:31 +00:00
{
2011-02-07 01:59:05 +00:00
GSVertexSW * v = & m_vertices [ m_count - 3 ] ;
2009-05-26 03:40:31 +00:00
2011-02-07 01:59:05 +00:00
int tl = 0 ;
int br = 0 ;
2009-05-26 03:40:31 +00:00
2011-02-07 01:59:05 +00:00
bool isquad = false ;
switch ( prim )
{
case GS_TRIANGLESTRIP :
case GS_TRIANGLEFAN :
case GS_TRIANGLELIST :
isquad = GSVertexSW : : IsQuad ( v , tl , br ) ;
break ;
2010-08-17 04:38:49 +00:00
}
2009-05-26 03:40:31 +00:00
2011-02-07 01:59:05 +00:00
if ( isquad )
{
m_count - = 3 ;
2009-05-26 03:40:31 +00:00
2011-02-07 01:59:05 +00:00
if ( m_count > 0 )
{
tl + = m_count ;
br + = m_count ;
2009-05-26 03:40:31 +00:00
2011-02-07 01:59:05 +00:00
Flush ( ) ;
}
2009-05-26 03:40:31 +00:00
2011-02-07 01:59:05 +00:00
if ( tl ! = 0 ) m_vertices [ 0 ] = m_vertices [ tl ] ;
if ( br ! = 1 ) m_vertices [ 1 ] = m_vertices [ br ] ;
2009-05-26 03:40:31 +00:00
2011-02-07 01:59:05 +00:00
m_count = 2 ;
2009-05-26 03:40:31 +00:00
2011-02-07 01:59:05 +00:00
uint32 tmp = PRIM - > PRIM ;
PRIM - > PRIM = GS_SPRITE ;
2009-05-26 03:40:31 +00:00
2011-02-07 01:59:05 +00:00
Flush ( ) ;
PRIM - > PRIM = tmp ;
m_perfmon . Put ( GSPerfMon : : Quad , 1 ) ;
return ;
}
2009-05-26 03:40:31 +00:00
}
2010-08-17 04:38:49 +00:00
2011-02-07 01:59:05 +00:00
m_count + = count ;
2011-03-19 19:29:30 +00:00
// Flush();
2011-02-07 01:59:05 +00:00
}
2009-05-26 03:40:31 +00:00
}