2014-09-07 20:06:58 -05:00
#include "Common/CommonTypes.h"
2010-10-03 08:20:24 +00:00
2014-02-17 05:18:15 -05:00
#include "VideoCommon/BPStructs.h"
#include "VideoCommon/Debugger.h"
#include "VideoCommon/IndexGenerator.h"
#include "VideoCommon/MainBase.h"
#include "VideoCommon/NativeVertexFormat.h"
#include "VideoCommon/OpcodeDecoding.h"
#include "VideoCommon/PerfQueryBase.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
2010-10-03 08:20:24 +00:00
VertexManager * g_vertex_manager ;
2013-02-21 12:36:29 +01:00
u8 * VertexManager :: s_pCurBufferPointer ;
2013-02-22 01:41:52 -06:00
u8 * VertexManager :: s_pBaseBufferPointer ;
2013-02-21 12:36:29 +01:00
u8 * VertexManager :: s_pEndBufferPointer ;
2010-10-03 08:20:24 +00:00
2014-01-15 21:44:46 +01:00
PrimitiveType VertexManager :: current_primitive_type ;
2014-01-23 13:11:38 +01:00
bool VertexManager :: IsFlushed ;
2014-01-15 21:44:46 +01:00
static const PrimitiveType primitive_from_gx [ 8 ] = {
PRIMITIVE_TRIANGLES , // GX_DRAW_QUADS
2014-05-08 16:53:18 -07:00
PRIMITIVE_TRIANGLES , // GX_DRAW_QUADS_2
2014-01-15 21:44:46 +01:00
PRIMITIVE_TRIANGLES , // GX_DRAW_TRIANGLES
PRIMITIVE_TRIANGLES , // GX_DRAW_TRIANGLE_STRIP
PRIMITIVE_TRIANGLES , // GX_DRAW_TRIANGLE_FAN
PRIMITIVE_LINES , // GX_DRAW_LINES
PRIMITIVE_LINES , // GX_DRAW_LINE_STRIP
PRIMITIVE_POINTS , // GX_DRAW_POINTS
};
2010-10-03 08:20:24 +00:00
VertexManager :: VertexManager ()
{
2014-01-23 13:11:38 +01:00
IsFlushed = true ;
2010-10-03 08:20:24 +00:00
}
VertexManager ::~ VertexManager ()
2013-04-24 09:21:54 -04:00
{
}
2010-10-03 08:20:24 +00:00
2013-02-26 22:47:50 -06:00
u32 VertexManager :: GetRemainingSize ()
2010-10-03 08:20:24 +00:00
{
2013-02-26 22:47:50 -06:00
return ( u32 )( s_pEndBufferPointer - s_pCurBufferPointer );
}
2014-12-09 08:35:04 +01:00
DataReader VertexManager :: PrepareForAdditionalData ( int primitive , u32 count , u32 stride )
2013-10-29 01:23:17 -04:00
{
2014-11-11 01:48:38 -08:00
// The SSE vertex loader can write up to 4 bytes past the end
u32 const needed_vertex_bytes = count * stride + 4 ;
2013-10-29 01:23:17 -04:00
2014-01-15 21:44:46 +01:00
// We can't merge different kinds of primitives, so we have to flush here
if ( current_primitive_type != primitive_from_gx [ primitive ])
Flush ();
current_primitive_type = primitive_from_gx [ primitive ];
// Check for size in buffer, if the buffer gets full, call Flush()
2014-01-23 23:39:20 +01:00
if ( ! IsFlushed && ( count > IndexGenerator :: GetRemainingIndices () ||
count > GetRemainingIndices ( primitive ) || needed_vertex_bytes > GetRemainingSize () ) )
2013-02-26 22:47:50 -06:00
{
Flush ();
2013-10-29 01:23:17 -04:00
2014-03-11 00:30:55 +13:00
if ( count > IndexGenerator :: GetRemainingIndices ())
2013-03-31 19:10:21 -04:00
ERROR_LOG ( VIDEO , "Too little remaining index values. Use 32-bit or reset them on flush." );
2013-03-06 12:33:02 +01:00
if ( count > GetRemainingIndices ( primitive ))
ERROR_LOG ( VIDEO , "VertexManager: Buffer not large enough for all indices! "
2013-03-31 19:10:21 -04:00
"Increase MAXIBUFFERSIZE or we need primitive breaking after all." );
2013-03-23 00:18:35 +01:00
if ( needed_vertex_bytes > GetRemainingSize ())
ERROR_LOG ( VIDEO , "VertexManager: Buffer not large enough for all vertices! "
2013-03-31 19:10:21 -04:00
"Increase MAXVBUFFERSIZE or we need primitive breaking after all." );
2013-02-26 22:47:50 -06:00
}
2010-10-03 08:20:24 +00:00
2014-01-23 13:11:38 +01:00
// need to alloc new buffer
2014-03-11 00:30:55 +13:00
if ( IsFlushed )
2014-01-23 13:11:38 +01:00
{
g_vertex_manager -> ResetBuffer ( stride );
IsFlushed = false ;
}
2014-12-09 08:35:04 +01:00
return DataReader ( s_pCurBufferPointer , s_pEndBufferPointer );
}
void VertexManager :: FlushData ( u32 count , u32 stride )
{
s_pCurBufferPointer += count * stride ;
2013-02-22 01:41:52 -06:00
}
2013-02-26 22:47:50 -06:00
u32 VertexManager :: GetRemainingIndices ( int primitive )
2010-10-03 08:20:24 +00:00
{
2014-01-15 21:44:46 +01:00
u32 index_len = MAXIBUFFERSIZE - IndexGenerator :: GetIndexLen ();
2013-10-29 01:23:17 -04:00
2014-03-11 00:30:55 +13:00
if ( g_Config . backend_info . bSupportsPrimitiveRestart )
2013-04-24 09:21:54 -04:00
{
2013-03-29 14:27:33 +01:00
switch ( primitive )
{
case GX_DRAW_QUADS :
2014-05-08 16:53:18 -07:00
case GX_DRAW_QUADS_2 :
2014-01-15 21:44:46 +01:00
return index_len / 5 * 4 ;
2013-03-29 14:27:33 +01:00
case GX_DRAW_TRIANGLES :
2014-01-15 21:44:46 +01:00
return index_len / 4 * 3 ;
2013-03-29 14:27:33 +01:00
case GX_DRAW_TRIANGLE_STRIP :
2014-01-15 21:44:46 +01:00
return index_len / 1 - 1 ;
2013-03-29 14:27:33 +01:00
case GX_DRAW_TRIANGLE_FAN :
2014-01-15 21:44:46 +01:00
return index_len / 6 * 4 + 1 ;
2010-10-03 08:20:24 +00:00
2013-03-29 14:27:33 +01:00
case GX_DRAW_LINES :
2014-01-15 21:44:46 +01:00
return index_len ;
2013-03-29 14:27:33 +01:00
case GX_DRAW_LINE_STRIP :
2014-01-15 21:44:46 +01:00
return index_len / 2 + 1 ;
2010-10-03 08:20:24 +00:00
2013-03-29 14:27:33 +01:00
case GX_DRAW_POINTS :
2014-01-15 21:44:46 +01:00
return index_len ;
2010-10-03 08:20:24 +00:00
2013-03-29 14:27:33 +01:00
default :
return 0 ;
}
2013-04-24 09:21:54 -04:00
}
else
{
2013-03-29 14:27:33 +01:00
switch ( primitive )
{
case GX_DRAW_QUADS :
2014-05-08 16:53:18 -07:00
case GX_DRAW_QUADS_2 :
2014-01-15 21:44:46 +01:00
return index_len / 6 * 4 ;
2013-03-29 14:27:33 +01:00
case GX_DRAW_TRIANGLES :
2014-01-15 21:44:46 +01:00
return index_len ;
2013-03-29 14:27:33 +01:00
case GX_DRAW_TRIANGLE_STRIP :
2014-01-15 21:44:46 +01:00
return index_len / 3 + 2 ;
2013-03-29 14:27:33 +01:00
case GX_DRAW_TRIANGLE_FAN :
2014-01-15 21:44:46 +01:00
return index_len / 3 + 2 ;
2013-03-29 14:27:33 +01:00
case GX_DRAW_LINES :
2014-01-15 21:44:46 +01:00
return index_len ;
2013-03-29 14:27:33 +01:00
case GX_DRAW_LINE_STRIP :
2014-01-15 21:44:46 +01:00
return index_len / 2 + 1 ;
2013-03-29 14:27:33 +01:00
case GX_DRAW_POINTS :
2014-01-15 21:44:46 +01:00
return index_len ;
2013-03-29 14:27:33 +01:00
default :
return 0 ;
}
2013-10-29 01:23:17 -04:00
}
2010-10-03 08:20:24 +00:00
}
void VertexManager :: Flush ()
{
2014-09-07 20:06:58 -05:00
if ( IsFlushed )
return ;
2013-03-19 21:51:12 -04:00
2012-12-21 21:04:53 +01:00
// loading a state will invalidate BP, so check for it
2012-12-23 13:32:23 +01:00
g_video_backend -> CheckInvalidState ();
2013-03-19 21:51:12 -04:00
2013-02-22 01:41:52 -06:00
VideoFifo_CheckEFBAccess ();
2013-03-19 21:51:12 -04:00
2014-01-21 10:47:00 +01:00
#if defined(_DEBUG) || defined(DEBUGFAST)
2014-04-27 11:59:04 -07:00
PRIM_LOG ( "frame%d: \n texgen=%d, numchan=%d, dualtex=%d, ztex=%d, cole=%d, alpe=%d, ze=%d" , g_ActiveConfig . iSaveTargetId , xfmem . numTexGen . numTexGens ,
xfmem . numChan . numColorChans , xfmem . dualTexTrans . enabled , bpmem . ztex2 . op ,
2014-06-11 20:34:15 +02:00
( int ) bpmem . blendmode . colorupdate , ( int ) bpmem . blendmode . alphaupdate , ( int ) bpmem . zmode . updateenable );
2014-01-21 10:47:00 +01:00
2014-04-27 11:59:04 -07:00
for ( unsigned int i = 0 ; i < xfmem . numChan . numColorChans ; ++ i )
2014-01-21 10:47:00 +01:00
{
2014-04-27 11:59:04 -07:00
LitChannel * ch = & xfmem . color [ i ];
2014-01-21 10:47:00 +01:00
PRIM_LOG ( "colchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d" , i , ch -> matsource , ch -> GetFullLightMask (), ch -> ambsource , ch -> diffusefunc , ch -> attnfunc );
2014-04-27 11:59:04 -07:00
ch = & xfmem . alpha [ i ];
2014-01-21 10:47:00 +01:00
PRIM_LOG ( "alpchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d" , i , ch -> matsource , ch -> GetFullLightMask (), ch -> ambsource , ch -> diffusefunc , ch -> attnfunc );
}
2014-04-27 11:59:04 -07:00
for ( unsigned int i = 0 ; i < xfmem . numTexGen . numTexGens ; ++ i )
2014-01-21 10:47:00 +01:00
{
2014-04-27 11:59:04 -07:00
TexMtxInfo tinfo = xfmem . texMtxInfo [ i ];
2014-01-21 10:47:00 +01:00
if ( tinfo . texgentype != XF_TEXGEN_EMBOSS_MAP ) tinfo . hex &= 0x7ff ;
if ( tinfo . texgentype != XF_TEXGEN_REGULAR ) tinfo . projection = 0 ;
PRIM_LOG ( "txgen%d: proj=%d, input=%d, gentype=%d, srcrow=%d, embsrc=%d, emblght=%d, postmtx=%d, postnorm=%d" ,
i , tinfo . projection , tinfo . inputform , tinfo . texgentype , tinfo . sourcerow , tinfo . embosssourceshift , tinfo . embosslightshift ,
2014-04-27 11:59:04 -07:00
xfmem . postMtxInfo [ i ]. index , xfmem . postMtxInfo [ i ]. normalize );
2014-01-21 10:47:00 +01:00
}
2014-06-11 20:34:15 +02:00
PRIM_LOG ( "pixel: tev=%d, ind=%d, texgen=%d, dstalpha=%d, alphatest=0x%x" , ( int ) bpmem . genMode . numtevstages + 1 , ( int ) bpmem . genMode . numindstages ,
( int ) bpmem . genMode . numtexgens , ( u32 ) bpmem . dstalpha . enable , ( bpmem . alpha_test . hex >> 16 ) & 0xff );
2014-01-21 10:47:00 +01:00
#endif
2014-10-21 20:42:55 -04:00
BitSet32 usedtextures ;
2014-01-21 10:47:00 +01:00
for ( u32 i = 0 ; i < bpmem . genMode . numtevstages + 1u ; ++ i )
if ( bpmem . tevorders [ i / 2 ]. getEnable ( i & 1 ))
2014-10-21 20:42:55 -04:00
usedtextures [ bpmem . tevorders [ i / 2 ]. getTexMap ( i & 1 )] = true ;
2014-01-21 10:47:00 +01:00
if ( bpmem . genMode . numindstages > 0 )
for ( unsigned int i = 0 ; i < bpmem . genMode . numtevstages + 1u ; ++ i )
if ( bpmem . tevind [ i ]. IsActive () && bpmem . tevind [ i ]. bt < bpmem . genMode . numindstages )
2014-10-21 20:42:55 -04:00
usedtextures [ bpmem . tevindref . getTexMap ( bpmem . tevind [ i ]. bt )] = true ;
2014-01-21 10:47:00 +01:00
2014-10-21 20:42:55 -04:00
for ( unsigned int i : usedtextures )
2014-01-21 10:47:00 +01:00
{
2014-10-21 20:42:55 -04:00
g_renderer -> SetSamplerState ( i & 3 , i >> 2 );
const FourTexUnits & tex = bpmem . tex [ i >> 2 ];
const TextureCache :: TCacheEntryBase * tentry = TextureCache :: Load ( i ,
( tex . texImage3 [ i & 3 ]. image_base /* & 0x1FFFFF*/ ) << 5 ,
tex . texImage0 [ i & 3 ]. width + 1 , tex . texImage0 [ i & 3 ]. height + 1 ,
tex . texImage0 [ i & 3 ]. format , tex . texTlut [ i & 3 ]. tmem_offset << 9 ,
tex . texTlut [ i & 3 ]. tlut_format ,
(( tex . texMode0 [ i & 3 ]. min_filter & 3 ) != 0 ),
( tex . texMode1 [ i & 3 ]. max_lod + 0xf ) / 0x10 ,
( tex . texImage1 [ i & 3 ]. image_type != 0 ));
2014-01-21 10:47:00 +01:00
2014-10-21 20:42:55 -04:00
if ( tentry )
{
// 0s are probably for no manual wrapping needed.
PixelShaderManager :: SetTexDims ( i , tentry -> native_width , tentry -> native_height , 0 , 0 );
2014-01-21 10:47:00 +01:00
}
2014-10-21 20:42:55 -04:00
else
ERROR_LOG ( VIDEO , "error loading texture" );
2014-01-21 10:47:00 +01:00
}
// set global constants
VertexShaderManager :: SetConstants ();
PixelShaderManager :: SetConstants ();
2014-03-11 00:30:55 +13:00
bool useDstAlpha = ! g_ActiveConfig . bDstAlphaPass &&
bpmem . dstalpha . enable &&
bpmem . blendmode . alphaupdate &&
2014-03-23 21:44:23 +01:00
bpmem . zcontrol . pixel_format == PEControl :: RGBA6_Z24 ;
2014-02-03 16:56:17 +01:00
2014-03-11 00:30:55 +13:00
if ( PerfQueryBase :: ShouldEmulate ())
2014-02-04 20:16:03 +01:00
g_perf_query -> EnableQuery ( bpmem . zcontrol . early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP );
2014-02-03 16:56:17 +01:00
g_vertex_manager -> vFlush ( useDstAlpha );
2014-03-11 00:30:55 +13:00
if ( PerfQueryBase :: ShouldEmulate ())
2014-02-04 20:16:03 +01:00
g_perf_query -> DisableQuery ( bpmem . zcontrol . early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP );
2014-02-03 16:56:17 +01:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_FLUSH , true );
2013-03-19 21:51:12 -04:00
2014-09-24 10:46:09 +10:00
if ( xfmem . numTexGen . numTexGens != bpmem . genMode . numtexgens )
ERROR_LOG ( VIDEO , "xf.numtexgens (%d) does not match bp.numtexgens (%d). Error in command stream." , xfmem . numTexGen . numTexGens , bpmem . genMode . numtexgens . Value ());
2014-01-23 13:11:38 +01:00
IsFlushed = true ;
2010-10-03 08:20:24 +00:00
}
2010-10-19 22:24:27 +00:00
2012-01-04 00:42:22 -08:00
void VertexManager :: DoState ( PointerWrap & p )
{
g_vertex_manager -> vDoState ( p );
}