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
2012-09-09 18:16:11 +00:00
* the Free Software Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA 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 ;
2016-07-06 23:21:31 +00:00
GSVector4 GSRendererSW : : m_pos_scale ;
# if _M_SSE >= 0x501
GSVector8 GSRendererSW : : m_pos_scale2 ;
# endif
void GSRendererSW : : InitVectors ( )
{
m_pos_scale = GSVector4 ( 1.0f / 16 , 1.0f / 16 , 1.0f , 128.0f ) ;
2009-05-22 01:22:52 +00:00
2013-06-17 04:11:10 +00:00
# if _M_SSE >= 0x501
2016-07-06 23:21:31 +00:00
m_pos_scale2 = GSVector8 ( 1.0f / 16 , 1.0f / 16 , 1.0f , 128.0f , 1.0f / 16 , 1.0f / 16 , 1.0f , 128.0f ) ;
2013-06-17 04:11:10 +00:00
# endif
2016-07-06 23:21:31 +00:00
}
2013-06-17 04:11:10 +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 ) ) ;
2015-11-20 13:56:29 +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
2015-02-28 09:59:48 +00:00
for ( uint32 i = 0 ; i < countof ( m_fzb_pages ) ; i + + ) {
m_fzb_pages [ i ] = 0 ;
}
for ( uint32 i = 0 ; i < countof ( m_tex_pages ) ; i + + ) {
m_tex_pages [ i ] = 0 ;
}
2012-01-21 04:44:04 +00:00
2017-03-03 16:01:13 +00:00
# define InitCVB2(P, Q) \
m_cvb [ P ] [ 0 ] [ 0 ] [ Q ] = & GSRendererSW : : ConvertVertexBuffer < P , 0 , 0 , Q > ; \
m_cvb [ P ] [ 0 ] [ 1 ] [ Q ] = & GSRendererSW : : ConvertVertexBuffer < P , 0 , 1 , Q > ; \
m_cvb [ P ] [ 1 ] [ 0 ] [ Q ] = & GSRendererSW : : ConvertVertexBuffer < P , 1 , 0 , Q > ; \
m_cvb [ P ] [ 1 ] [ 1 ] [ Q ] = & GSRendererSW : : ConvertVertexBuffer < P , 1 , 1 , Q > ;
2012-01-21 04:44:04 +00:00
# define InitCVB(P) \
2017-03-03 16:01:13 +00:00
InitCVB2 ( P , 0 ) \
InitCVB2 ( P , 1 )
2012-01-21 04:44:04 +00:00
InitCVB ( GS_POINT_CLASS ) ;
InitCVB ( GS_LINE_CLASS ) ;
InitCVB ( GS_TRIANGLE_CLASS ) ;
InitCVB ( GS_SPRITE_CLASS ) ;
2016-07-14 17:41:21 +00:00
m_dump_root = root_sw ;
2016-09-15 15:24:40 +00:00
2019-04-30 23:28:28 +00:00
// Reset handler with the auto flush hack enabled on the SW renderer.
// Some games run better without the hack so rely on ini/gui option.
if ( ! GLLoader : : in_replayer & & theApp . GetConfigB ( " autoflush_sw " ) ) {
2016-09-17 10:05:05 +00:00
m_userhacks_auto_flush = true ;
ResetHandlers ( ) ;
}
2009-05-22 01:22:52 +00:00
}
GSRendererSW : : ~ GSRendererSW ( )
{
delete m_tc ;
2009-07-04 22:54:57 +00:00
2013-06-29 12:02:03 +00:00
for ( size_t i = 0 ; i < countof ( m_texture ) ; i + + )
2009-07-04 22:54:57 +00:00
{
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-21 04:44:04 +00:00
if ( 0 ) if ( LOG )
2012-01-18 11:47:31 +00:00
{
2016-08-13 10:40:30 +00:00
fprintf ( s_fp , " %llu \n " , m_perfmon . GetFrame ( ) ) ;
2012-01-18 11:47:31 +00:00
2015-08-04 01:34:46 +00:00
GSVector4i dr = GetDisplayRect ( ) ;
2012-01-18 11:47:31 +00:00
GSVector4i fr = GetFrameRect ( ) ;
2016-08-07 07:13:03 +00:00
fprintf ( s_fp , " dr %d %d %d %d, fr %d %d %d %d \n " ,
2015-08-04 01:34:46 +00:00
dr . x , dr . y , dr . z , dr . w ,
2016-08-07 07:13:03 +00:00
fr . x , fr . y , fr . z , fr . w ) ;
2012-01-18 11:47:31 +00:00
2016-10-08 14:53:44 +00:00
m_regs - > Dump ( s_fp ) ;
2012-01-18 11:47:31 +00:00
fflush ( s_fp ) ;
}
2011-12-22 01:48:16 +00:00
/*
2011-12-28 14:10:20 +00:00
int draw [ 8 ] , sum = 0 ;
2013-06-29 12:02:03 +00:00
for ( size_t i = 0 ; i < countof ( draw ) ; i + + )
2011-12-28 14:10:20 +00:00
{
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 ( ) ;
2013-06-17 04:11:10 +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
{
2013-06-29 12:02:03 +00:00
for ( size_t i = 0 ; i < countof ( m_texture ) ; i + + )
2009-05-22 01:22:52 +00:00
{
delete m_texture [ i ] ;
m_texture [ i ] = NULL ;
}
}
2016-03-19 11:37:25 +00:00
GSTexture * GSRendererSW : : GetOutput ( int i , int & y_offset )
2009-05-22 01:22:52 +00:00
{
2011-12-22 14:36:54 +00:00
Sync ( 1 ) ;
2011-12-18 08:13:20 +00:00
2016-10-06 18:02:22 +00:00
const GSRegDISPFB & DISPFB = m_regs - > DISP [ i ] . DISPFB ;
2016-10-04 20:09:22 +00:00
2009-07-22 03:55:28 +00:00
int w = DISPFB . FBW * 64 ;
2016-12-12 08:00:25 +00:00
int h = GetFramebufferHeight ( ) ;
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
{
2015-05-31 15:38:52 +00:00
if ( s_savef & & s_n > = s_saven )
2009-07-04 15:14:04 +00:00
{
2016-09-05 18:34:29 +00:00
m_texture [ i ] - > Save ( m_dump_root + format ( " %05d_f%lld_fr%d_%05x_%s.bmp " , s_n , m_perfmon . GetFrame ( ) , i , ( int ) DISPFB . Block ( ) , psm_str ( DISPFB . PSM ) ) ) ;
2009-07-04 15:14:04 +00:00
}
}
2009-05-22 01:22:52 +00:00
}
return m_texture [ i ] ;
}
2016-10-09 15:48:07 +00:00
GSTexture * GSRendererSW : : GetFeedbackOutput ( )
{
int dummy ;
// It is enough to emulate Xenosaga cutscene. (or any game that will do a basic loopback)
for ( int i = 0 ; i < 2 ; i + + ) {
if ( m_regs - > EXTBUF . EXBP = = m_regs - > DISP [ i ] . DISPFB . Block ( ) )
return GetOutput ( i , dummy ) ;
}
return nullptr ;
}
2017-03-03 16:01:13 +00:00
template < uint32 primclass , uint32 tme , uint32 fst , uint32 q_div >
2012-01-21 04:44:04 +00:00
void GSRendererSW : : ConvertVertexBuffer ( GSVertexSW * RESTRICT dst , const GSVertex * RESTRICT src , size_t count )
2009-05-22 01:22:52 +00:00
{
2017-03-03 16:01:13 +00:00
// FIXME q_div wasn't added to AVX2 code path.
2013-06-17 04:11:10 +00:00
#if 0 //_M_SSE >= 0x501
2012-01-22 08:37:44 +00:00
2013-06-17 04:11:10 +00:00
// TODO: something isn't right here, this makes other functions slower (split load/store? old sse code in 3rd party lib?)
2009-05-22 01:22:52 +00:00
2013-06-17 04:11:10 +00:00
GSVector8i o2 ( ( GSVector4i ) m_context - > XYOFFSET ) ;
GSVector8 tsize2 ( GSVector4 ( 0x10000 < < m_context - > TEX0 . TW , 0x10000 < < m_context - > TEX0 . TH , 1 , 0 ) ) ;
2012-01-22 08:37:44 +00:00
2013-06-17 04:11:10 +00:00
for ( int i = ( int ) m_vertex . next ; i > 0 ; i - = 2 , src + = 2 , dst + = 2 ) // ok to overflow, allocator makes sure there is one more dummy vertex
{
GSVector8i v0 = GSVector8i : : load < true > ( src [ 0 ] . m ) ;
GSVector8i v1 = GSVector8i : : load < true > ( src [ 1 ] . m ) ;
2012-01-22 08:37:44 +00:00
2013-06-17 04:11:10 +00:00
GSVector8 stcq = GSVector8 : : cast ( v0 . ac ( v1 ) ) ;
GSVector8i xyzuvf = v0 . bd ( v1 ) ;
//GSVector8 stcq = GSVector8::load(&src[0].m[0], &src[1].m[0]);
//GSVector8i xyzuvf = GSVector8i::load(&src[0].m[1], &src[1].m[1]);
GSVector8i xy = xyzuvf . upl16 ( ) - o2 ;
GSVector8i zf = xyzuvf . ywww ( ) . min_u32 ( GSVector8i : : xffffff00 ( ) ) ;
2016-07-06 23:21:31 +00:00
GSVector8 p = GSVector8 ( xy ) . xyxy ( GSVector8 ( zf ) + ( GSVector8 : : m_x4f800000 & GSVector8 : : cast ( zf . sra32 ( 31 ) ) ) ) * m_pos_scale2 ;
2013-06-17 04:11:10 +00:00
GSVector8 c = GSVector8 ( GSVector8i : : cast ( stcq ) . uph8 ( ) . upl16 ( ) < < 7 ) ;
GSVector8 t = GSVector8 : : zero ( ) ;
if ( tme )
{
if ( fst )
{
t = GSVector8 ( xyzuvf . uph16 ( ) < < ( 16 - 4 ) ) ;
}
else
{
t = stcq . xyww ( ) * tsize2 ;
}
}
if ( primclass = = GS_SPRITE_CLASS )
{
t = t . insert32 < 1 , 3 > ( GSVector8 : : cast ( xyzuvf ) ) ;
}
2013-07-01 21:28:58 +00:00
GSVector8 : : storel ( & dst [ 0 ] . p , p ) ;
if ( tme | | primclass = = GS_SPRITE_CLASS )
2013-06-17 04:11:10 +00:00
{
2013-07-01 21:28:58 +00:00
GSVector8 : : store < true > ( & dst [ 0 ] . t , t . ac ( c ) ) ;
2013-06-17 04:11:10 +00:00
}
2013-07-01 21:28:58 +00:00
else
2013-06-17 04:11:10 +00:00
{
2013-07-01 21:28:58 +00:00
GSVector8 : : storel ( & dst [ 0 ] . c , c ) ;
2013-06-17 04:11:10 +00:00
}
2013-07-01 21:28:58 +00:00
GSVector8 : : storeh ( & dst [ 1 ] . p , p ) ;
if ( tme | | primclass = = GS_SPRITE_CLASS )
2013-06-17 04:11:10 +00:00
{
2013-07-01 21:28:58 +00:00
GSVector8 : : store < true > ( & dst [ 1 ] . t , t . bd ( c ) ) ;
2013-06-17 04:11:10 +00:00
}
2013-07-01 21:28:58 +00:00
else
2013-06-17 04:11:10 +00:00
{
2013-07-01 21:28:58 +00:00
GSVector8 : : storeh ( & dst [ 1 ] . c , c ) ;
2013-06-17 04:11:10 +00:00
}
}
# else
2012-01-22 08:37:44 +00:00
2015-05-15 18:40:09 +00:00
GSVector4i off = ( GSVector4i ) m_context - > XYOFFSET ;
2013-06-17 04:11:10 +00:00
GSVector4 tsize = GSVector4 ( 0x10000 < < m_context - > TEX0 . TW , 0x10000 < < m_context - > TEX0 . TH , 1 , 0 ) ;
for ( int i = ( int ) m_vertex . next ; i > 0 ; i - - , src + + , dst + + )
2012-01-19 04:53:36 +00:00
{
2012-01-21 04:44:04 +00:00
GSVector4 stcq = GSVector4 : : load < true > ( & src - > m [ 0 ] ) ; // s t rgba q
2011-12-27 09:15:35 +00:00
2012-01-21 04:44:04 +00:00
# if _M_SSE >= 0x401
2012-01-06 00:17:52 +00:00
2012-01-21 04:44:04 +00:00
GSVector4i xyzuvf ( src - > m [ 1 ] ) ;
2011-12-27 09:15:35 +00:00
2015-05-15 18:40:09 +00:00
GSVector4i xy = xyzuvf . upl16 ( ) - off ;
2012-01-21 04:44:04 +00:00
GSVector4i zf = xyzuvf . ywww ( ) . min_u32 ( GSVector4i : : xffffff00 ( ) ) ;
2012-01-20 00:34:44 +00:00
2012-01-21 04:44:04 +00:00
# else
2009-05-22 01:22:52 +00:00
2012-01-21 04:44:04 +00:00
uint32 z = src - > XYZ . Z ;
2012-01-06 00:17:52 +00:00
2015-05-15 18:40:09 +00:00
GSVector4i xy = GSVector4i : : load ( ( int ) src - > XYZ . u32 [ 0 ] ) . upl16 ( ) - off ;
2012-01-21 04:44:04 +00:00
GSVector4i zf = GSVector4i ( ( int ) std : : min < uint32 > ( z , 0xffffff00 ) , src - > FOG ) ; // NOTE: larger values of z may roll over to 0 when converting back to uint32 later
2012-01-05 02:40:24 +00:00
2012-01-21 04:44:04 +00:00
# endif
2012-01-08 17:10:00 +00:00
2016-07-06 23:21:31 +00:00
dst - > p = GSVector4 ( xy ) . xyxy ( GSVector4 ( zf ) + ( GSVector4 : : m_x4f800000 & GSVector4 : : cast ( zf . sra32 ( 31 ) ) ) ) * m_pos_scale ;
2012-01-21 04:44:04 +00:00
dst - > c = GSVector4 ( GSVector4i : : cast ( stcq ) . zzzz ( ) . u8to32 ( ) < < 7 ) ;
2012-01-20 00:34:44 +00:00
2013-06-17 04:11:10 +00:00
GSVector4 t = GSVector4 : : zero ( ) ;
2012-01-21 04:44:04 +00:00
if ( tme )
{
if ( fst )
2012-01-19 04:53:36 +00:00
{
2012-01-21 04:44:04 +00:00
# if _M_SSE >= 0x401
2012-01-05 02:40:24 +00:00
2012-01-21 04:44:04 +00:00
t = GSVector4 ( xyzuvf . uph16 ( ) < < ( 16 - 4 ) ) ;
2017-03-03 16:01:13 +00:00
2012-01-21 04:44:04 +00:00
# else
2012-01-05 02:40:24 +00:00
2012-01-21 04:44:04 +00:00
t = GSVector4 ( GSVector4i : : load ( src - > UV ) . upl16 ( ) < < ( 16 - 4 ) ) ;
2012-01-05 02:40:24 +00:00
2012-01-21 04:44:04 +00:00
# endif
}
2017-03-03 16:01:13 +00:00
else if ( q_div )
{
// Division is required if number are huge (Pro Soccer Club)
if ( primclass = = GS_SPRITE_CLASS & & ( i & 1 ) = = 0 )
{
// q(n) isn't valid, you need to take q(n+1)
const GSVertex * next = src + 1 ;
GSVector4 stcq1 = GSVector4 : : load < true > ( & next - > m [ 0 ] ) ; // s t rgba q
t = ( stcq / stcq1 . wwww ( ) ) * tsize ;
}
else
{
t = ( stcq / stcq . wwww ( ) ) * tsize ;
}
}
2012-01-21 04:44:04 +00:00
else
2012-01-19 04:53:36 +00:00
{
2012-01-21 04:44:04 +00:00
t = stcq . xyww ( ) * tsize ;
2012-01-19 04:53:36 +00:00
}
}
2012-01-21 04:44:04 +00:00
if ( primclass = = GS_SPRITE_CLASS )
{
# if _M_SSE >= 0x401
2013-06-17 04:11:10 +00:00
t = t . insert32 < 1 , 3 > ( GSVector4 : : cast ( xyzuvf ) ) ;
2012-01-21 04:44:04 +00:00
# else
2013-06-17 04:11:10 +00:00
t = t . insert32 < 0 , 3 > ( GSVector4 : : cast ( GSVector4i : : load ( z ) ) ) ;
2012-01-21 04:44:04 +00:00
# endif
}
dst - > t = t ;
2013-06-17 04:11:10 +00:00
2013-06-20 05:07:52 +00:00
#if 0 //_M_SSE >= 0x501
2013-06-17 04:11:10 +00:00
dst - > _pad = GSVector4 : : zero ( ) ;
# endif
2012-01-19 04:53:36 +00:00
}
2013-06-17 04:11:10 +00:00
# endif
2012-01-21 04:44:04 +00:00
}
2012-01-05 02:40:24 +00:00
2012-01-21 04:44:04 +00:00
void GSRendererSW : : Draw ( )
{
2012-01-28 10:07:17 +00:00
const GSDrawingContext * context = m_context ;
2012-01-21 04:44:04 +00:00
SharedData * sd = new SharedData ( this ) ;
2012-01-05 02:40:24 +00:00
2017-05-26 16:37:20 +00:00
std : : shared_ptr < GSRasterizerData > data ( sd ) ;
2012-01-21 04:44:04 +00:00
sd - > primclass = m_vt . m_primclass ;
2013-07-01 21:28:58 +00:00
sd - > buff = ( uint8 * ) _aligned_malloc ( sizeof ( GSVertexSW ) * ( ( m_vertex . next + 1 ) & ~ 1 ) + sizeof ( uint32 ) * m_index . tail , 64 ) ;
2012-01-21 04:44:04 +00:00
sd - > vertex = ( GSVertexSW * ) sd - > buff ;
sd - > vertex_count = m_vertex . next ;
2013-06-17 04:11:10 +00:00
sd - > index = ( uint32 * ) ( sd - > buff + sizeof ( GSVertexSW ) * ( ( m_vertex . next + 1 ) & ~ 1 ) ) ;
2012-01-21 04:44:04 +00:00
sd - > index_count = m_index . tail ;
2017-03-03 16:01:13 +00:00
// skip per pixel division if q is constant.
// Optimize the division by 1 with a nop. It also means that GS_SPRITE_CLASS must be processed when !m_vt.m_eq.q.
// If you have both GS_SPRITE_CLASS && m_vt.m_eq.q, it will depends on the first part of the 'OR'
uint32 q_div = ! IsMipMapActive ( ) & & ( ( m_vt . m_eq . q & & m_vt . m_min . t . z ! = 1.0f ) | | ( ! m_vt . m_eq . q & & m_vt . m_primclass = = GS_SPRITE_CLASS ) ) ;
( this - > * m_cvb [ m_vt . m_primclass ] [ PRIM - > TME ] [ PRIM - > FST ] [ q_div ] ) ( sd - > vertex , m_vertex . buff , m_vertex . next ) ;
2012-01-21 04:44:04 +00:00
memcpy ( sd - > index , m_index . buff , sizeof ( uint32 ) * m_index . tail ) ;
2012-01-13 18:10:05 +00:00
2012-02-08 20:21:18 +00:00
GSVector4i scissor = GSVector4i ( context - > scissor . in ) ;
GSVector4i bbox = GSVector4i ( m_vt . m_min . p . floor ( ) . xyxy ( m_vt . m_max . p . ceil ( ) ) ) ;
2014-09-15 13:49:16 +00:00
// points and lines may have zero area bbox (single line: 0, 0 - 256, 0)
if ( m_vt . m_primclass = = GS_POINT_CLASS | | m_vt . m_primclass = = GS_LINE_CLASS )
{
if ( bbox . x = = bbox . z ) bbox . z + + ;
if ( bbox . y = = bbox . w ) bbox . w + + ;
}
2012-02-08 20:21:18 +00:00
GSVector4i r = bbox . rintersect ( scissor ) ;
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
sd - > scissor = scissor ;
sd - > bbox = bbox ;
sd - > frame = m_perfmon . GetFrame ( ) ;
2015-08-04 01:34:46 +00:00
if ( ! GetScanlineGlobalData ( sd ) )
{
2015-06-07 07:42:12 +00:00
return ;
}
2011-12-28 14:10:20 +00:00
2012-02-08 16:57:14 +00:00
if ( 0 ) if ( LOG )
{
int n = GSUtil : : GetVertexCount ( PRIM - > PRIM ) ;
2013-06-28 10:43:50 +00:00
for ( uint32 i = 0 , j = 0 ; i < m_index . tail ; i + = n , j + + )
2012-02-08 16:57:14 +00:00
{
for ( int k = 0 ; k < n ; k + + )
{
GSVertex * v = & m_vertex . buff [ m_index . buff [ i + k ] ] ;
GSVertex * vn = & m_vertex . buff [ m_index . buff [ i + n - 1 ] ] ;
fprintf ( s_fp , " %d:%d %f %f %f %f \n " ,
j , k ,
( float ) ( v - > XYZ . X - context - > XYOFFSET . OFX ) / 16 ,
( float ) ( v - > XYZ . Y - context - > XYOFFSET . OFY ) / 16 ,
PRIM - > FST ? ( float ) ( v - > U ) / 16 : v - > ST . S / ( PRIM - > PRIM = = GS_SPRITE ? vn - > RGBAQ . Q : v - > RGBAQ . Q ) ,
PRIM - > FST ? ( float ) ( v - > V ) / 16 : v - > ST . T / ( PRIM - > PRIM = = GS_SPRITE ? vn - > RGBAQ . Q : v - > RGBAQ . Q )
) ;
}
}
}
2012-01-28 10:07:17 +00:00
//
2014-04-14 18:25:02 +00:00
// GSScanlineGlobalData& gd = sd->global;
2012-01-28 10:07:17 +00:00
uint32 * fb_pages = NULL ;
uint32 * zb_pages = NULL ;
if ( sd - > global . sel . fb )
{
fb_pages = m_context - > offset . fb - > GetPages ( r ) ;
}
if ( sd - > global . sel . zb )
{
zb_pages = m_context - > offset . zb - > GetPages ( r ) ;
}
// check if there is an overlap between this and previous targets
if ( CheckTargetPages ( fb_pages , zb_pages , r ) )
{
sd - > m_syncpoint = SharedData : : SyncTarget ;
}
// check if the texture is not part of a target currently in use
if ( CheckSourcePages ( sd ) )
{
sd - > m_syncpoint = SharedData : : SyncSource ;
}
// addref source and target pages
sd - > UsePages ( fb_pages , m_context - > offset . fb - > psm , zb_pages , m_context - > offset . zb - > psm ) ;
//
2011-12-27 09:15:35 +00:00
2011-12-20 14:33:28 +00:00
if ( s_dump )
2011-12-18 21:57:48 +00:00
{
2012-02-14 08:03:27 +00:00
Sync ( 2 ) ;
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
uint64 frame = m_perfmon . GetFrame ( ) ;
2015-06-17 18:02:03 +00:00
// Dump the texture in 32 bits format. It helps to debug texture shuffle effect
// It will breaks the few games that really uses 16 bits RT
2015-06-13 06:40:32 +00:00
bool texture_shuffle = ( ( context - > FRAME . PSM & 0x2 ) & & ( ( context - > TEX0 . PSM & 3 ) = = 2 ) & & ( m_vt . m_primclass = = GS_SPRITE_CLASS ) ) ;
2011-12-18 21:57:48 +00:00
2017-05-26 15:26:46 +00:00
std : : string s ;
2011-12-18 21:57:48 +00:00
2015-08-04 01:34:46 +00:00
if ( s_n > = s_saven )
{
2015-05-23 10:23:05 +00:00
// Dump Register state
s = format ( " %05d_context.txt " , s_n ) ;
2016-07-14 17:41:21 +00:00
m_env . Dump ( m_dump_root + s ) ;
m_context - > Dump ( m_dump_root + s ) ;
2015-05-23 10:23:05 +00:00
}
2015-05-01 11:35:21 +00:00
if ( s_savet & & s_n > = s_saven & & PRIM - > TME )
2011-12-20 14:33:28 +00:00
{
2015-06-13 06:40:32 +00:00
if ( texture_shuffle ) {
2015-06-17 18:02:03 +00:00
// Dump the RT in 32 bits format. It helps to debug texture shuffle effect
2016-09-27 16:59:06 +00:00
s = format ( " %05d_f%lld_itexraw_%05x_32bits.bmp " , s_n , frame , ( int ) m_context - > TEX0 . TBP0 ) ;
2016-07-14 17:41:21 +00:00
m_mem . SaveBMP ( m_dump_root + s , m_context - > TEX0 . TBP0 , m_context - > TEX0 . TBW , 0 , 1 < < m_context - > TEX0 . TW , 1 < < m_context - > TEX0 . TH ) ;
2015-06-13 06:40:32 +00:00
}
2011-12-18 21:57:48 +00:00
2016-09-27 16:59:06 +00:00
s = format ( " %05d_f%lld_itexraw_%05x_%s.bmp " , s_n , frame , ( int ) m_context - > TEX0 . TBP0 , psm_str ( m_context - > TEX0 . PSM ) ) ;
2016-07-14 17:41:21 +00:00
m_mem . SaveBMP ( m_dump_root + 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-20 14:33:28 +00:00
}
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
2015-06-13 06:40:32 +00:00
if ( texture_shuffle ) {
// Dump the RT in 32 bits format. It helps to debug texture shuffle effect
s = format ( " %05d_f%lld_rt0_%05x_32bits.bmp " , s_n , frame , m_context - > FRAME . Block ( ) ) ;
2016-07-14 17:41:21 +00:00
m_mem . SaveBMP ( m_dump_root + s , m_context - > FRAME . Block ( ) , m_context - > FRAME . FBW , 0 , GetFrameRect ( ) . width ( ) , 512 ) ;
2015-06-13 06:40:32 +00:00
}
2015-09-08 09:27:36 +00:00
2016-09-05 18:34:29 +00:00
s = format ( " %05d_f%lld_rt0_%05x_%s.bmp " , s_n , frame , m_context - > FRAME . Block ( ) , psm_str ( m_context - > FRAME . PSM ) ) ;
2016-07-14 17:41:21 +00:00
m_mem . SaveBMP ( m_dump_root + s , m_context - > FRAME . Block ( ) , m_context - > FRAME . FBW , m_context - > FRAME . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
2011-12-20 14:33:28 +00:00
}
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
if ( s_savez & & s_n > = s_saven )
{
2016-09-05 18:34:29 +00:00
s = format ( " %05d_f%lld_rz0_%05x_%s.bmp " , s_n , frame , m_context - > ZBUF . Block ( ) , psm_str ( m_context - > ZBUF . PSM ) ) ;
2011-12-18 21:57:48 +00:00
2016-07-14 17:41:21 +00:00
m_mem . SaveBMP ( m_dump_root + s , m_context - > ZBUF . Block ( ) , m_context - > FRAME . FBW , m_context - > ZBUF . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
2011-12-18 21:57:48 +00:00
}
2012-01-28 10:07:17 +00:00
Queue ( data ) ;
2011-12-18 21:57:48 +00:00
2012-02-14 08:03:27 +00:00
Sync ( 3 ) ;
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
{
2015-06-13 06:40:32 +00:00
if ( texture_shuffle ) {
// Dump the RT in 32 bits format. It helps to debug texture shuffle effect
s = format ( " %05d_f%lld_rt1_%05x_32bits.bmp " , s_n , frame , m_context - > FRAME . Block ( ) ) ;
2016-07-14 17:41:21 +00:00
m_mem . SaveBMP ( m_dump_root + s , m_context - > FRAME . Block ( ) , m_context - > FRAME . FBW , 0 , GetFrameRect ( ) . width ( ) , 512 ) ;
2015-06-13 06:40:32 +00:00
}
2015-09-08 09:27:36 +00:00
2016-09-05 18:34:29 +00:00
s = format ( " %05d_f%lld_rt1_%05x_%s.bmp " , s_n , frame , m_context - > FRAME . Block ( ) , psm_str ( m_context - > FRAME . PSM ) ) ;
2016-07-14 17:41:21 +00:00
m_mem . SaveBMP ( m_dump_root + s , m_context - > FRAME . Block ( ) , m_context - > FRAME . FBW , m_context - > FRAME . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
2011-12-20 14:33:28 +00:00
}
2011-12-18 21:57:48 +00:00
2011-12-20 14:33:28 +00:00
if ( s_savez & & s_n > = s_saven )
{
2016-09-05 18:34:29 +00:00
s = format ( " %05d_f%lld_rz1_%05x_%s.bmp " , s_n , frame , m_context - > ZBUF . Block ( ) , psm_str ( m_context - > ZBUF . PSM ) ) ;
2011-12-18 21:57:48 +00:00
2016-07-14 17:41:21 +00:00
m_mem . SaveBMP ( m_dump_root + 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
2015-08-05 17:10:55 +00:00
if ( s_savel > 0 & & ( s_n - s_saven ) > s_savel )
2015-08-04 01:34:46 +00:00
{
2015-05-03 14:46:48 +00:00
s_dump = 0 ;
}
2011-12-18 21:57:48 +00:00
}
else
{
2012-01-28 10:07:17 +00:00
Queue ( data ) ;
2011-12-18 21:57:48 +00:00
}
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
*/
}
2017-05-26 16:37:20 +00:00
void GSRendererSW : : Queue ( std : : shared_ptr < GSRasterizerData > & item )
2012-01-28 10:07:17 +00:00
{
SharedData * sd = ( SharedData * ) item . get ( ) ;
if ( sd - > m_syncpoint = = SharedData : : SyncSource )
{
2012-02-14 08:03:27 +00:00
Sync ( 4 ) ;
2012-01-28 10:07:17 +00:00
}
// update previously invalidated parts
sd - > UpdateSource ( ) ;
2012-02-14 08:03:27 +00:00
if ( sd - > m_syncpoint = = SharedData : : SyncTarget )
{
Sync ( 5 ) ;
}
if ( LOG )
{
GSScanlineGlobalData & gd = ( ( SharedData * ) item . get ( ) ) - > global ;
2016-08-13 10:40:30 +00:00
fprintf ( s_fp , " [%d] queue %05x %d (%d) %05x %d (%d) %05x %d %dx%d (%d %d %d) | %u %d %d \n " ,
2012-02-14 08:03:27 +00:00
sd - > counter ,
m_context - > FRAME . Block ( ) , m_context - > FRAME . PSM , gd . sel . fwrite ,
m_context - > ZBUF . Block ( ) , m_context - > ZBUF . PSM , gd . sel . zwrite ,
PRIM - > TME ? m_context - > TEX0 . TBP0 : 0xfffff , m_context - > TEX0 . PSM , ( int ) m_context - > TEX0 . TW , ( int ) m_context - > TEX0 . TH , m_context - > TEX0 . CSM , m_context - > TEX0 . CPSM , m_context - > TEX0 . CSA ,
PRIM - > PRIM , sd - > vertex_count , sd - > index_count ) ;
fflush ( s_fp ) ;
}
m_rl - > Queue ( item ) ;
2012-01-28 10:07:17 +00:00
// invalidate new parts rendered onto
if ( sd - > global . sel . fwrite )
{
m_tc - > InvalidatePages ( sd - > m_fb_pages , sd - > m_fpsm ) ;
2016-09-02 22:11:56 +00:00
m_mem . m_clut . Invalidate ( m_context - > FRAME . Block ( ) ) ;
2012-01-28 10:07:17 +00:00
}
if ( sd - > global . sel . zwrite )
{
m_tc - > InvalidatePages ( sd - > m_zb_pages , sd - > m_zpsm ) ;
}
}
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-22 08:37:44 +00:00
if ( 0 ) if ( LOG )
2012-01-18 11:47:31 +00:00
{
2012-01-22 13:00:45 +00:00
std : : string s ;
if ( s_save )
{
2016-09-05 18:34:29 +00:00
s = format ( " %05d_f%lld_rt1_%05x_%s.bmp " , s_n , m_perfmon . GetFrame ( ) , m_context - > FRAME . Block ( ) , psm_str ( m_context - > FRAME . PSM ) ) ;
2012-01-18 11:47:31 +00:00
2016-07-14 17:41:21 +00:00
m_mem . SaveBMP ( m_dump_root + s , m_context - > FRAME . Block ( ) , m_context - > FRAME . FBW , m_context - > FRAME . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
2012-01-22 13:00:45 +00:00
}
2012-01-18 11:47:31 +00:00
2012-01-22 13:00:45 +00:00
if ( s_savez )
{
2016-09-05 18:34:29 +00:00
s = format ( " %05d_f%lld_zb1_%05x_%s.bmp " , s_n , m_perfmon . GetFrame ( ) , m_context - > ZBUF . Block ( ) , psm_str ( m_context - > ZBUF . PSM ) ) ;
2012-01-22 08:37:44 +00:00
2016-07-14 17:41:21 +00:00
m_mem . SaveBMP ( m_dump_root + s , m_context - > ZBUF . Block ( ) , m_context - > FRAME . FBW , m_context - > ZBUF . PSM , GetFrameRect ( ) . width ( ) , 512 ) ;
2012-01-22 13:00:45 +00:00
}
2012-01-18 11:47:31 +00:00
}
2012-01-13 18:10:05 +00:00
t = __rdtsc ( ) - t ;
2012-01-18 11:47:31 +00:00
int pixels = m_rl - > GetPixels ( ) ;
2016-08-13 10:40:30 +00:00
if ( LOG ) { fprintf ( s_fp , " sync n=%d r=%d t=%llu 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 )
{
2016-08-13 10:40:30 +00:00
if ( LOG ) { fprintf ( s_fp , " w %05x %u %u, %d %d %d %d \n " , BITBLTBUF . DBP , BITBLTBUF . DBW , BITBLTBUF . DPSM , r . x , r . y , r . z , r . w ) ; fflush ( s_fp ) ; }
2012-01-27 11:56:49 +00:00
2015-05-15 18:40:09 +00:00
GSOffset * off = m_mem . GetOffset ( BITBLTBUF . DBP , BITBLTBUF . DBW , BITBLTBUF . DPSM ) ;
2011-12-18 21:57:48 +00:00
2015-05-15 18:40:09 +00:00
off - > 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 ] )
{
2012-02-14 08:03:27 +00:00
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-13 18:10:05 +00:00
2015-05-15 18:40:09 +00:00
m_tc - > InvalidatePages ( m_tmp_pages , off - > 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
{
2016-08-13 10:40:30 +00:00
if ( LOG ) { fprintf ( s_fp , " %s %05x %u %u, %d %d %d %d \n " , clut ? " rp " : " r " , BITBLTBUF . SBP , BITBLTBUF . SBW , BITBLTBUF . SPSM , r . x , r . y , r . z , r . w ) ; fflush ( s_fp ) ; }
2012-01-27 11:56:49 +00:00
2012-01-18 11:47:31 +00:00
if ( ! m_rl - > IsSynced ( ) )
2011-12-18 21:57:48 +00:00
{
2015-05-15 18:40:09 +00:00
GSOffset * off = m_mem . GetOffset ( BITBLTBUF . SBP , BITBLTBUF . SBW , BITBLTBUF . SPSM ) ;
2012-01-18 11:47:31 +00:00
2015-05-15 18:40:09 +00:00
off - > 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 ] )
{
2012-01-21 12:34:36 +00:00
Sync ( 7 ) ;
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
}
}
}
2015-02-28 09:59:48 +00:00
void GSRendererSW : : UsePages ( const uint32 * pages , const int type )
2013-06-17 04:11:10 +00:00
{
2015-02-28 09:59:48 +00:00
for ( const uint32 * p = pages ; * p ! = GSOffset : : EOP ; p + + ) {
switch ( type ) {
case 0 :
ASSERT ( ( m_fzb_pages [ * p ] & 0xFFFF ) < USHRT_MAX ) ;
m_fzb_pages [ * p ] + = 1 ;
break ;
case 1 :
ASSERT ( ( m_fzb_pages [ * p ] > > 16 ) < USHRT_MAX ) ;
m_fzb_pages [ * p ] + = 0x10000 ;
break ;
case 2 :
ASSERT ( m_tex_pages [ * p ] < USHRT_MAX ) ;
m_tex_pages [ * p ] + = 1 ;
break ;
default : break ;
2011-12-28 14:10:20 +00:00
}
2011-12-23 15:53:53 +00:00
}
}
2011-12-18 21:57:48 +00:00
2015-02-28 09:59:48 +00:00
void GSRendererSW : : ReleasePages ( const uint32 * pages , const int type )
2011-12-23 15:53:53 +00:00
{
2015-02-28 09:59:48 +00:00
for ( const uint32 * p = pages ; * p ! = GSOffset : : EOP ; p + + ) {
switch ( type ) {
case 0 :
ASSERT ( ( m_fzb_pages [ * p ] & 0xFFFF ) > 0 ) ;
m_fzb_pages [ * p ] - = 1 ;
break ;
case 1 :
ASSERT ( ( m_fzb_pages [ * p ] > > 16 ) > 0 ) ;
m_fzb_pages [ * p ] - = 0x10000 ;
break ;
case 2 :
ASSERT ( m_tex_pages [ * p ] > 0 ) ;
m_tex_pages [ * p ] - = 1 ;
break ;
default : break ;
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 ( ) ;
2017-03-12 22:22:45 +00:00
2012-01-22 13:00:45 +00:00
bool fb = fb_pages ! = NULL ;
bool zb = zb_pages ! = NULL ;
2012-01-18 11:47:31 +00:00
2012-02-12 17:56:06 +00:00
bool res = false ;
2012-01-18 11:47:31 +00:00
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 ) ;
2017-03-12 22:22:45 +00:00
2012-01-18 11:47:31 +00:00
m_fzb_cur_pages [ row ] | = col ;
used | = m_fzb_pages [ i ] ;
2017-03-12 22:22:45 +00:00
used | = m_tex_pages [ i ] ;
2012-01-18 11:47:31 +00:00
}
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 ;
2017-03-12 22:22:45 +00:00
2012-01-18 11:47:31 +00:00
uint32 row = i > > 5 ;
uint32 col = 1 < < ( i & 31 ) ;
2017-03-12 22:22:45 +00:00
2012-01-18 11:47:31 +00:00
m_fzb_cur_pages [ row ] | = col ;
used | = m_fzb_pages [ i ] ;
2017-03-12 22:22:45 +00:00
used | = m_tex_pages [ i ] ;
2012-01-18 11:47:31 +00:00
}
if ( ! synced )
{
if ( used )
{
if ( LOG ) { fprintf ( s_fp , " syncpoint 0 \n " ) ; fflush ( s_fp ) ; }
2012-02-12 17:56:06 +00:00
res = true ;
2012-01-18 11:47:31 +00:00
}
2012-01-21 12:34:36 +00:00
//if(LOG) {fprintf(s_fp, "no syncpoint *\n"); fflush(s_fp);}
2012-01-18 11:47:31 +00:00
}
}
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 ) ; }
2012-02-12 17:56:06 +00:00
res = true ;
2012-01-18 11:47:31 +00:00
}
}
}
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)
2012-02-12 17:56:06 +00:00
if ( fb & & ! res )
2012-01-18 11:47:31 +00:00
{
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 ) ; }
2012-02-12 17:56:06 +00:00
res = true ;
break ;
2012-01-18 11:47:31 +00:00
}
}
}
2012-02-12 17:56:06 +00:00
if ( zb & & ! res )
2012-01-18 11:47:31 +00:00
{
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 ) ; }
2012-02-12 17:56:06 +00:00
res = true ;
break ;
2012-01-18 11:47:31 +00:00
}
}
}
2012-01-13 18:10:05 +00:00
}
}
2012-02-12 17:56:06 +00:00
if ( ! fb & & fb_pages ! = NULL ) delete [ ] fb_pages ;
if ( ! zb & & zb_pages ! = NULL ) delete [ ] zb_pages ;
return res ;
2012-01-13 18:10:05 +00:00
}
2012-01-21 04:44:04 +00:00
bool GSRendererSW : : CheckSourcePages ( SharedData * sd )
{
if ( ! m_rl - > IsSynced ( ) )
{
for ( size_t i = 0 ; sd - > m_tex [ i ] . t ! = NULL ; i + + )
{
2017-03-12 22:22:45 +00:00
sd - > m_tex [ i ] . t - > m_offset - > GetPages ( sd - > m_tex [ i ] . r , m_tmp_pages ) ;
2012-01-21 12:34:36 +00:00
2012-01-21 04:44:04 +00:00
uint32 * pages = m_tmp_pages ; // sd->m_tex[i].t->m_pages.n;
for ( const uint32 * p = pages ; * p ! = GSOffset : : EOP ; p + + )
{
// TODO: 8H 4HL 4HH texture at the same place as the render target (24 bit, or 32-bit where the alpha channel is masked, Valkyrie Profile 2)
if ( m_fzb_pages [ * p ] ) // currently being drawn to? => sync
{
return true ;
}
}
}
}
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 ;
2014-09-15 13:49:16 +00:00
gd . sel . ababcd = 0xff ;
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 )
{
2012-02-08 16:57:14 +00:00
if ( GSLocalMemory : : m_psm [ context - > TEX0 . PSM ] . pal > 0 )
{
m_mem . m_clut . Read32 ( context - > TEX0 , env . TEXA ) ;
}
2009-05-22 01:22:52 +00:00
}
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
}
2015-08-04 11:27:08 +00:00
bool mipmap = IsMipMapActive ( ) ;
2016-07-31 11:14:51 +00:00
GIFRegTEX0 TEX0 = m_context - > GetSizeFixedTEX0 ( s_n , m_vt . m_min . t . xyxy ( m_vt . m_max . t ) , m_vt . IsLinear ( ) , mipmap ) ;
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
2015-08-04 11:27:08 +00:00
GetTextureMinMax ( r , TEX0 , context - > CLAMP , gd . sel . ltf ) ;
GSTextureCacheSW : : Texture * t = m_tc - > Lookup ( TEX0 , env . TEXA ) ;
if ( t = = NULL ) { ASSERT ( 0 ) ; return false ; }
2009-05-22 01:22:52 +00:00
2012-01-21 04:44:04 +00:00
data - > SetSource ( t , r , 0 ) ;
2011-07-25 11:16:01 +00:00
2011-03-17 02:55:20 +00:00
gd . sel . tw = t - > m_tw - 3 ;
2011-03-12 22:10:58 +00:00
2015-08-04 11:27:08 +00:00
if ( mipmap )
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 ;
2014-09-15 13:49:16 +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 ) ;
2017-04-23 17:08:29 +00:00
gd . l = GSVector4 ( ( float ) ( - ( 0x10000 < < context - > TEX1 . L ) ) ) ;
2011-03-27 03:12:12 +00:00
gd . k = GSVector4 ( ( float ) k ) ;
}
2011-03-12 22:10:58 +00:00
2011-03-17 02:55:20 +00:00
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
for ( int i = 1 , j = std : : min < int > ( ( int ) context - > TEX1 . MXL , 6 ) ; i < = j ; i + + )
{
2016-09-25 09:51:48 +00:00
const GIFRegTEX0 & MIP_TEX0 = GetTex0Layer ( i ) ;
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 ; }
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
2012-01-21 04:44:04 +00:00
data - > SetSource ( t , r , i ) ;
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
{
2017-03-03 16:01:13 +00:00
// skip per pixel division if q is constant. Sprite uses flat
// q, so it's always constant by primitive.
// Note: the 'q' division was done in GSRendererSW::ConvertVertexBuffer
gd . sel . fst | = ( m_vt . m_eq . q | | primclass = = GS_SPRITE_CLASS ) ;
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
}
}
}
2015-08-04 11:27:08 +00:00
uint16 tw = 1u < < TEX0 . TW ;
uint16 th = 1u < < 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 :
2012-01-29 10:12:20 +00:00
gd . t . min . u16 [ 0 ] = gd . t . minmax . u16 [ 0 ] = context - > CLAMP . MINU & ( tw - 1 ) ;
gd . t . max . u16 [ 0 ] = gd . t . minmax . u16 [ 2 ] = context - > CLAMP . MAXU & ( tw - 1 ) ;
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 :
2012-01-29 10:12:20 +00:00
gd . t . min . u16 [ 4 ] = gd . t . minmax . u16 [ 1 ] = context - > CLAMP . MINV & ( th - 1 ) ; // skygunner main menu water texture 64x64, MINV = 127
gd . t . max . u16 [ 4 ] = gd . t . minmax . u16 [ 3 ] = context - > CLAMP . MAXV & ( th - 1 ) ;
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 ;
2013-06-20 05:07:52 +00:00
gd . frb = env . FOGCOL . u32 [ 0 ] & 0x00ff00ff ;
gd . fga = ( env . FOGCOL . u32 [ 0 ] > > 8 ) & 0x00ff00ff ;
2011-02-17 03:24:37 +00:00
}
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 ;
2016-08-12 17:20:07 +00:00
gd . sel . ztst = ztest ? context - > TEST . ZTST : ( int ) ZTST_ALWAYS ;
2015-11-07 08:59:41 +00:00
gd . sel . zoverflow = ( uint32 ) GSVector4i ( m_vt . m_max . p ) . z = = 0x80000000U ;
2011-02-17 03:24:37 +00:00
}
2013-06-20 05:07:52 +00:00
# if _M_SSE >= 0x501
gd . fm = fm ;
gd . zm = zm ;
if ( gd . sel . fpsm = = 1 )
{
gd . fm | = 0xff000000 ;
}
else if ( gd . sel . fpsm = = 2 )
{
uint32 rb = gd . fm & 0x00f800f8 ;
uint32 ga = gd . fm & 0x8000f800 ;
gd . fm = ( ga > > 16 ) | ( rb > > 9 ) | ( ga > > 6 ) | ( rb > > 3 ) | 0xffff0000 ;
}
if ( gd . sel . zpsm = = 1 )
{
gd . zm | = 0xff000000 ;
}
else if ( gd . sel . zpsm = = 2 )
{
gd . zm | = 0xffff0000 ;
}
# else
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
2013-06-20 05:07:52 +00:00
# endif
2012-02-12 17:56:06 +00:00
if ( gd . sel . prim = = GS_SPRITE_CLASS & & ! gd . sel . ftest & & ! gd . sel . ztest & & data - > bbox . eq ( data - > bbox . rintersect ( data - > scissor ) ) ) // TODO: check scissor horizontally only
2012-02-08 16:57:14 +00:00
{
gd . sel . notest = 1 ;
uint32 ofx = context - > XYOFFSET . OFX ;
for ( int i = 0 , j = m_vertex . tail ; i < j ; i + + )
{
2013-06-20 05:07:52 +00:00
# if _M_SSE >= 0x501
if ( ( ( ( m_vertex . buff [ i ] . XYZ . X - ofx ) + 15 ) > > 4 ) & 7 ) // aligned to 8
# else
2012-02-08 16:57:14 +00:00
if ( ( ( ( m_vertex . buff [ i ] . XYZ . X - ofx ) + 15 ) > > 4 ) & 3 ) // aligned to 4
2013-06-20 05:07:52 +00:00
# endif
2012-02-08 16:57:14 +00:00
{
gd . sel . notest = 0 ;
break ;
}
}
}
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 )
2015-09-11 10:19:49 +00:00
, m_fpsm ( 0 )
, m_zpsm ( 0 )
2011-12-28 14:10:20 +00:00
, m_using_pages ( false )
2012-01-28 10:07:17 +00:00
, m_syncpoint ( SyncNone )
2011-12-28 14:10:20 +00:00
{
2012-01-21 04:44:04 +00:00
m_tex [ 0 ] . t = 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
{
2012-01-28 10:07:17 +00:00
ReleasePages ( ) ;
2011-12-28 14:10:20 +00:00
2012-01-08 17:10:00 +00:00
if ( global . clut ) _aligned_free ( global . clut ) ;
if ( global . dimx ) _aligned_free ( global . dimx ) ;
2012-02-08 16:57:14 +00:00
if ( LOG ) { fprintf ( s_fp , " [%d] done t=%lld p=%d | %d %d %d | %08x_%08x \n " ,
counter ,
__rdtsc ( ) - start , pixels ,
primclass , vertex_count , index_count ,
global . sel . hi , global . sel . lo
) ;
fflush ( s_fp ) ; }
2011-12-28 14:10:20 +00:00
}
2015-03-01 16:40:48 +00:00
//static TransactionScope::Lock s_lock;
2013-06-17 04:11:10 +00:00
2012-01-28 10:07:17 +00:00
void GSRendererSW : : SharedData : : UsePages ( const uint32 * fb_pages , int fpsm , const uint32 * zb_pages , int zpsm )
2011-12-28 14:10:20 +00:00
{
if ( m_using_pages ) return ;
{
2013-06-17 04:11:10 +00:00
//TransactionScope scope(s_lock);
2011-12-28 14:10:20 +00:00
2015-10-14 15:49:05 +00:00
if ( global . sel . fb & & fb_pages ! = NULL )
2013-06-17 04:11:10 +00:00
{
m_parent - > UsePages ( fb_pages , 0 ) ;
}
2011-12-28 14:10:20 +00:00
2015-10-14 15:49:05 +00:00
if ( global . sel . zb & & zb_pages ! = NULL )
2013-06-17 04:11:10 +00:00
{
m_parent - > UsePages ( zb_pages , 1 ) ;
}
for ( size_t i = 0 ; m_tex [ i ] . t ! = NULL ; i + + )
{
m_parent - > UsePages ( m_tex [ i ] . t - > m_pages . n , 2 ) ;
}
2012-01-28 10:07:17 +00:00
}
m_fb_pages = fb_pages ;
m_zb_pages = zb_pages ;
m_fpsm = fpsm ;
m_zpsm = zpsm ;
2011-12-28 14:10:20 +00:00
m_using_pages = true ;
}
2012-01-28 10:07:17 +00:00
void GSRendererSW : : SharedData : : ReleasePages ( )
{
if ( ! m_using_pages ) return ;
{
2013-06-17 04:11:10 +00:00
//TransactionScope scope(s_lock);
2012-01-28 10:07:17 +00:00
2013-06-17 04:11:10 +00:00
if ( global . sel . fb )
{
m_parent - > ReleasePages ( m_fb_pages , 0 ) ;
}
2012-01-28 10:07:17 +00:00
2013-06-17 04:11:10 +00:00
if ( global . sel . zb )
{
m_parent - > ReleasePages ( m_zb_pages , 1 ) ;
}
for ( size_t i = 0 ; m_tex [ i ] . t ! = NULL ; i + + )
{
m_parent - > ReleasePages ( m_tex [ i ] . t - > m_pages . n , 2 ) ;
}
2012-01-28 10:07:17 +00:00
}
delete [ ] m_fb_pages ;
delete [ ] m_zb_pages ;
m_fb_pages = NULL ;
m_zb_pages = NULL ;
m_using_pages = false ;
}
2012-01-21 04:44:04 +00:00
void GSRendererSW : : SharedData : : SetSource ( GSTextureCacheSW : : Texture * t , const GSVector4i & r , int level )
2011-12-28 14:10:20 +00:00
{
2012-01-21 04:44:04 +00:00
ASSERT ( m_tex [ level ] . t = = NULL ) ;
m_tex [ level ] . t = t ;
m_tex [ level ] . r = r ;
m_tex [ level + 1 ] . t = NULL ;
}
2012-01-28 10:07:17 +00:00
void GSRendererSW : : SharedData : : UpdateSource ( )
2012-01-21 04:44:04 +00:00
{
for ( size_t i = 0 ; m_tex [ i ] . t ! = NULL ; i + + )
{
2012-01-21 12:34:36 +00:00
if ( m_tex [ i ] . t - > Update ( m_tex [ i ] . r ) )
{
global . tex [ i ] = m_tex [ i ] . t - > m_buff ;
}
else
{
printf ( " GSdx: out-of-memory, texturing temporarily disabled \n " ) ;
2012-01-18 11:47:31 +00:00
2012-01-21 12:34:36 +00:00
global . sel . tfx = TFX_NONE ;
}
2012-02-14 08:03:27 +00:00
}
2011-12-28 14:10:20 +00:00
2012-02-14 08:03:27 +00:00
// TODO
2012-01-27 11:56:49 +00:00
2012-02-14 08:03:27 +00:00
if ( m_parent - > s_dump )
{
uint64 frame = m_parent - > m_perfmon . GetFrame ( ) ;
2012-01-21 04:44:04 +00:00
2017-05-26 15:26:46 +00:00
std : : string s ;
2012-01-21 04:44:04 +00:00
2015-05-01 11:35:21 +00:00
if ( m_parent - > s_savet & & m_parent - > s_n > = m_parent - > s_saven )
2012-02-14 08:03:27 +00:00
{
for ( size_t i = 0 ; m_tex [ i ] . t ! = NULL ; i + + )
2012-01-21 04:44:04 +00:00
{
2016-09-25 09:51:48 +00:00
const GIFRegTEX0 & TEX0 = m_parent - > GetTex0Layer ( i ) ;
2016-09-24 07:15:40 +00:00
2016-09-27 16:59:06 +00:00
s = format ( " %05d_f%lld_itex%d_%05x_%s.bmp " , m_parent - > s_n , frame , i , TEX0 . TBP0 , psm_str ( TEX0 . PSM ) ) ;
2012-01-21 04:44:04 +00:00
2015-02-21 12:51:06 +00:00
m_tex [ i ] . t - > Save ( root_sw + s ) ;
2012-01-21 04:44:04 +00:00
}
2012-02-14 08:03:27 +00:00
if ( global . clut ! = NULL )
{
GSTextureSW * t = new GSTextureSW ( 0 , 256 , 1 ) ;
t - > Update ( GSVector4i ( 0 , 0 , 256 , 1 ) , global . clut , sizeof ( uint32 ) * 256 ) ;
2016-09-27 16:59:06 +00:00
s = format ( " %05d_f%lld_itexp_%05x_%s.bmp " , m_parent - > s_n , frame , ( int ) m_parent - > m_context - > TEX0 . CBP , psm_str ( m_parent - > m_context - > TEX0 . CPSM ) ) ;
2012-02-14 08:03:27 +00:00
2015-02-21 12:51:06 +00:00
t - > Save ( root_sw + s ) ;
2012-02-14 08:03:27 +00:00
delete t ;
}
2012-01-21 04:44:04 +00:00
}
}
2011-12-28 14:10:20 +00:00
}