/*---------------------------------------------------------------------------* Project: Horizon File: gr_Vertex.cpp Copyright (C)2010 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 38755 $ *---------------------------------------------------------------------------*/ #include namespace nn { namespace gr { namespace CTR { const uptr scBaseAddr = nngxGetPhysicalAddr( nngxGetVramStartAddr( nn::gx::MEM_VRAMA ) ) >> 3; //------------------------------------------------------------------------ bit32* Vertex::MakeDrawCommand( bit32* command, const IndexStream& index_stream ) const { bit32 fmt = index_stream.isUnsignedByte ? 0x00000000 : 0x80000000; uptr addr = index_stream.physicalAddr - scBaseAddr * 8; // Resets vertex information. *command++ = 0x1; // 0x25F *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_START_DRAW_FUNC1 ); // offset *command++ = fmt | addr; // 0x227 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_INDEX_ARRAY_ADDR_OFFSET ); // Number of vertices to render *command++ = index_stream.drawVtxNum; // 0x228 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_DRAW_VERTEX_NUM ); *command++ = 0x00000000; // 0x245 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_START_DRAW_FUNC0, 0x1 ); // Rendering kick *command++ = 0x00000001; // 0x22f *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_START_DRAW_ELEMENT ); *command++ = 0x00000001; // 0x245 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_START_DRAW_FUNC0, 0x1 ); // Flush vertex cache *command++ = 0x00000001; // 0x231 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VERTEX_FUNC ); // Send dummy command twice for ( u32 index = 0; index < 2; index++ ) { *command++ = 0x0; // 0x25E *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE2, 0x8 ); } return command; } //------------------------------------------------------------------------ void Vertex::EnableAttrAsArray( const BindSymbolVSInput& symbol, const uptr physical_addr, const PicaDataVertexAttrType type ) { const bit32 bind_reg = symbol.start; const u32 byte = PicaDataVertexAttrTypeToByteSize( type ); NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); // Disabled because there is a chance it is set somewhere else DisableAttr_( bind_reg ); // Search for empty stream LoadArray* array = NULL; for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) { if ( m_LoadArray[ i ].IsEnable() == false ) { array = &m_LoadArray[ i ]; break; } } NN_GR_ASSERT( array != NULL ); m_IsEnableReg[ bind_reg ] = true; array->physicalAddr = physical_addr; array->type[ 0 ] = type; array->bind[ 0 ] = bind_reg; array->byte[ 0 ] = byte; for ( int i = 1; i < VERTEX_ATTRIBUTE_MAX; ++i ) { array->bind[ i ] = -1; array->byte[ i ] = 0; } // Disable cache m_CmdCacheVertexNum = 0; } //------------------------------------------------------------------------ void Vertex::EnableAttrAsConst( const BindSymbolVSInput& symbol, const u8 dimension, const f32 param[] ) { const bit32 bind_reg = symbol.start; NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); // Disabled because there is a chance it is set somewhere else DisableAttr_( bind_reg ); m_IsEnableReg[ bind_reg ] = true; m_AttrConst[ bind_reg ].dimension = dimension; f32 defaultParam[ 4 ] = { 0.f, 0.f, 0.f, 1.f }; for ( int i = 0; i < 4; ++i ) { m_AttrConst[ bind_reg ].param[ i ] = i < dimension ? param[ i ] : defaultParam[ i ]; } // Disable cache m_CmdCacheVertexNum = 0; } //------------------------------------------------------------------------ void Vertex::EnableInterleavedArray( const nn::gr::CTR::Vertex::InterleaveInfo& interleave_info, const uptr physical_addr ) { // Search for empty stream LoadArray* array = NULL; for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) { if ( m_LoadArray[ i ].IsEnable() == false ) { array = &m_LoadArray[ i ]; break; } } NN_GR_ASSERT( array != NULL ); for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) { if ( interleave_info.symbol[ i ] == NULL ) { array->bind[ i ] = -1; } else { array->bind[ i ] = interleave_info.symbol[ i ]->start; array->physicalAddr = physical_addr; } array->type[ i ] = interleave_info.dataType[ i ]; array->byte[ i ] = i < interleave_info.dataNum ? PicaDataVertexAttrTypeToByteSize( array->type[ i ] ) : 0; } // Disable cache m_CmdCacheVertexNum = 0; } //------------------------------------------------------------------------ void Vertex::DisableAttr_( const bit32 bind_reg ) { NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); // Do nothing if already disabled if ( !m_IsEnableReg[ bind_reg ] ) return; // Disable cache m_CmdCacheVertexNum = 0; if ( m_AttrConst[ bind_reg ].IsEnable() ) { // Disable fixed vertex attributes m_AttrConst[ bind_reg ].Disable(); m_IsEnableReg[ bind_reg ] = false; return; } // Disable while searching in load arrays for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) { if ( ! m_LoadArray[ i ].IsEnable() ) continue; for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j ) { if ( m_LoadArray[ i ].bind[ j ] != bind_reg ) continue; m_LoadArray[ i ].bind[ j ] = -1; m_IsEnableReg[ bind_reg ] = false; // When disabled, checks whether the load array can be disabled m_LoadArray[ i ].CheckDisable(); return; } } NN_GR_ASSERT( m_IsEnableReg[ bind_reg ] == false ); } //------------------------------------------------------------------------ void Vertex::LoadArray::CheckDisable() { // Does nothing specific if disabled if ( !IsEnable() ) { return; } // If enabled, disables if all contents is disabled for ( u32 index = 0; index < VERTEX_ATTRIBUTE_MAX; ++index ) { if ( bind[ index ] != -1 ) { return; } } physicalAddr = NULL; for ( u32 index = 0; index < VERTEX_ATTRIBUTE_MAX; ++index ) { byte[ index ] = 0; } } //------------------------------------------------------------------------ void Vertex::LoadArray::DisableAll() { physicalAddr = NULL; for ( u32 index = 0; index < VERTEX_ATTRIBUTE_MAX; index++ ) { // Initializes at 0x0 type[ index ] = PICA_DATA_SIZE_1_BYTE; byte[ index ] = 0; bind[ index ] = -1; } } //------------------------------------------------------------------------ bit32* Vertex::MakeEnableAttrCommand_( bit32* command ) const { // #define NN_GR_VERTEX_DUMP #if defined( NN_GR_VERTEX_DUMP ) // For debugging bit32 * start = command; #endif // Sets the vertex shader input register number later bit32* reg0x2b9 = command++; // = vtx_attr_num | 0xa0000000; *command++ = 0x000b02b9; bit32* reg0x242 = command++; // = vtx_attr_num; *command++ = 0x00010242; // Sets bind_reg_map bit32* bind_reg_command = command; // 0x2bb *command++ = 0; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP0 ); // 0x2bc *command++ = 0; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP1 ); // 0x201 bit32* type = &command[ 2 ]; // 0x202[27:16] bit32& fixed_attr_mask = command[ 3 ]; // 0x200 *command++ = scBaseAddr; bit32* headerBaseAddr = command++; // = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * m_AttrArrayNum ); // 0x201 *command++ = 0; // 0x202 bit32* reg0x202 = command++; // vtx_attr_num << 28; int input_index = 0; int array_num = 0; for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) { const LoadArray& vtx_array = m_LoadArray[ i ]; if ( !vtx_array.IsEnable() ) continue; ++array_num; int total_byte = 0; int elem_num = 0; int elem[ 2 ] = { 0, 0 }; for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j ) { if ( vtx_array.byte[ j ] == 0 ) break; total_byte += vtx_array.byte[ j ]; // If bound if ( vtx_array.bind[ j ] >= 0 ) { // 0x204 + ( 3 * N ) or 0x205 + ( 3 * N ) elem[ j / 8 ] |= input_index << ( 4 * ( j % 8 ) ); // 0x201 or 0x202 type[ input_index / 8 ] |= vtx_array.type[ j ] << ( 4 * ( input_index % 8 ) ); // Set the index of the input register to 0x2bb or 0x2bc bind_reg_command[ ( input_index >> 3 ) << 1 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) ); bind_reg_command[ ( input_index >> 3 ) << 1 ] |= vtx_array.bind[ j ] << ( 4 * ( input_index % 8 ) ); ++input_index; #if defined( NN_GR_VERTEX_DUMP ) // For debugging NN_LOG( "+ 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ], elem[0], elem[1] ); #endif } // If Padding is used else { // 0x204 + ( 3 * N ) or 0x205 + ( 3 * N ) elem[ j / 8 ] |= ( ( vtx_array.byte[ j ] >> 2 ) + 0xb ) << ( 4 * ( j % 8 ) ); #if defined( NN_GR_VERTEX_DUMP ) // For debugging NN_LOG( "- 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ] >> 2, elem[0], elem[1] ); #endif } ++elem_num; } // 0x203 + ( 3 * N ) *command++ = vtx_array.physicalAddr - scBaseAddr * 8; // 0x204 + ( 3 * N ) *command++ = elem[ 0 ]; // 0x205 + ( 3 * N ) *command++ = elem[ 1 ] | total_byte << 16 | elem_num << 28; } // 0x200 *headerBaseAddr = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * array_num ); if ( array_num % 2 ) *command++ = 0; // Fixed vertex setup for ( int bind_reg = VERTEX_ATTRIBUTE_MAX-1; bind_reg >= 0; --bind_reg ) { const AttrConst& vtxConst = m_AttrConst[ bind_reg ]; if ( !vtxConst.IsEnable() ) continue; // Index that inputs to vertex shader *command++ = input_index; // 0x232 *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FIXED_ATTR , 4 ); // 3 fixed vertex attributes converted to 24-bit values, 0x233, 0x234, 0x235 *command++ = ( ( Float32ToFloat24( vtxConst.param[3] ) << 8 ) & 0xffffff00 ) | ( ( Float32ToFloat24( vtxConst.param[2] ) >> 16 ) & 0x000000ff ); *command++ = ( ( Float32ToFloat24( vtxConst.param[2] ) << 16 ) & 0xffff0000 ) | ( ( Float32ToFloat24( vtxConst.param[1] ) >> 8 ) & 0x0000ffff ); *command++ = ( ( Float32ToFloat24( vtxConst.param[1] ) << 24 ) & 0xff000000 ) | ( ( Float32ToFloat24( vtxConst.param[0] ) >> 0 ) & 0x00ffffff ); *command++ = 0; // Padding // Set the index of the input register to 0x2bb or 0x2bc bind_reg_command[ ( input_index / 8 ) * 2 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) ); bind_reg_command[ ( input_index / 8 ) * 2 ] |= bind_reg << ( 4 * ( input_index % 8 ) ); // 0x202[27:16] Fixed vertex attribute mask fixed_attr_mask |= ( 1 << input_index + 16 ); ++input_index; } // Set the number of input vertex attributes // 0x2b9 *reg0x2b9 = (input_index - 1) | 0xa0000000; // 0x242 *reg0x242 = input_index - 1; // 0x202 *reg0x202 |= (input_index - 1) << 28; #if defined( NN_GR_VERTEX_DUMP ) // For debugging static int a = 0; if ( ++a == 1 ) { for ( bit32* i = start; i != command; i +=2 ) { NN_LOG( "0x%08x 0x%08x\n", *i, *(i+1) ); } } #endif return command; } } // namespace CTR } // namespace gr } // namespace nn