2009-07-28 21:32:10 +00:00
// Copyright (C) 2003 Dolphin Project.
2008-12-08 05:25:12 +00:00
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
# include <assert.h>
# include "Common.h"
2008-12-26 13:09:16 +00:00
# include "VideoCommon.h"
2009-09-13 21:18:04 +00:00
# include "VideoConfig.h"
2008-12-08 05:25:12 +00:00
# include "Profiler.h"
# include "MemoryUtil.h"
# include "StringUtil.h"
# include "x64Emitter.h"
# include "ABI.h"
2009-10-10 21:19:39 +00:00
# include "PixelEngine.h"
2008-12-08 05:25:12 +00:00
# include "LookUpTables.h"
# include "Statistics.h"
# include "VertexLoaderManager.h"
# include "VertexLoader.h"
2009-06-22 09:31:30 +00:00
# include "BPMemory.h"
2008-12-08 05:25:12 +00:00
# include "DataReader.h"
2008-12-26 12:56:56 +00:00
# include "NativeVertexWriter.h"
2008-12-08 05:25:12 +00:00
# include "VertexLoader_Position.h"
# include "VertexLoader_Normal.h"
# include "VertexLoader_Color.h"
# include "VertexLoader_TextCoord.h"
2009-06-28 20:04:07 +00:00
//BBox
# include "XFMemory.h"
extern float GC_ALIGNED16 ( g_fProjectionMatrix [ 16 ] ) ;
2008-12-08 05:25:12 +00:00
# define USE_JIT
2008-12-19 21:24:52 +00:00
# define COMPILED_CODE_SIZE 4096
2008-12-08 05:25:12 +00:00
NativeVertexFormat * g_nativeVertexFmt ;
# ifndef _WIN32
# undef inline
# define inline
# endif
2008-12-25 21:44:56 +00:00
// Matrix components are first in GC format but later in PC format - we need to store it temporarily
// when decoding each vertex.
2008-12-08 05:25:12 +00:00
static u8 s_curposmtx ;
static u8 s_curtexmtx [ 8 ] ;
static int s_texmtxwrite = 0 ;
static int s_texmtxread = 0 ;
2008-12-25 21:44:56 +00:00
2008-12-08 05:25:12 +00:00
static int loop_counter ;
// Vertex loaders read these. Although the scale ones should be baked into the shader.
int tcIndex ;
int colIndex ;
TVtxAttr * pVtxAttr ;
int colElements [ 2 ] ;
float posScale ;
2010-02-24 23:58:48 +00:00
float tcScale [ 8 ] ;
2008-12-08 05:25:12 +00:00
using namespace Gen ;
void LOADERDECL PosMtx_ReadDirect_UByte ( )
{
s_curposmtx = DataReadU8 ( ) & 0x3f ;
PRIM_LOG ( " posmtx: %d, " , s_curposmtx ) ;
}
void LOADERDECL PosMtx_Write ( )
{
* VertexManager : : s_pCurBufferPointer + + = s_curposmtx ;
* VertexManager : : s_pCurBufferPointer + + = 0 ;
* VertexManager : : s_pCurBufferPointer + + = 0 ;
* VertexManager : : s_pCurBufferPointer + + = 0 ;
}
2009-06-28 20:04:07 +00:00
void LOADERDECL UpdateBoundingBox ( )
{
2009-10-10 21:19:39 +00:00
if ( ! PixelEngine : : bbox_active )
2009-06-28 20:04:07 +00:00
return ;
// Truly evil hack, reading backwards from the write pointer. If we were writing to write-only
// memory like we might have been with a D3D vertex buffer, this would have been a bad idea.
float * data = ( float * ) ( VertexManager : : s_pCurBufferPointer - 12 ) ;
// We must transform the just loaded point by the current world and projection matrix - in software.
// Then convert to screen space and update the bounding box.
float p [ 3 ] = { data [ 0 ] , data [ 1 ] , data [ 2 ] } ;
const float * world_matrix = ( float * ) xfmem + MatrixIndexA . PosNormalMtxIdx * 4 ;
const float * proj_matrix = & g_fProjectionMatrix [ 0 ] ;
float t [ 3 ] ;
t [ 0 ] = p [ 0 ] * world_matrix [ 0 ] + p [ 1 ] * world_matrix [ 1 ] + p [ 2 ] * world_matrix [ 2 ] + world_matrix [ 3 ] ;
t [ 1 ] = p [ 0 ] * world_matrix [ 4 ] + p [ 1 ] * world_matrix [ 5 ] + p [ 2 ] * world_matrix [ 6 ] + world_matrix [ 7 ] ;
t [ 2 ] = p [ 0 ] * world_matrix [ 8 ] + p [ 1 ] * world_matrix [ 9 ] + p [ 2 ] * world_matrix [ 10 ] + world_matrix [ 11 ] ;
float o [ 4 ] ;
2009-07-03 18:33:28 +00:00
o [ 2 ] = t [ 0 ] * proj_matrix [ 8 ] + t [ 1 ] * proj_matrix [ 9 ] + t [ 2 ] * proj_matrix [ 10 ] + proj_matrix [ 11 ] ;
// Depth culling
if ( o [ 2 ] < 0.0 ) {
// No pixels are likely to be drawn - don't update bounding box.
return ;
}
2009-06-28 20:04:07 +00:00
o [ 0 ] = t [ 0 ] * proj_matrix [ 0 ] + t [ 1 ] * proj_matrix [ 1 ] + t [ 2 ] * proj_matrix [ 2 ] + proj_matrix [ 3 ] ;
o [ 1 ] = t [ 0 ] * proj_matrix [ 4 ] + t [ 1 ] * proj_matrix [ 5 ] + t [ 2 ] * proj_matrix [ 6 ] + proj_matrix [ 7 ] ;
o [ 3 ] = t [ 0 ] * proj_matrix [ 12 ] + t [ 1 ] * proj_matrix [ 13 ] + t [ 2 ] * proj_matrix [ 14 ] + proj_matrix [ 15 ] ;
2009-07-03 18:33:28 +00:00
2009-06-28 20:04:07 +00:00
o [ 0 ] / = o [ 3 ] ;
o [ 1 ] / = o [ 3 ] ;
// should possibly adjust for viewport?
o [ 0 ] = ( o [ 0 ] + 1.0f ) * 320.0f ;
o [ 1 ] = ( o [ 1 ] + 1.0f ) * 240.0f ;
2009-10-10 21:19:39 +00:00
if ( o [ 0 ] < PixelEngine : : bbox [ 0 ] ) PixelEngine : : bbox [ 0 ] = ( u16 ) std : : max ( 0.0f , o [ 0 ] ) ;
if ( o [ 0 ] > PixelEngine : : bbox [ 1 ] ) PixelEngine : : bbox [ 1 ] = ( u16 ) std : : min ( 640.0f , o [ 0 ] ) ;
if ( o [ 1 ] < PixelEngine : : bbox [ 2 ] ) PixelEngine : : bbox [ 2 ] = ( u16 ) std : : max ( 0.0f , o [ 1 ] ) ;
if ( o [ 1 ] > PixelEngine : : bbox [ 3 ] ) PixelEngine : : bbox [ 3 ] = ( u16 ) std : : min ( 480.0f , o [ 1 ] ) ;
2009-06-28 20:04:07 +00:00
/*
if ( GetAsyncKeyState ( VK_LSHIFT ) ) {
ERROR_LOG ( VIDEO , " XForm: %f %f %f to %f %f " , p [ 0 ] , p [ 1 ] , p [ 2 ] , o [ 0 ] , o [ 1 ] ) ;
ERROR_LOG ( VIDEO , " %i %i %i %i " , g_VideoInitialize . pBBox [ 0 ] , g_VideoInitialize . pBBox [ 1 ] , g_VideoInitialize . pBBox [ 2 ] , g_VideoInitialize . pBBox [ 3 ] ) ;
} */
}
2008-12-08 05:25:12 +00:00
void LOADERDECL TexMtx_ReadDirect_UByte ( )
{
2009-02-15 12:38:25 +00:00
s_curtexmtx [ s_texmtxread ] = DataReadU8 ( ) & 0x3f ;
2008-12-08 05:25:12 +00:00
PRIM_LOG ( " texmtx%d: %d, " , s_texmtxread , s_curtexmtx [ s_texmtxread ] ) ;
s_texmtxread + + ;
}
void LOADERDECL TexMtx_Write_Float ( )
{
* ( float * ) VertexManager : : s_pCurBufferPointer = ( float ) s_curtexmtx [ s_texmtxwrite + + ] ;
VertexManager : : s_pCurBufferPointer + = 4 ;
}
void LOADERDECL TexMtx_Write_Float2 ( )
{
( ( float * ) VertexManager : : s_pCurBufferPointer ) [ 0 ] = 0 ;
( ( float * ) VertexManager : : s_pCurBufferPointer ) [ 1 ] = ( float ) s_curtexmtx [ s_texmtxwrite + + ] ;
VertexManager : : s_pCurBufferPointer + = 8 ;
}
2010-01-12 00:08:02 +00:00
void LOADERDECL TexMtx_Write_Float4 ( )
2008-12-08 05:25:12 +00:00
{
2010-01-12 00:08:02 +00:00
( ( float * ) VertexManager : : s_pCurBufferPointer ) [ 0 ] = 0 ;
( ( float * ) VertexManager : : s_pCurBufferPointer ) [ 1 ] = 0 ;
( ( float * ) VertexManager : : s_pCurBufferPointer ) [ 2 ] = s_curtexmtx [ s_texmtxwrite + + ] ;
( ( float * ) VertexManager : : s_pCurBufferPointer ) [ 3 ] = 0 ; // Just to fill out with 0.
VertexManager : : s_pCurBufferPointer + = 16 ;
2008-12-08 05:25:12 +00:00
}
VertexLoader : : VertexLoader ( const TVtxDesc & vtx_desc , const VAT & vtx_attr )
{
2008-12-19 21:24:52 +00:00
m_compiledCode = NULL ;
2008-12-08 05:25:12 +00:00
m_numLoadedVertices = 0 ;
m_VertexSize = 0 ;
m_numPipelineStages = 0 ;
2008-12-25 15:56:36 +00:00
m_NativeFmt = NativeVertexFormat : : Create ( ) ;
2008-12-08 05:25:12 +00:00
loop_counter = 0 ;
VertexLoader_Normal : : Init ( ) ;
2010-04-09 15:13:42 +00:00
VertexLoader_Position : : Init ( ) ;
VertexLoader_TextCoord : : Init ( ) ;
2008-12-08 05:25:12 +00:00
m_VtxDesc = vtx_desc ;
SetVAT ( vtx_attr . g0 . Hex , vtx_attr . g1 . Hex , vtx_attr . g2 . Hex ) ;
2008-12-19 21:24:52 +00:00
AllocCodeSpace ( COMPILED_CODE_SIZE ) ;
2008-12-08 05:25:12 +00:00
CompileVertexTranslator ( ) ;
2008-12-19 21:24:52 +00:00
WriteProtect ( ) ;
2008-12-08 05:25:12 +00:00
}
VertexLoader : : ~ VertexLoader ( )
{
2008-12-19 21:24:52 +00:00
FreeCodeSpace ( ) ;
2008-12-08 05:25:12 +00:00
delete m_NativeFmt ;
}
void VertexLoader : : CompileVertexTranslator ( )
{
m_VertexSize = 0 ;
const TVtxAttr & vtx_attr = m_VtxAttr ;
# ifdef USE_JIT
2008-12-19 21:24:52 +00:00
if ( m_compiledCode )
PanicAlert ( " trying to recompile a vtx translator " ) ;
m_compiledCode = GetCodePtr ( ) ;
2008-12-08 05:25:12 +00:00
ABI_EmitPrologue ( 4 ) ;
2008-12-19 21:24:52 +00:00
2008-12-08 05:25:12 +00:00
// Start loop here
const u8 * loop_start = GetCodePtr ( ) ;
// Reset component counters if present in vertex format only.
if ( m_VtxDesc . Tex0Coord | | m_VtxDesc . Tex1Coord | | m_VtxDesc . Tex2Coord | | m_VtxDesc . Tex3Coord | |
m_VtxDesc . Tex4Coord | | m_VtxDesc . Tex5Coord | | m_VtxDesc . Tex6Coord | | m_VtxDesc . Tex7Coord ) {
2009-01-10 23:10:33 +00:00
WriteSetVariable ( 32 , & tcIndex , Imm32 ( 0 ) ) ;
2008-12-08 05:25:12 +00:00
}
if ( m_VtxDesc . Color0 | | m_VtxDesc . Color1 ) {
2009-01-10 23:10:33 +00:00
WriteSetVariable ( 32 , & colIndex , Imm32 ( 0 ) ) ;
2008-12-08 05:25:12 +00:00
}
if ( m_VtxDesc . Tex0MatIdx | | m_VtxDesc . Tex1MatIdx | | m_VtxDesc . Tex2MatIdx | | m_VtxDesc . Tex3MatIdx | |
m_VtxDesc . Tex4MatIdx | | m_VtxDesc . Tex5MatIdx | | m_VtxDesc . Tex6MatIdx | | m_VtxDesc . Tex7MatIdx ) {
2009-01-10 23:10:33 +00:00
WriteSetVariable ( 32 , & s_texmtxwrite , Imm32 ( 0 ) ) ;
WriteSetVariable ( 32 , & s_texmtxread , Imm32 ( 0 ) ) ;
2008-12-08 05:25:12 +00:00
}
# endif
// Colors
const int col [ 2 ] = { m_VtxDesc . Color0 , m_VtxDesc . Color1 } ;
// TextureCoord
// Since m_VtxDesc.Text7Coord is broken across a 32 bit word boundary, retrieve its value manually.
// If we didn't do this, the vertex format would be read as one bit offset from where it should be, making
// 01 become 00, and 10/11 become 01
const int tc [ 8 ] = {
m_VtxDesc . Tex0Coord , m_VtxDesc . Tex1Coord , m_VtxDesc . Tex2Coord , m_VtxDesc . Tex3Coord ,
m_VtxDesc . Tex4Coord , m_VtxDesc . Tex5Coord , m_VtxDesc . Tex6Coord , ( m_VtxDesc . Hex > > 31 ) & 3
} ;
// Reset pipeline
m_numPipelineStages = 0 ;
// It's a bit ugly that we poke inside m_NativeFmt in this function. Planning to fix this.
m_NativeFmt - > m_components = 0 ;
// Position in pc vertex format.
int nat_offset = 0 ;
PortableVertexDeclaration vtx_decl ;
memset ( & vtx_decl , 0 , sizeof ( vtx_decl ) ) ;
for ( int i = 0 ; i < 8 ; i + + ) {
vtx_decl . texcoord_offset [ i ] = - 1 ;
}
// m_VBVertexStride for texmtx and posmtx is computed later when writing.
// Position Matrix Index
if ( m_VtxDesc . PosMatIdx ) {
WriteCall ( PosMtx_ReadDirect_UByte ) ;
m_NativeFmt - > m_components | = VB_HAS_POSMTXIDX ;
m_VertexSize + = 1 ;
}
if ( m_VtxDesc . Tex0MatIdx ) { m_VertexSize + = 1 ; m_NativeFmt - > m_components | = VB_HAS_TEXMTXIDX0 ; WriteCall ( TexMtx_ReadDirect_UByte ) ; }
if ( m_VtxDesc . Tex1MatIdx ) { m_VertexSize + = 1 ; m_NativeFmt - > m_components | = VB_HAS_TEXMTXIDX1 ; WriteCall ( TexMtx_ReadDirect_UByte ) ; }
if ( m_VtxDesc . Tex2MatIdx ) { m_VertexSize + = 1 ; m_NativeFmt - > m_components | = VB_HAS_TEXMTXIDX2 ; WriteCall ( TexMtx_ReadDirect_UByte ) ; }
if ( m_VtxDesc . Tex3MatIdx ) { m_VertexSize + = 1 ; m_NativeFmt - > m_components | = VB_HAS_TEXMTXIDX3 ; WriteCall ( TexMtx_ReadDirect_UByte ) ; }
if ( m_VtxDesc . Tex4MatIdx ) { m_VertexSize + = 1 ; m_NativeFmt - > m_components | = VB_HAS_TEXMTXIDX4 ; WriteCall ( TexMtx_ReadDirect_UByte ) ; }
if ( m_VtxDesc . Tex5MatIdx ) { m_VertexSize + = 1 ; m_NativeFmt - > m_components | = VB_HAS_TEXMTXIDX5 ; WriteCall ( TexMtx_ReadDirect_UByte ) ; }
if ( m_VtxDesc . Tex6MatIdx ) { m_VertexSize + = 1 ; m_NativeFmt - > m_components | = VB_HAS_TEXMTXIDX6 ; WriteCall ( TexMtx_ReadDirect_UByte ) ; }
if ( m_VtxDesc . Tex7MatIdx ) { m_VertexSize + = 1 ; m_NativeFmt - > m_components | = VB_HAS_TEXMTXIDX7 ; WriteCall ( TexMtx_ReadDirect_UByte ) ; }
2010-02-28 08:41:02 +00:00
// Write vertex position loader
_assert_msg_ ( VIDEO , DIRECT < = m_VtxDesc . Position & & m_VtxDesc . Position < = INDEX16 , " Invalid vertex position! \n (m_VtxDesc.Position = %d) " , m_VtxDesc . Position ) ;
_assert_msg_ ( VIDEO , FORMAT_UBYTE < = m_VtxAttr . PosFormat & & m_VtxAttr . PosFormat < = FORMAT_FLOAT , " Invalid vertex position format! \n (m_VtxAttr.PosFormat = %d) " , m_VtxAttr . PosFormat ) ;
_assert_msg_ ( VIDEO , 0 < = m_VtxAttr . PosElements & & m_VtxAttr . PosElements < = 1 , " Invalid number of vertex position elemnts! \n (m_VtxAttr.PosElements = %d) " , m_VtxAttr . PosElements ) ;
2010-04-09 15:13:42 +00:00
WriteCall ( VertexLoader_Position : : GetFunction ( m_VtxDesc . Position , m_VtxAttr . PosFormat , m_VtxAttr . PosElements ) ) ;
m_VertexSize + = VertexLoader_Position : : GetSize ( m_VtxDesc . Position , m_VtxAttr . PosFormat , m_VtxAttr . PosElements ) ;
2010-02-28 08:41:02 +00:00
nat_offset + = 12 ;
2008-12-08 05:25:12 +00:00
2009-06-28 20:04:07 +00:00
// OK, so we just got a point. Let's go back and read it for the bounding box.
# ifdef BBOX_SUPPORT
WriteCall ( UpdateBoundingBox ) ;
# endif
2008-12-08 05:25:12 +00:00
// Normals
vtx_decl . num_normals = 0 ;
if ( m_VtxDesc . Normal ! = NOT_PRESENT ) {
m_VertexSize + = VertexLoader_Normal : : GetSize ( m_VtxDesc . Normal , m_VtxAttr . NormalFormat , m_VtxAttr . NormalElements , m_VtxAttr . NormalIndex3 ) ;
2009-09-13 21:18:04 +00:00
TPipelineFunction pFunc = VertexLoader_Normal : : GetFunction ( m_VtxDesc . Normal , m_VtxAttr . NormalFormat , m_VtxAttr . NormalElements , m_VtxAttr . NormalIndex3 , g_Config . bAllowSignedBytes ) ;
2008-12-08 05:25:12 +00:00
if ( pFunc = = 0 )
{
char temp [ 256 ] ;
sprintf ( temp , " %i %i %i %i " , m_VtxDesc . Normal , m_VtxAttr . NormalFormat , m_VtxAttr . NormalElements , m_VtxAttr . NormalIndex3 ) ;
g_VideoInitialize . pSysMessage ( " VertexLoader_Normal::GetFunction returned zero! " ) ;
}
WriteCall ( pFunc ) ;
vtx_decl . num_normals = vtx_attr . NormalElements ? 3 : 1 ;
2009-03-10 22:51:17 +00:00
vtx_decl . normal_offset [ 0 ] = - 1 ;
vtx_decl . normal_offset [ 1 ] = - 1 ;
vtx_decl . normal_offset [ 2 ] = - 1 ;
2008-12-08 05:25:12 +00:00
switch ( vtx_attr . NormalFormat ) {
case FORMAT_UBYTE :
case FORMAT_BYTE :
2009-09-13 21:18:04 +00:00
{
2008-12-08 05:25:12 +00:00
vtx_decl . normal_gl_type = VAR_BYTE ;
2009-09-13 21:18:04 +00:00
int native_size = 4 ;
if ( vtx_attr . NormalFormat = = FORMAT_BYTE & & ! g_Config . bAllowSignedBytes )
{
vtx_decl . normal_gl_type = VAR_SHORT ;
native_size = 8 ;
}
2008-12-08 05:25:12 +00:00
vtx_decl . normal_gl_size = 4 ;
vtx_decl . normal_offset [ 0 ] = nat_offset ;
2009-09-13 21:18:04 +00:00
nat_offset + = native_size ;
2008-12-08 05:25:12 +00:00
if ( vtx_attr . NormalElements ) {
vtx_decl . normal_offset [ 1 ] = nat_offset ;
2009-09-13 21:18:04 +00:00
nat_offset + = native_size ;
2008-12-08 05:25:12 +00:00
vtx_decl . normal_offset [ 2 ] = nat_offset ;
2009-09-13 21:18:04 +00:00
nat_offset + = native_size ;
2008-12-08 05:25:12 +00:00
}
break ;
2009-09-13 21:18:04 +00:00
}
2008-12-08 05:25:12 +00:00
case FORMAT_USHORT :
case FORMAT_SHORT :
vtx_decl . normal_gl_type = VAR_SHORT ;
vtx_decl . normal_gl_size = 4 ;
vtx_decl . normal_offset [ 0 ] = nat_offset ;
nat_offset + = 8 ;
if ( vtx_attr . NormalElements ) {
vtx_decl . normal_offset [ 1 ] = nat_offset ;
nat_offset + = 8 ;
vtx_decl . normal_offset [ 2 ] = nat_offset ;
nat_offset + = 8 ;
}
break ;
case FORMAT_FLOAT :
vtx_decl . normal_gl_type = VAR_FLOAT ;
vtx_decl . normal_gl_size = 3 ;
vtx_decl . normal_offset [ 0 ] = nat_offset ;
nat_offset + = 12 ;
if ( vtx_attr . NormalElements ) {
vtx_decl . normal_offset [ 1 ] = nat_offset ;
nat_offset + = 12 ;
vtx_decl . normal_offset [ 2 ] = nat_offset ;
nat_offset + = 12 ;
}
break ;
default : _assert_ ( 0 ) ; break ;
}
int numNormals = ( m_VtxAttr . NormalElements = = 1 ) ? NRM_THREE : NRM_ONE ;
m_NativeFmt - > m_components | = VB_HAS_NRM0 ;
if ( numNormals = = NRM_THREE )
m_NativeFmt - > m_components | = VB_HAS_NRM1 | VB_HAS_NRM2 ;
}
vtx_decl . color_gl_type = VAR_UNSIGNED_BYTE ;
2009-03-10 22:51:17 +00:00
vtx_decl . color_offset [ 0 ] = - 1 ;
vtx_decl . color_offset [ 1 ] = - 1 ;
2008-12-08 05:25:12 +00:00
for ( int i = 0 ; i < 2 ; i + + ) {
m_NativeFmt - > m_components | = VB_HAS_COL0 < < i ;
switch ( col [ i ] )
{
case NOT_PRESENT :
m_NativeFmt - > m_components & = ~ ( VB_HAS_COL0 < < i ) ;
vtx_decl . color_offset [ i ] = - 1 ;
break ;
case DIRECT :
switch ( m_VtxAttr . color [ i ] . Comp )
{
case FORMAT_16B_565 : m_VertexSize + = 2 ; WriteCall ( Color_ReadDirect_16b_565 ) ; break ;
case FORMAT_24B_888 : m_VertexSize + = 3 ; WriteCall ( Color_ReadDirect_24b_888 ) ; break ;
case FORMAT_32B_888x : m_VertexSize + = 4 ; WriteCall ( Color_ReadDirect_32b_888x ) ; break ;
case FORMAT_16B_4444 : m_VertexSize + = 2 ; WriteCall ( Color_ReadDirect_16b_4444 ) ; break ;
case FORMAT_24B_6666 : m_VertexSize + = 3 ; WriteCall ( Color_ReadDirect_24b_6666 ) ; break ;
case FORMAT_32B_8888 : m_VertexSize + = 4 ; WriteCall ( Color_ReadDirect_32b_8888 ) ; break ;
default : _assert_ ( 0 ) ; break ;
}
break ;
case INDEX8 :
m_VertexSize + = 1 ;
switch ( m_VtxAttr . color [ i ] . Comp )
{
case FORMAT_16B_565 : WriteCall ( Color_ReadIndex8_16b_565 ) ; break ;
case FORMAT_24B_888 : WriteCall ( Color_ReadIndex8_24b_888 ) ; break ;
case FORMAT_32B_888x : WriteCall ( Color_ReadIndex8_32b_888x ) ; break ;
case FORMAT_16B_4444 : WriteCall ( Color_ReadIndex8_16b_4444 ) ; break ;
case FORMAT_24B_6666 : WriteCall ( Color_ReadIndex8_24b_6666 ) ; break ;
case FORMAT_32B_8888 : WriteCall ( Color_ReadIndex8_32b_8888 ) ; break ;
default : _assert_ ( 0 ) ; break ;
}
break ;
case INDEX16 :
m_VertexSize + = 2 ;
switch ( m_VtxAttr . color [ i ] . Comp )
{
case FORMAT_16B_565 : WriteCall ( Color_ReadIndex16_16b_565 ) ; break ;
case FORMAT_24B_888 : WriteCall ( Color_ReadIndex16_24b_888 ) ; break ;
case FORMAT_32B_888x : WriteCall ( Color_ReadIndex16_32b_888x ) ; break ;
case FORMAT_16B_4444 : WriteCall ( Color_ReadIndex16_16b_4444 ) ; break ;
case FORMAT_24B_6666 : WriteCall ( Color_ReadIndex16_24b_6666 ) ; break ;
case FORMAT_32B_8888 : WriteCall ( Color_ReadIndex16_32b_8888 ) ; break ;
default : _assert_ ( 0 ) ; break ;
}
break ;
}
// Common for the three bottom cases
if ( col [ i ] ! = NOT_PRESENT ) {
vtx_decl . color_offset [ i ] = nat_offset ;
nat_offset + = 4 ;
}
}
// Texture matrix indices (remove if corresponding texture coordinate isn't enabled)
for ( int i = 0 ; i < 8 ; i + + ) {
2009-03-10 22:51:17 +00:00
vtx_decl . texcoord_offset [ i ] = - 1 ;
2010-02-28 11:36:00 +00:00
const int format = m_VtxAttr . texCoord [ i ] . Format ;
const int elements = m_VtxAttr . texCoord [ i ] . Elements ;
if ( tc [ i ] = = NOT_PRESENT ) {
2008-12-08 05:25:12 +00:00
m_NativeFmt - > m_components & = ~ ( VB_HAS_UV0 < < i ) ;
2010-02-28 11:36:00 +00:00
} else {
_assert_msg_ ( VIDEO , DIRECT < = tc [ i ] & & tc [ i ] < = INDEX16 , " Invalid texture coordinates! \n (tc[i] = %d) " , tc [ i ] ) ;
_assert_msg_ ( VIDEO , FORMAT_UBYTE < = format & & format < = FORMAT_FLOAT , " Invalid texture coordinates format! \n (format = %d) " , format ) ;
_assert_msg_ ( VIDEO , 0 < = elements & & elements < = 1 , " Invalid number of texture coordinates elemnts! \n (elements = %d) " , elements ) ;
m_NativeFmt - > m_components | = VB_HAS_UV0 < < i ;
2010-04-09 15:13:42 +00:00
WriteCall ( VertexLoader_TextCoord : : GetFunction ( tc [ i ] , format , elements ) ) ;
m_VertexSize + = VertexLoader_TextCoord : : GetSize ( tc [ i ] , format , elements ) ;
2008-12-08 05:25:12 +00:00
}
if ( m_NativeFmt - > m_components & ( VB_HAS_TEXMTXIDX0 < < i ) ) {
if ( tc [ i ] ! = NOT_PRESENT ) {
// if texmtx is included, texcoord will always be 3 floats, z will be the texmtx index
vtx_decl . texcoord_offset [ i ] = nat_offset ;
vtx_decl . texcoord_gl_type [ i ] = VAR_FLOAT ;
vtx_decl . texcoord_size [ i ] = 3 ;
nat_offset + = 12 ;
WriteCall ( m_VtxAttr . texCoord [ i ] . Elements ? TexMtx_Write_Float : TexMtx_Write_Float2 ) ;
}
else {
m_NativeFmt - > m_components | = VB_HAS_UV0 < < i ; // have to include since using now
vtx_decl . texcoord_offset [ i ] = nat_offset ;
2010-01-12 00:08:02 +00:00
vtx_decl . texcoord_gl_type [ i ] = VAR_FLOAT ;
2008-12-08 05:25:12 +00:00
vtx_decl . texcoord_size [ i ] = 4 ;
2010-01-12 00:08:02 +00:00
nat_offset + = 16 ; // still include the texture coordinate, but this time as 6 + 2 bytes
WriteCall ( TexMtx_Write_Float4 ) ;
2008-12-08 05:25:12 +00:00
}
}
else {
if ( tc [ i ] ! = NOT_PRESENT ) {
vtx_decl . texcoord_offset [ i ] = nat_offset ;
vtx_decl . texcoord_gl_type [ i ] = VAR_FLOAT ;
vtx_decl . texcoord_size [ i ] = vtx_attr . texCoord [ i ] . Elements ? 2 : 1 ;
nat_offset + = 4 * ( vtx_attr . texCoord [ i ] . Elements ? 2 : 1 ) ;
}
}
if ( tc [ i ] = = NOT_PRESENT ) {
// if there's more tex coords later, have to write a dummy call
int j = i + 1 ;
for ( ; j < 8 ; + + j ) {
if ( tc [ j ] ! = NOT_PRESENT ) {
2010-04-09 15:13:42 +00:00
WriteCall ( VertexLoader_TextCoord : : GetDummyFunction ( ) ) ; // important to get indices right!
2008-12-08 05:25:12 +00:00
break ;
}
}
// tricky!
if ( j = = 8 & & ! ( ( m_NativeFmt - > m_components & VB_HAS_TEXMTXIDXALL ) & ( VB_HAS_TEXMTXIDXALL < < ( i + 1 ) ) ) ) {
// no more tex coords and tex matrices, so exit loop
break ;
}
}
}
if ( m_VtxDesc . PosMatIdx ) {
WriteCall ( PosMtx_Write ) ;
vtx_decl . posmtx_offset = nat_offset ;
nat_offset + = 4 ;
} else {
vtx_decl . posmtx_offset = - 1 ;
}
native_stride = nat_offset ;
vtx_decl . stride = native_stride ;
# ifdef USE_JIT
// End loop here
2009-01-10 23:10:33 +00:00
# ifdef _M_X64
MOV ( 64 , R ( RAX ) , Imm64 ( ( u64 ) & loop_counter ) ) ;
SUB ( 32 , MatR ( RAX ) , Imm8 ( 1 ) ) ;
# else
2008-12-08 05:25:12 +00:00
SUB ( 32 , M ( & loop_counter ) , Imm8 ( 1 ) ) ;
2009-01-10 23:10:33 +00:00
# endif
2008-12-08 05:25:12 +00:00
J_CC ( CC_NZ , loop_start , true ) ;
ABI_EmitEpilogue ( 4 ) ;
# endif
m_NativeFmt - > Initialize ( vtx_decl ) ;
}
void VertexLoader : : WriteCall ( TPipelineFunction func )
{
# ifdef USE_JIT
2009-01-10 23:10:33 +00:00
# ifdef _M_X64
MOV ( 64 , R ( RAX ) , Imm64 ( ( u64 ) func ) ) ;
CALLptr ( R ( RAX ) ) ;
# else
2008-12-08 05:25:12 +00:00
CALL ( ( void * ) func ) ;
2009-01-10 23:10:33 +00:00
# endif
2008-12-08 05:25:12 +00:00
# else
m_PipelineStages [ m_numPipelineStages + + ] = func ;
# endif
}
2009-01-10 23:10:33 +00:00
void VertexLoader : : WriteGetVariable ( int bits , OpArg dest , void * address )
{
# ifdef USE_JIT
# ifdef _M_X64
MOV ( 64 , R ( RAX ) , Imm64 ( ( u64 ) address ) ) ;
MOV ( bits , dest , MatR ( RAX ) ) ;
# else
MOV ( bits , dest , M ( address ) ) ;
# endif
# endif
}
void VertexLoader : : WriteSetVariable ( int bits , void * address , OpArg value )
{
# ifdef USE_JIT
# ifdef _M_X64
MOV ( 64 , R ( RAX ) , Imm64 ( ( u64 ) address ) ) ;
MOV ( bits , MatR ( RAX ) , value ) ;
# else
MOV ( bits , M ( address ) , value ) ;
# endif
# endif
}
2008-12-08 05:25:12 +00:00
void VertexLoader : : RunVertices ( int vtx_attr_group , int primitive , int count )
{
DVSTARTPROFILE ( ) ;
m_numLoadedVertices + = count ;
// Flush if our vertex format is different from the currently set.
if ( g_nativeVertexFmt ! = NULL & & g_nativeVertexFmt ! = m_NativeFmt )
{
2009-09-26 21:00:04 +00:00
// We really must flush here. It's possible that the native representations
// of the two vtx formats are the same, but we have no way to easily check that
// now.
VertexManager : : Flush ( ) ;
2008-12-08 05:25:12 +00:00
// Also move the Set() here?
}
g_nativeVertexFmt = m_NativeFmt ;
2009-06-22 09:31:30 +00:00
if ( bpmem . genMode . cullmode = = 3 & & primitive < 5 )
2008-12-08 05:25:12 +00:00
{
// if cull mode is none, ignore triangles and quads
DataSkip ( count * m_VertexSize ) ;
return ;
}
2008-12-26 17:02:46 +00:00
m_NativeFmt - > EnableComponents ( m_NativeFmt - > m_components ) ;
2008-12-08 05:25:12 +00:00
// Load position and texcoord scale factors.
m_VtxAttr . PosFrac = g_VtxAttr [ vtx_attr_group ] . g0 . PosFrac ;
m_VtxAttr . texCoord [ 0 ] . Frac = g_VtxAttr [ vtx_attr_group ] . g0 . Tex0Frac ;
m_VtxAttr . texCoord [ 1 ] . Frac = g_VtxAttr [ vtx_attr_group ] . g1 . Tex1Frac ;
m_VtxAttr . texCoord [ 2 ] . Frac = g_VtxAttr [ vtx_attr_group ] . g1 . Tex2Frac ;
m_VtxAttr . texCoord [ 3 ] . Frac = g_VtxAttr [ vtx_attr_group ] . g1 . Tex3Frac ;
m_VtxAttr . texCoord [ 4 ] . Frac = g_VtxAttr [ vtx_attr_group ] . g2 . Tex4Frac ;
m_VtxAttr . texCoord [ 5 ] . Frac = g_VtxAttr [ vtx_attr_group ] . g2 . Tex5Frac ;
m_VtxAttr . texCoord [ 6 ] . Frac = g_VtxAttr [ vtx_attr_group ] . g2 . Tex6Frac ;
m_VtxAttr . texCoord [ 7 ] . Frac = g_VtxAttr [ vtx_attr_group ] . g2 . Tex7Frac ;
pVtxAttr = & m_VtxAttr ;
2009-07-30 20:29:52 +00:00
posScale = 1.0f / float ( 1 < < m_VtxAttr . PosFrac ) ;
2010-02-24 23:58:48 +00:00
if ( m_NativeFmt - > m_components & VB_HAS_UVALL )
for ( int i = 0 ; i < 8 ; i + + )
tcScale [ i ] = 1.0f / float ( 1 < < m_VtxAttr . texCoord [ i ] . Frac ) ;
2008-12-08 05:25:12 +00:00
for ( int i = 0 ; i < 2 ; i + + )
colElements [ i ] = m_VtxAttr . color [ i ] . Elements ;
// if strips or fans, make sure all vertices can fit in buffer, otherwise flush
int granularity = 1 ;
switch ( primitive ) {
case 3 : // strip .. hm, weird
case 4 : // fan
if ( VertexManager : : GetRemainingSize ( ) < 3 * native_stride )
VertexManager : : Flush ( ) ;
break ;
case 6 : // line strip
if ( VertexManager : : GetRemainingSize ( ) < 2 * native_stride )
VertexManager : : Flush ( ) ;
break ;
case 0 : granularity = 4 ; break ; // quads
case 2 : granularity = 3 ; break ; // tris
case 5 : granularity = 2 ; break ; // lines
}
int startv = 0 , extraverts = 0 ;
int v = 0 ;
while ( v < count )
{
int remainingVerts = VertexManager : : GetRemainingSize ( ) / native_stride ;
if ( remainingVerts < granularity ) {
INCSTAT ( stats . thisFrame . numBufferSplits ) ;
// This buffer full - break current primitive and flush, to switch to the next buffer.
u8 * plastptr = VertexManager : : s_pCurBufferPointer ;
if ( v - startv > 0 )
VertexManager : : AddVertices ( primitive , v - startv + extraverts ) ;
VertexManager : : Flush ( ) ;
// Why does this need to be so complicated?
switch ( primitive ) {
case 3 : // triangle strip, copy last two vertices
// a little trick since we have to keep track of signs
if ( v & 1 ) {
memcpy_gc ( VertexManager : : s_pCurBufferPointer , plastptr - 2 * native_stride , native_stride ) ;
memcpy_gc ( VertexManager : : s_pCurBufferPointer + native_stride , plastptr - native_stride * 2 , 2 * native_stride ) ;
VertexManager : : s_pCurBufferPointer + = native_stride * 3 ;
extraverts = 3 ;
}
else {
memcpy_gc ( VertexManager : : s_pCurBufferPointer , plastptr - native_stride * 2 , native_stride * 2 ) ;
VertexManager : : s_pCurBufferPointer + = native_stride * 2 ;
extraverts = 2 ;
}
break ;
case 4 : // tri fan, copy first and last vert
memcpy_gc ( VertexManager : : s_pCurBufferPointer , plastptr - native_stride * ( v - startv + extraverts ) , native_stride ) ;
VertexManager : : s_pCurBufferPointer + = native_stride ;
memcpy_gc ( VertexManager : : s_pCurBufferPointer , plastptr - native_stride , native_stride ) ;
VertexManager : : s_pCurBufferPointer + = native_stride ;
extraverts = 2 ;
break ;
case 6 : // line strip
memcpy_gc ( VertexManager : : s_pCurBufferPointer , plastptr - native_stride , native_stride ) ;
VertexManager : : s_pCurBufferPointer + = native_stride ;
extraverts = 1 ;
break ;
default :
extraverts = 0 ;
break ;
}
startv = v ;
}
int remainingPrims = remainingVerts / granularity ;
remainingVerts = remainingPrims * granularity ;
if ( count - v < remainingVerts )
remainingVerts = count - v ;
# ifdef USE_JIT
if ( remainingVerts > 0 ) {
loop_counter = remainingVerts ;
( ( void ( * ) ( ) ) ( void * ) m_compiledCode ) ( ) ;
}
# else
for ( int s = 0 ; s < remainingVerts ; s + + )
{
tcIndex = 0 ;
colIndex = 0 ;
s_texmtxwrite = s_texmtxread = 0 ;
for ( int i = 0 ; i < m_numPipelineStages ; i + + )
m_PipelineStages [ i ] ( ) ;
PRIM_LOG ( " \n " ) ;
}
# endif
v + = remainingVerts ;
}
if ( startv < count )
VertexManager : : AddVertices ( primitive , count - startv + extraverts ) ;
}
void VertexLoader : : SetVAT ( u32 _group0 , u32 _group1 , u32 _group2 )
{
VAT vat ;
vat . g0 . Hex = _group0 ;
vat . g1 . Hex = _group1 ;
vat . g2 . Hex = _group2 ;
m_VtxAttr . PosElements = vat . g0 . PosElements ;
m_VtxAttr . PosFormat = vat . g0 . PosFormat ;
m_VtxAttr . PosFrac = vat . g0 . PosFrac ;
m_VtxAttr . NormalElements = vat . g0 . NormalElements ;
m_VtxAttr . NormalFormat = vat . g0 . NormalFormat ;
m_VtxAttr . color [ 0 ] . Elements = vat . g0 . Color0Elements ;
m_VtxAttr . color [ 0 ] . Comp = vat . g0 . Color0Comp ;
m_VtxAttr . color [ 1 ] . Elements = vat . g0 . Color1Elements ;
m_VtxAttr . color [ 1 ] . Comp = vat . g0 . Color1Comp ;
m_VtxAttr . texCoord [ 0 ] . Elements = vat . g0 . Tex0CoordElements ;
m_VtxAttr . texCoord [ 0 ] . Format = vat . g0 . Tex0CoordFormat ;
m_VtxAttr . texCoord [ 0 ] . Frac = vat . g0 . Tex0Frac ;
m_VtxAttr . ByteDequant = vat . g0 . ByteDequant ;
m_VtxAttr . NormalIndex3 = vat . g0 . NormalIndex3 ;
m_VtxAttr . texCoord [ 1 ] . Elements = vat . g1 . Tex1CoordElements ;
m_VtxAttr . texCoord [ 1 ] . Format = vat . g1 . Tex1CoordFormat ;
m_VtxAttr . texCoord [ 1 ] . Frac = vat . g1 . Tex1Frac ;
m_VtxAttr . texCoord [ 2 ] . Elements = vat . g1 . Tex2CoordElements ;
m_VtxAttr . texCoord [ 2 ] . Format = vat . g1 . Tex2CoordFormat ;
m_VtxAttr . texCoord [ 2 ] . Frac = vat . g1 . Tex2Frac ;
m_VtxAttr . texCoord [ 3 ] . Elements = vat . g1 . Tex3CoordElements ;
m_VtxAttr . texCoord [ 3 ] . Format = vat . g1 . Tex3CoordFormat ;
m_VtxAttr . texCoord [ 3 ] . Frac = vat . g1 . Tex3Frac ;
m_VtxAttr . texCoord [ 4 ] . Elements = vat . g1 . Tex4CoordElements ;
m_VtxAttr . texCoord [ 4 ] . Format = vat . g1 . Tex4CoordFormat ;
m_VtxAttr . texCoord [ 4 ] . Frac = vat . g2 . Tex4Frac ;
m_VtxAttr . texCoord [ 5 ] . Elements = vat . g2 . Tex5CoordElements ;
m_VtxAttr . texCoord [ 5 ] . Format = vat . g2 . Tex5CoordFormat ;
m_VtxAttr . texCoord [ 5 ] . Frac = vat . g2 . Tex5Frac ;
m_VtxAttr . texCoord [ 6 ] . Elements = vat . g2 . Tex6CoordElements ;
m_VtxAttr . texCoord [ 6 ] . Format = vat . g2 . Tex6CoordFormat ;
m_VtxAttr . texCoord [ 6 ] . Frac = vat . g2 . Tex6Frac ;
m_VtxAttr . texCoord [ 7 ] . Elements = vat . g2 . Tex7CoordElements ;
m_VtxAttr . texCoord [ 7 ] . Format = vat . g2 . Tex7CoordFormat ;
m_VtxAttr . texCoord [ 7 ] . Frac = vat . g2 . Tex7Frac ;
} ;
2009-02-15 12:38:25 +00:00
void VertexLoader : : AppendToString ( std : : string * dest ) const
2009-02-06 19:52:23 +00:00
{
2009-02-09 20:35:30 +00:00
dest - > reserve ( 250 ) ;
2008-12-08 05:25:12 +00:00
static const char * posMode [ 4 ] = {
2009-02-06 19:52:23 +00:00
" Inv " ,
" Dir " ,
2009-02-09 20:35:30 +00:00
" I8 " ,
2009-02-06 19:52:23 +00:00
" I16 " ,
2008-12-08 05:25:12 +00:00
} ;
static const char * posFormats [ 5 ] = {
2009-02-09 20:35:30 +00:00
" u8 " , " s8 " , " u16 " , " s16 " , " flt " ,
2009-02-06 19:52:23 +00:00
} ;
2009-02-09 20:35:30 +00:00
static const char * colorFormat [ 8 ] = {
" 565 " ,
" 888 " ,
" 888x " ,
" 4444 " ,
" 6666 " ,
" 8888 " ,
" Inv " ,
" Inv " ,
} ;
dest - > append ( StringFromFormat ( " %ib skin: %i P: %i %s-%s " ,
2009-02-06 19:52:23 +00:00
m_VertexSize , m_VtxDesc . PosMatIdx ,
m_VtxAttr . PosElements ? 3 : 2 , posMode [ m_VtxDesc . Position ] , posFormats [ m_VtxAttr . PosFormat ] ) ) ;
2009-02-09 20:35:30 +00:00
if ( m_VtxDesc . Normal ) {
dest - > append ( StringFromFormat ( " Nrm: %i %s-%s " ,
m_VtxAttr . NormalElements , posMode [ m_VtxDesc . Normal ] , posFormats [ m_VtxAttr . NormalFormat ] ) ) ;
}
int color_mode [ 2 ] = { m_VtxDesc . Color0 , m_VtxDesc . Color1 } ;
for ( int i = 0 ; i < 2 ; i + + )
{
if ( color_mode [ i ] )
{
dest - > append ( StringFromFormat ( " C%i: %i %s-%s " , i , m_VtxAttr . color [ i ] . Elements , posMode [ color_mode [ i ] ] , colorFormat [ m_VtxAttr . color [ i ] . Comp ] ) ) ;
}
}
2009-02-06 19:52:23 +00:00
int tex_mode [ 8 ] = {
m_VtxDesc . Tex0Coord , m_VtxDesc . Tex1Coord , m_VtxDesc . Tex2Coord , m_VtxDesc . Tex3Coord ,
m_VtxDesc . Tex4Coord , m_VtxDesc . Tex5Coord , m_VtxDesc . Tex6Coord , m_VtxDesc . Tex7Coord
2008-12-08 05:25:12 +00:00
} ;
2009-02-06 19:52:23 +00:00
for ( int i = 0 ; i < 8 ; i + + )
{
if ( tex_mode [ i ] )
{
2009-02-09 20:35:30 +00:00
dest - > append ( StringFromFormat ( " T%i: %i %s-%s " ,
2009-02-06 19:52:23 +00:00
i , m_VtxAttr . texCoord [ i ] . Elements , posMode [ tex_mode [ i ] ] , posFormats [ m_VtxAttr . texCoord [ i ] . Format ] ) ) ;
}
}
dest - > append ( StringFromFormat ( " - %i v \n " , m_numLoadedVertices ) ) ;
2008-12-08 05:25:12 +00:00
}