2014-09-07 19:06:58 -06:00
# include "Common/CommonTypes.h"
2014-02-17 03:18:15 -07: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 02:20:24 -06:00
VertexManager * g_vertex_manager ;
2013-02-21 04:36:29 -07:00
u8 * VertexManager : : s_pCurBufferPointer ;
2013-02-22 00:41:52 -07:00
u8 * VertexManager : : s_pBaseBufferPointer ;
2013-02-21 04:36:29 -07:00
u8 * VertexManager : : s_pEndBufferPointer ;
2010-10-03 02:20:24 -06:00
2014-01-15 13:44:46 -07:00
PrimitiveType VertexManager : : current_primitive_type ;
2014-01-23 05:11:38 -07:00
bool VertexManager : : IsFlushed ;
2014-01-15 13:44:46 -07:00
static const PrimitiveType primitive_from_gx [ 8 ] = {
PRIMITIVE_TRIANGLES , // GX_DRAW_QUADS
2014-05-08 17:53:18 -06:00
PRIMITIVE_TRIANGLES , // GX_DRAW_QUADS_2
2014-01-15 13:44:46 -07: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 02:20:24 -06:00
VertexManager : : VertexManager ( )
{
2014-01-23 05:11:38 -07:00
IsFlushed = true ;
2010-10-03 02:20:24 -06:00
}
VertexManager : : ~ VertexManager ( )
2013-04-24 07:21:54 -06:00
{
}
2010-10-03 02:20:24 -06:00
2013-02-26 21:47:50 -07:00
u32 VertexManager : : GetRemainingSize ( )
2010-10-03 02:20:24 -06:00
{
2013-02-26 21:47:50 -07:00
return ( u32 ) ( s_pEndBufferPointer - s_pCurBufferPointer ) ;
}
void VertexManager : : PrepareForAdditionalData ( int primitive , u32 count , u32 stride )
2013-10-28 23:23:17 -06:00
{
2013-02-26 21:47:50 -07:00
u32 const needed_vertex_bytes = count * stride ;
2013-10-28 23:23:17 -06:00
2014-01-15 13:44:46 -07: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 15:39:20 -07:00
if ( ! IsFlushed & & ( count > IndexGenerator : : GetRemainingIndices ( ) | |
count > GetRemainingIndices ( primitive ) | | needed_vertex_bytes > GetRemainingSize ( ) ) )
2013-02-26 21:47:50 -07:00
{
Flush ( ) ;
2013-10-28 23:23:17 -06:00
2014-03-10 05:30:55 -06:00
if ( count > IndexGenerator : : GetRemainingIndices ( ) )
2013-03-31 17:10:21 -06:00
ERROR_LOG ( VIDEO , " Too little remaining index values. Use 32-bit or reset them on flush. " ) ;
2013-03-06 04:33:02 -07:00
if ( count > GetRemainingIndices ( primitive ) )
ERROR_LOG ( VIDEO , " VertexManager: Buffer not large enough for all indices! "
2013-03-31 17:10:21 -06:00
" Increase MAXIBUFFERSIZE or we need primitive breaking after all. " ) ;
2013-03-22 17:18:35 -06:00
if ( needed_vertex_bytes > GetRemainingSize ( ) )
ERROR_LOG ( VIDEO , " VertexManager: Buffer not large enough for all vertices! "
2013-03-31 17:10:21 -06:00
" Increase MAXVBUFFERSIZE or we need primitive breaking after all. " ) ;
2013-02-26 21:47:50 -07:00
}
2010-10-03 02:20:24 -06:00
2014-01-23 05:11:38 -07:00
// need to alloc new buffer
2014-03-10 05:30:55 -06:00
if ( IsFlushed )
2014-01-23 05:11:38 -07:00
{
g_vertex_manager - > ResetBuffer ( stride ) ;
IsFlushed = false ;
}
2013-02-22 00:41:52 -07:00
}
2013-02-26 21:47:50 -07:00
u32 VertexManager : : GetRemainingIndices ( int primitive )
2010-10-03 02:20:24 -06:00
{
2014-01-15 13:44:46 -07:00
u32 index_len = MAXIBUFFERSIZE - IndexGenerator : : GetIndexLen ( ) ;
2013-10-28 23:23:17 -06:00
2014-03-10 05:30:55 -06:00
if ( g_Config . backend_info . bSupportsPrimitiveRestart )
2013-04-24 07:21:54 -06:00
{
2013-03-29 07:27:33 -06:00
switch ( primitive )
{
case GX_DRAW_QUADS :
2014-05-08 17:53:18 -06:00
case GX_DRAW_QUADS_2 :
2014-01-15 13:44:46 -07:00
return index_len / 5 * 4 ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_TRIANGLES :
2014-01-15 13:44:46 -07:00
return index_len / 4 * 3 ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_TRIANGLE_STRIP :
2014-01-15 13:44:46 -07:00
return index_len / 1 - 1 ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_TRIANGLE_FAN :
2014-01-15 13:44:46 -07:00
return index_len / 6 * 4 + 1 ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_LINES :
2014-01-15 13:44:46 -07:00
return index_len ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_LINE_STRIP :
2014-01-15 13:44:46 -07:00
return index_len / 2 + 1 ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_POINTS :
2014-01-15 13:44:46 -07:00
return index_len ;
2013-03-29 07:27:33 -06:00
default :
return 0 ;
}
2013-04-24 07:21:54 -06:00
}
else
{
2013-03-29 07:27:33 -06:00
switch ( primitive )
{
case GX_DRAW_QUADS :
2014-05-08 17:53:18 -06:00
case GX_DRAW_QUADS_2 :
2014-01-15 13:44:46 -07:00
return index_len / 6 * 4 ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_TRIANGLES :
2014-01-15 13:44:46 -07:00
return index_len ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_TRIANGLE_STRIP :
2014-01-15 13:44:46 -07:00
return index_len / 3 + 2 ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_TRIANGLE_FAN :
2014-01-15 13:44:46 -07:00
return index_len / 3 + 2 ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_LINES :
2014-01-15 13:44:46 -07:00
return index_len ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_LINE_STRIP :
2014-01-15 13:44:46 -07:00
return index_len / 2 + 1 ;
2013-03-29 07:27:33 -06:00
case GX_DRAW_POINTS :
2014-01-15 13:44:46 -07:00
return index_len ;
2013-03-29 07:27:33 -06:00
default :
return 0 ;
}
2013-10-28 23:23:17 -06:00
}
2010-10-03 02:20:24 -06:00
}
void VertexManager : : Flush ( )
{
2014-09-07 19:06:58 -06:00
if ( IsFlushed )
return ;
2013-03-19 19:51:12 -06:00
2012-12-21 13:04:53 -07:00
// loading a state will invalidate BP, so check for it
2012-12-23 05:32:23 -07:00
g_video_backend - > CheckInvalidState ( ) ;
2013-03-19 19:51:12 -06:00
2013-02-22 00:41:52 -07:00
VideoFifo_CheckEFBAccess ( ) ;
2013-03-19 19:51:12 -06:00
2014-01-21 02:47:00 -07:00
# if defined(_DEBUG) || defined(DEBUGFAST)
2014-04-27 12:59:04 -06: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 12:34:15 -06:00
( int ) bpmem . blendmode . colorupdate , ( int ) bpmem . blendmode . alphaupdate , ( int ) bpmem . zmode . updateenable ) ;
2014-01-21 02:47:00 -07:00
2014-04-27 12:59:04 -06:00
for ( unsigned int i = 0 ; i < xfmem . numChan . numColorChans ; + + i )
2014-01-21 02:47:00 -07:00
{
2014-04-27 12:59:04 -06:00
LitChannel * ch = & xfmem . color [ i ] ;
2014-01-21 02:47:00 -07: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 12:59:04 -06:00
ch = & xfmem . alpha [ i ] ;
2014-01-21 02:47:00 -07: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 12:59:04 -06:00
for ( unsigned int i = 0 ; i < xfmem . numTexGen . numTexGens ; + + i )
2014-01-21 02:47:00 -07:00
{
2014-04-27 12:59:04 -06:00
TexMtxInfo tinfo = xfmem . texMtxInfo [ i ] ;
2014-01-21 02:47:00 -07: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 12:59:04 -06:00
xfmem . postMtxInfo [ i ] . index , xfmem . postMtxInfo [ i ] . normalize ) ;
2014-01-21 02:47:00 -07:00
}
2014-06-11 12:34:15 -06: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 02:47:00 -07:00
# endif
u32 usedtextures = 0 ;
for ( u32 i = 0 ; i < bpmem . genMode . numtevstages + 1u ; + + i )
if ( bpmem . tevorders [ i / 2 ] . getEnable ( i & 1 ) )
usedtextures | = 1 < < bpmem . tevorders [ i / 2 ] . getTexMap ( i & 1 ) ;
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 )
usedtextures | = 1 < < bpmem . tevindref . getTexMap ( bpmem . tevind [ i ] . bt ) ;
for ( unsigned int i = 0 ; i < 8 ; i + + )
{
if ( usedtextures & ( 1 < < i ) )
{
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 ) ) ;
if ( tentry )
{
// 0s are probably for no manual wrapping needed.
PixelShaderManager : : SetTexDims ( i , tentry - > native_width , tentry - > native_height , 0 , 0 ) ;
}
else
ERROR_LOG ( VIDEO , " error loading texture " ) ;
}
}
// set global constants
VertexShaderManager : : SetConstants ( ) ;
PixelShaderManager : : SetConstants ( ) ;
2014-03-10 05:30:55 -06:00
bool useDstAlpha = ! g_ActiveConfig . bDstAlphaPass & &
bpmem . dstalpha . enable & &
bpmem . blendmode . alphaupdate & &
2014-03-23 14:44:23 -06:00
bpmem . zcontrol . pixel_format = = PEControl : : RGBA6_Z24 ;
2014-02-03 08:56:17 -07:00
2014-03-10 05:30:55 -06:00
if ( PerfQueryBase : : ShouldEmulate ( ) )
2014-02-04 12:16:03 -07:00
g_perf_query - > EnableQuery ( bpmem . zcontrol . early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP ) ;
2014-02-03 08:56:17 -07:00
g_vertex_manager - > vFlush ( useDstAlpha ) ;
2014-03-10 05:30:55 -06:00
if ( PerfQueryBase : : ShouldEmulate ( ) )
2014-02-04 12:16:03 -07:00
g_perf_query - > DisableQuery ( bpmem . zcontrol . early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP ) ;
2014-02-03 08:56:17 -07:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_FLUSH , true ) ;
2013-03-19 19:51:12 -06:00
2014-09-23 18:46:09 -06: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 05:11:38 -07:00
IsFlushed = true ;
2010-10-03 02:20:24 -06:00
}
2010-10-19 16:24:27 -06:00
2012-01-04 01:42:22 -07:00
void VertexManager : : DoState ( PointerWrap & p )
{
g_vertex_manager - > vDoState ( p ) ;
}