1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: gr_Vertex.cpp 4 5 Copyright (C)2010 Nintendo Co., Ltd. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Rev: 26237 $ 14 *---------------------------------------------------------------------------*/ 15 16 #include <nn/gr/CTR/gr_Vertex.h> 17 18 namespace nn 19 { 20 namespace gr 21 { 22 namespace CTR 23 { 24 25 const u32 scBaseAddr = nngxGetPhysicalAddr( nngxGetVramStartAddr( nn::gx::MEM_VRAMA ) ) >> 3; 26 27 //------------------------------------------------------------------------ 28 MakeDrawCommand(u32 * command,const IndexStream & index_stream) const29 u32* Vertex::MakeDrawCommand( u32* command, const IndexStream& index_stream ) const 30 { 31 u32 fmt = index_stream.isUnsignedByte ? 0x00000000 : 0x80000000; 32 33 u32 addr = index_stream.physicalAddr - scBaseAddr * 8; 34 35 // offset 36 *command++ = fmt | addr; 37 // 0x227 38 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_INDEX_ARRAY_ADDR_OFFSET ); 39 40 // 描画頂点数 41 *command++ = index_stream.drawVtxNum; 42 // 0x228 43 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_DRAW_VERTEX_NUM ); 44 45 // ジオメトリシェーダー関連の設定 on 46 *command++ = 0x00000000; 47 // 0x245 48 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_START_DRAW_FUNC0, 0x1 ); 49 50 // 描画キック 51 *command++ = 0x00000001; 52 // 0x22f 53 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_START_DRAW_ELEMENT ); 54 55 // ジオメトリシェーダー関連の設定 off 56 *command++ = 0x00000001; 57 // 0x245 58 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_START_DRAW_FUNC0 ); 59 60 // 頂点キャッシュのフラッシュ 61 *command++ = 0x00000001; 62 // 0x231 63 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VERTEX_FUNC ); 64 65 return command; 66 } 67 68 //------------------------------------------------------------------------ 69 EnableAttrAsArray(const BindSymbolVSInput & symbol,const u32 physical_addr,const PicaDataVertexAttrType type)70 void Vertex::EnableAttrAsArray( const BindSymbolVSInput& symbol, 71 const u32 physical_addr, 72 const PicaDataVertexAttrType type ) 73 { 74 const u32 bind_reg = symbol.start; 75 const u32 byte = PicaDataVertexAttrTypeToByteSize( type ); 76 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); 77 78 // ほかで設定されている可能性があるので無効化しておく 79 DisableAttr_( bind_reg ); 80 81 // 空いているストリームを探す 82 LoadArray* array = NULL; 83 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 84 { 85 if ( m_LoadArray[ i ].IsEnable() == false ) 86 { 87 array = &m_LoadArray[ i ]; 88 break; 89 } 90 } 91 NN_GR_ASSERT( array != NULL ); 92 93 array->physicalAddr = physical_addr; 94 array->type[ 0 ] = type; 95 array->bind[ 0 ] = bind_reg; 96 array->byte[ 0 ] = byte; 97 98 for ( int i = 1; i < VERTEX_ATTRIBUTE_MAX; ++i ) 99 { 100 array->bind[ i ] = -1; 101 array->byte[ i ] = 0; 102 } 103 104 // キャッシュの無効化 105 m_CmdCacheVertexNum = 0; 106 } 107 108 //------------------------------------------------------------------------ 109 EnableAttrAsConst(const BindSymbolVSInput & symbol,const u8 dimension,const f32 param[])110 void Vertex::EnableAttrAsConst( const BindSymbolVSInput& symbol, 111 const u8 dimension, 112 const f32 param[] ) 113 { 114 const u32 bind_reg = symbol.start; 115 116 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); 117 118 // ほかで設定されている可能性があるので無効化しておく 119 DisableAttr_( bind_reg ); 120 121 m_IsEnableReg[ bind_reg ] = true; 122 m_AttrConst[ bind_reg ].dimension = dimension; 123 124 f32 defaultParam[ 4 ] = { 0.f, 0.f, 0.f, 1.f }; 125 for ( int i = 0; i < 4; ++i ) 126 { 127 m_AttrConst[ bind_reg ].param[ i ] = i < dimension ? param[ i ] : defaultParam[ i ]; 128 } 129 130 // キャッシュの無効化 131 m_CmdCacheVertexNum = 0; 132 } 133 134 //------------------------------------------------------------------------ 135 EnableInterleavedArray(const nn::gr::CTR::Vertex::InterleaveInfo & interleave_info,const u32 physical_addr)136 void Vertex::EnableInterleavedArray( const nn::gr::CTR::Vertex::InterleaveInfo& interleave_info, const u32 physical_addr ) 137 { 138 // 空いているストリームを探す 139 LoadArray* array = NULL; 140 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 141 { 142 if ( m_LoadArray[ i ].IsEnable() == false ) 143 { 144 array = &m_LoadArray[ i ]; 145 break; 146 } 147 } 148 NN_GR_ASSERT( array != NULL ); 149 150 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 151 { 152 if ( interleave_info.symbol[ i ] == NULL ) 153 { 154 array->bind[ i ] = -1; 155 } 156 else 157 { 158 array->bind[ i ] = interleave_info.symbol[ i ]->start; 159 array->physicalAddr = physical_addr; 160 } 161 162 array->type[ i ] = interleave_info.dataType[ i ]; 163 164 array->byte[ i ] = i < interleave_info.dataNum ? PicaDataVertexAttrTypeToByteSize( array->type[ i ] ) : 0; 165 } 166 167 // キャッシュの無効化 168 m_CmdCacheVertexNum = 0; 169 } 170 171 //------------------------------------------------------------------------ 172 DisableAttr_(const u32 bind_reg)173 void Vertex::DisableAttr_( const u32 bind_reg ) 174 { 175 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); 176 177 // すでに無効化されていたら何もしない 178 if ( !m_IsEnableReg[ bind_reg ] ) return; 179 180 // キャッシュの無効化 181 m_CmdCacheVertexNum = 0; 182 183 if ( m_AttrConst[ bind_reg ].IsEnable() ) 184 { 185 // 固定頂点属性の無効化 186 m_AttrConst[ bind_reg ].Disable(); 187 188 m_IsEnableReg[ bind_reg ] = false; 189 return; 190 } 191 192 193 // ロードアレイの中を探しながら無効化 194 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 195 { 196 if ( ! m_LoadArray[ i ].IsEnable() ) continue; 197 198 for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j ) 199 { 200 if ( m_LoadArray[ i ].bind[ j ] != bind_reg ) continue; 201 202 m_LoadArray[ i ].bind[ j ] = -1; 203 m_IsEnableReg[ bind_reg ] = false; 204 205 // 無効化できた場合、ロードアレイ自体が無効化できないか調べる 206 m_LoadArray[ i ].CheckDisable(); 207 208 return; 209 } 210 } 211 212 NN_GR_ASSERT( m_IsEnableReg[ bind_reg ] == false ); 213 } 214 215 //------------------------------------------------------------------------ 216 CheckDisable()217 void Vertex::LoadArray::CheckDisable() 218 { 219 // 無効化されているなら、特に何もしない 220 if ( !IsEnable() ) return; 221 222 // 有効化されている場合、中身がすべて無効なら無効化する 223 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 224 { 225 if ( bind[ i ] != -1 ) return; 226 } 227 228 physicalAddr = 0; 229 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 230 { 231 byte[ i ] = 0; 232 } 233 } 234 235 //------------------------------------------------------------------------ 236 MakeEnableAttrCommand_(u32 * command) const237 u32* Vertex::MakeEnableAttrCommand_( u32* command ) const 238 { 239 // #define NN_GR_VERTEX_DUMP 240 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 241 u32 * start = command; 242 #endif 243 244 // 頂点シェーダーの入力レジスタ数を設定 245 u32* reg0x2b9 = command++;// = vtx_attr_num | 0xa0000000; 246 *command++ = 0x000b02b9; 247 u32* reg0x242 = command++;// = vtx_attr_num; 248 *command++ = 0x00010242; 249 250 // bind_reg_mapの設定 251 u32* bind_reg_command = command; 252 *command++ = 0; 253 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP0 ); 254 *command++ = 0; 255 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP1 ); 256 257 // 頂点属性の設定ヘッダー部分 258 u32* type = &command[ 2 ]; 259 u32& fixed_attr_mask = command[ 3 ]; 260 *command++ = scBaseAddr; 261 u32* headerBaseAddr = command++; // = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * m_AttrArrayNum ); 262 *command++ = 0; 263 u32* reg0x202 = command++; // vtx_attr_num << 28; 264 265 int input_index = 0; 266 int array_num = 0; 267 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 268 { 269 const LoadArray& vtx_array = m_LoadArray[ i ]; 270 271 if ( !vtx_array.IsEnable() ) continue; 272 273 ++array_num; 274 int total_byte = 0; 275 int elem_num = 0; 276 int elem[ 2 ] = { 0, 0 }; 277 for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j ) 278 { 279 if ( vtx_array.byte[ j ] == 0 ) break; 280 total_byte += vtx_array.byte[ j ]; 281 282 if ( vtx_array.bind[ j ] >= 0 ) 283 { 284 elem[ j / 8 ] |= input_index << ( 4 * ( j % 8 ) ); 285 type[ input_index / 8 ] |= vtx_array.type[ j ] << ( 4 * ( input_index % 8 ) ); 286 bind_reg_command[ ( input_index >> 3 ) << 1 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) ); 287 bind_reg_command[ ( input_index >> 3 ) << 1 ] |= vtx_array.bind[ j ] << ( 4 * ( input_index % 8 ) ); 288 ++input_index; 289 ++elem_num; 290 291 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 292 NN_LOG( "+ 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ], elem[0], elem[1] ); 293 #endif 294 } 295 else 296 { 297 elem[ j / 8 ] |= ( ( vtx_array.byte[ j ] >> 2 ) + 0xb ) << ( 4 * ( j % 8 ) ); 298 299 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 300 NN_LOG( "- 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ] >> 2, elem[0], elem[1] ); 301 #endif 302 } 303 } 304 *command++ = vtx_array.physicalAddr - scBaseAddr * 8; 305 *command++ = elem[ 0 ]; 306 *command++ = elem[ 1 ] | total_byte << 16 | elem_num << 28; 307 } 308 *headerBaseAddr = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * array_num ); 309 if ( array_num % 2 ) *command++ = 0; 310 311 // 固定頂点のセットアップ 312 for ( int bind_reg = VERTEX_ATTRIBUTE_MAX-1; bind_reg >= 0; --bind_reg ) 313 { 314 const AttrConst& vtxConst = m_AttrConst[ bind_reg ]; 315 316 if ( !vtxConst.IsEnable() ) continue; 317 *command++ = input_index; 318 // 0x232 319 *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FIXED_ATTR , 4 ); 320 *command++ = ( ( Float32ToFloat24( vtxConst.param[3] ) << 8 ) & 0xffffff00 ) | ( ( Float32ToFloat24( vtxConst.param[2] ) >> 16 ) & 0x000000ff ); 321 *command++ = ( ( Float32ToFloat24( vtxConst.param[2] ) << 16 ) & 0xffff0000 ) | ( ( Float32ToFloat24( vtxConst.param[1] ) >> 8 ) & 0x0000ffff ); 322 *command++ = ( ( Float32ToFloat24( vtxConst.param[1] ) << 24 ) & 0xff000000 ) | ( ( Float32ToFloat24( vtxConst.param[0] ) >> 0 ) & 0x00ffffff ); 323 *command++ = 0; // padding 324 325 bind_reg_command[ ( input_index / 8 ) * 2 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) ); 326 bind_reg_command[ ( input_index / 8 ) * 2 ] |= bind_reg << ( 4 * ( input_index % 8 ) ); 327 328 fixed_attr_mask |= ( 1 << input_index + 16 ); 329 ++input_index; 330 } 331 // 0x2b9 332 *reg0x2b9 = (input_index - 1) | 0xa0000000; 333 // 0x242 334 *reg0x242 = input_index - 1; 335 // 0x202 336 *reg0x202 |= (input_index - 1) << 28; 337 338 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 339 static int a = 0; 340 if ( ++a == 1 ) 341 { 342 for ( u32* i = start; i != command; i +=2 ) 343 { 344 NN_LOG( "0x%08x 0x%08x\n", *i, *(i+1) ); 345 } 346 } 347 #endif 348 349 return command; 350 } 351 352 } // namespace CTR 353 } // namespace gr 354 } // namespace nn 355