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: 37389 $ 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 uptr scBaseAddr = nngxGetPhysicalAddr( nngxGetVramStartAddr( nn::gx::MEM_VRAMA ) ) >> 3; 26 27 //------------------------------------------------------------------------ 28 MakeDrawCommand(bit32 * command,const IndexStream & index_stream) const29 bit32* Vertex::MakeDrawCommand( bit32* command, const IndexStream& index_stream ) const 30 { 31 bit32 fmt = index_stream.isUnsignedByte ? 0x00000000 : 0x80000000; 32 uptr addr = index_stream.physicalAddr - scBaseAddr * 8; 33 34 // 頂点情報をリセットします 35 *command++ = 0x1; 36 // 0x25F 37 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_START_DRAW_FUNC1 ); 38 39 // offset 40 *command++ = fmt | addr; 41 // 0x227 42 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_INDEX_ARRAY_ADDR_OFFSET ); 43 44 // 描画頂点数 45 *command++ = index_stream.drawVtxNum; 46 // 0x228 47 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_DRAW_VERTEX_NUM ); 48 *command++ = 0x00000000; 49 // 0x245 50 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_START_DRAW_FUNC0, 0x1 ); 51 52 // 描画キック 53 *command++ = 0x00000001; 54 // 0x22f 55 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_START_DRAW_ELEMENT ); 56 57 *command++ = 0x00000001; 58 // 0x245 59 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_START_DRAW_FUNC0 ); 60 61 // 頂点キャッシュのフラッシュ 62 *command++ = 0x00000001; 63 // 0x231 64 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VERTEX_FUNC ); 65 66 // ダミーコマンド を 2回送ります 67 for ( u32 index = 0; index < 2; index++ ) 68 { 69 *command++ = 0x0; 70 // 0x25E 71 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE2, 0x8 ); 72 } 73 74 return command; 75 } 76 77 //------------------------------------------------------------------------ 78 EnableAttrAsArray(const BindSymbolVSInput & symbol,const uptr physical_addr,const PicaDataVertexAttrType type)79 void Vertex::EnableAttrAsArray( const BindSymbolVSInput& symbol, 80 const uptr physical_addr, 81 const PicaDataVertexAttrType type ) 82 { 83 const bit32 bind_reg = symbol.start; 84 const u32 byte = PicaDataVertexAttrTypeToByteSize( type ); 85 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); 86 87 // ほかで設定されている可能性があるので無効化しておく 88 DisableAttr_( bind_reg ); 89 90 // 空いているストリームを探す 91 LoadArray* array = NULL; 92 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 93 { 94 if ( m_LoadArray[ i ].IsEnable() == false ) 95 { 96 array = &m_LoadArray[ i ]; 97 break; 98 } 99 } 100 NN_GR_ASSERT( array != NULL ); 101 102 m_IsEnableReg[ bind_reg ] = true; 103 array->physicalAddr = physical_addr; 104 array->type[ 0 ] = type; 105 array->bind[ 0 ] = bind_reg; 106 array->byte[ 0 ] = byte; 107 108 for ( int i = 1; i < VERTEX_ATTRIBUTE_MAX; ++i ) 109 { 110 array->bind[ i ] = -1; 111 array->byte[ i ] = 0; 112 } 113 114 // キャッシュの無効化 115 m_CmdCacheVertexNum = 0; 116 } 117 118 //------------------------------------------------------------------------ 119 EnableAttrAsConst(const BindSymbolVSInput & symbol,const u8 dimension,const f32 param[])120 void Vertex::EnableAttrAsConst( const BindSymbolVSInput& symbol, 121 const u8 dimension, 122 const f32 param[] ) 123 { 124 const bit32 bind_reg = symbol.start; 125 126 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); 127 128 // ほかで設定されている可能性があるので無効化しておく 129 DisableAttr_( bind_reg ); 130 131 m_IsEnableReg[ bind_reg ] = true; 132 m_AttrConst[ bind_reg ].dimension = dimension; 133 134 f32 defaultParam[ 4 ] = { 0.f, 0.f, 0.f, 1.f }; 135 for ( int i = 0; i < 4; ++i ) 136 { 137 m_AttrConst[ bind_reg ].param[ i ] = i < dimension ? param[ i ] : defaultParam[ i ]; 138 } 139 140 // キャッシュの無効化 141 m_CmdCacheVertexNum = 0; 142 } 143 144 //------------------------------------------------------------------------ 145 EnableInterleavedArray(const nn::gr::CTR::Vertex::InterleaveInfo & interleave_info,const uptr physical_addr)146 void Vertex::EnableInterleavedArray( const nn::gr::CTR::Vertex::InterleaveInfo& interleave_info, const uptr physical_addr ) 147 { 148 // 空いているストリームを探す 149 LoadArray* array = NULL; 150 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 151 { 152 if ( m_LoadArray[ i ].IsEnable() == false ) 153 { 154 array = &m_LoadArray[ i ]; 155 break; 156 } 157 } 158 NN_GR_ASSERT( array != NULL ); 159 160 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 161 { 162 if ( interleave_info.symbol[ i ] == NULL ) 163 { 164 array->bind[ i ] = -1; 165 } 166 else 167 { 168 array->bind[ i ] = interleave_info.symbol[ i ]->start; 169 array->physicalAddr = physical_addr; 170 } 171 172 array->type[ i ] = interleave_info.dataType[ i ]; 173 174 array->byte[ i ] = i < interleave_info.dataNum ? PicaDataVertexAttrTypeToByteSize( array->type[ i ] ) : 0; 175 } 176 177 // キャッシュの無効化 178 m_CmdCacheVertexNum = 0; 179 } 180 181 //------------------------------------------------------------------------ 182 DisableAttr_(const bit32 bind_reg)183 void Vertex::DisableAttr_( const bit32 bind_reg ) 184 { 185 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); 186 187 // すでに無効化されていたら何もしない 188 if ( !m_IsEnableReg[ bind_reg ] ) return; 189 190 // キャッシュの無効化 191 m_CmdCacheVertexNum = 0; 192 193 if ( m_AttrConst[ bind_reg ].IsEnable() ) 194 { 195 // 固定頂点属性の無効化 196 m_AttrConst[ bind_reg ].Disable(); 197 198 m_IsEnableReg[ bind_reg ] = false; 199 return; 200 } 201 202 203 // ロードアレイの中を探しながら無効化 204 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 205 { 206 if ( ! m_LoadArray[ i ].IsEnable() ) continue; 207 208 for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j ) 209 { 210 if ( m_LoadArray[ i ].bind[ j ] != bind_reg ) continue; 211 212 m_LoadArray[ i ].bind[ j ] = -1; 213 m_IsEnableReg[ bind_reg ] = false; 214 215 // 無効化できた場合、ロードアレイ自体が無効化できないか調べる 216 m_LoadArray[ i ].CheckDisable(); 217 218 return; 219 } 220 } 221 222 NN_GR_ASSERT( m_IsEnableReg[ bind_reg ] == false ); 223 } 224 225 //------------------------------------------------------------------------ 226 CheckDisable()227 void Vertex::LoadArray::CheckDisable() 228 { 229 // 無効化されているなら、特に何もしない 230 if ( !IsEnable() ) return; 231 232 // 有効化されている場合、中身がすべて無効なら無効化する 233 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 234 { 235 if ( bind[ i ] != -1 ) return; 236 } 237 238 physicalAddr = 0; 239 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 240 { 241 byte[ i ] = 0; 242 } 243 } 244 245 //------------------------------------------------------------------------ 246 MakeEnableAttrCommand_(bit32 * command) const247 bit32* Vertex::MakeEnableAttrCommand_( bit32* command ) const 248 { 249 // #define NN_GR_VERTEX_DUMP 250 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 251 bit32 * start = command; 252 #endif 253 254 // 頂点シェーダーの入力レジスタ数を後で設定 255 bit32* reg0x2b9 = command++; // = vtx_attr_num | 0xa0000000; 256 *command++ = 0x000b02b9; 257 258 bit32* reg0x242 = command++; // = vtx_attr_num; 259 *command++ = 0x00010242; 260 261 // bind_reg_mapの設定 262 bit32* bind_reg_command = command; 263 264 // 0x2bb 265 *command++ = 0; 266 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP0 ); 267 268 // 0x2bc 269 *command++ = 0; 270 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP1 ); 271 272 // 0x201 273 bit32* type = &command[ 2 ]; 274 275 // 0x202[27:16] 276 bit32& fixed_attr_mask = command[ 3 ]; 277 278 // 0x200 279 *command++ = scBaseAddr; 280 bit32* headerBaseAddr = command++; // = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * m_AttrArrayNum ); 281 282 // 0x201 283 *command++ = 0; 284 285 // 0x202 286 bit32* reg0x202 = command++; // vtx_attr_num << 28; 287 288 int input_index = 0; 289 int array_num = 0; 290 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 291 { 292 const LoadArray& vtx_array = m_LoadArray[ i ]; 293 294 if ( !vtx_array.IsEnable() ) continue; 295 296 ++array_num; 297 int total_byte = 0; 298 int elem_num = 0; 299 int elem[ 2 ] = { 0, 0 }; 300 301 for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j ) 302 { 303 if ( vtx_array.byte[ j ] == 0 ) break; 304 total_byte += vtx_array.byte[ j ]; 305 306 // Bind されているとき 307 if ( vtx_array.bind[ j ] >= 0 ) 308 { 309 // 0x204 + ( 3 * N ) or 0x205 + ( 3 * N ) 310 elem[ j / 8 ] |= input_index << ( 4 * ( j % 8 ) ); 311 312 // 0x201 or 0x202 313 type[ input_index / 8 ] |= vtx_array.type[ j ] << ( 4 * ( input_index % 8 ) ); 314 315 // 0x2bb or 0x2bc に入力レジスタのインデックスを設定 316 bind_reg_command[ ( input_index >> 3 ) << 1 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) ); 317 bind_reg_command[ ( input_index >> 3 ) << 1 ] |= vtx_array.bind[ j ] << ( 4 * ( input_index % 8 ) ); 318 319 ++input_index; 320 321 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 322 NN_LOG( "+ 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ], elem[0], elem[1] ); 323 #endif 324 } 325 // Padding のとき 326 else 327 { 328 // 0x204 + ( 3 * N ) or 0x205 + ( 3 * N ) 329 elem[ j / 8 ] |= ( ( vtx_array.byte[ j ] >> 2 ) + 0xb ) << ( 4 * ( j % 8 ) ); 330 331 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 332 NN_LOG( "- 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ] >> 2, elem[0], elem[1] ); 333 #endif 334 } 335 336 ++elem_num; 337 } 338 339 // 0x203 + ( 3 * N ) 340 *command++ = vtx_array.physicalAddr - scBaseAddr * 8; 341 342 // 0x204 + ( 3 * N ) 343 *command++ = elem[ 0 ]; 344 345 // 0x205 + ( 3 * N ) 346 *command++ = elem[ 1 ] | total_byte << 16 | elem_num << 28; 347 } 348 349 // 0x200 350 *headerBaseAddr = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * array_num ); 351 352 if ( array_num % 2 ) *command++ = 0; 353 354 // 固定頂点のセットアップ 355 for ( int bind_reg = VERTEX_ATTRIBUTE_MAX-1; bind_reg >= 0; --bind_reg ) 356 { 357 const AttrConst& vtxConst = m_AttrConst[ bind_reg ]; 358 359 if ( !vtxConst.IsEnable() ) continue; 360 361 // 頂点シェーダへ入力するインデックス 362 *command++ = input_index; 363 // 0x232 364 *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FIXED_ATTR , 4 ); 365 // 固定頂点属性を 24bit に変換した 3 つのデータ, 0x233, 0x234, 0x235 366 *command++ = ( ( Float32ToFloat24( vtxConst.param[3] ) << 8 ) & 0xffffff00 ) | ( ( Float32ToFloat24( vtxConst.param[2] ) >> 16 ) & 0x000000ff ); 367 *command++ = ( ( Float32ToFloat24( vtxConst.param[2] ) << 16 ) & 0xffff0000 ) | ( ( Float32ToFloat24( vtxConst.param[1] ) >> 8 ) & 0x0000ffff ); 368 *command++ = ( ( Float32ToFloat24( vtxConst.param[1] ) << 24 ) & 0xff000000 ) | ( ( Float32ToFloat24( vtxConst.param[0] ) >> 0 ) & 0x00ffffff ); 369 *command++ = 0; // padding 370 371 // 0x2bb or 0x2bc に入力レジスタのインデックスを設定 372 bind_reg_command[ ( input_index / 8 ) * 2 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) ); 373 bind_reg_command[ ( input_index / 8 ) * 2 ] |= bind_reg << ( 4 * ( input_index % 8 ) ); 374 375 // 0x202[27:16] 固定頂点属性マスク 376 fixed_attr_mask |= ( 1 << input_index + 16 ); 377 378 ++input_index; 379 } 380 381 // 頂点属性の入力数の設定 382 // 0x2b9 383 *reg0x2b9 = (input_index - 1) | 0xa0000000; 384 // 0x242 385 *reg0x242 = input_index - 1; 386 // 0x202 387 *reg0x202 |= (input_index - 1) << 28; 388 389 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 390 static int a = 0; 391 if ( ++a == 1 ) 392 { 393 for ( bit32* i = start; i != command; i +=2 ) 394 { 395 NN_LOG( "0x%08x 0x%08x\n", *i, *(i+1) ); 396 } 397 } 398 #endif 399 400 return command; 401 } 402 403 } // namespace CTR 404 } // namespace gr 405 } // namespace nn 406