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: 29908 $ 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 array->physicalAddr = physical_addr; 103 array->type[ 0 ] = type; 104 array->bind[ 0 ] = bind_reg; 105 array->byte[ 0 ] = byte; 106 107 for ( int i = 1; i < VERTEX_ATTRIBUTE_MAX; ++i ) 108 { 109 array->bind[ i ] = -1; 110 array->byte[ i ] = 0; 111 } 112 113 // キャッシュの無効化 114 m_CmdCacheVertexNum = 0; 115 } 116 117 //------------------------------------------------------------------------ 118 EnableAttrAsConst(const BindSymbolVSInput & symbol,const u8 dimension,const f32 param[])119 void Vertex::EnableAttrAsConst( const BindSymbolVSInput& symbol, 120 const u8 dimension, 121 const f32 param[] ) 122 { 123 const bit32 bind_reg = symbol.start; 124 125 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); 126 127 // ほかで設定されている可能性があるので無効化しておく 128 DisableAttr_( bind_reg ); 129 130 m_IsEnableReg[ bind_reg ] = true; 131 m_AttrConst[ bind_reg ].dimension = dimension; 132 133 f32 defaultParam[ 4 ] = { 0.f, 0.f, 0.f, 1.f }; 134 for ( int i = 0; i < 4; ++i ) 135 { 136 m_AttrConst[ bind_reg ].param[ i ] = i < dimension ? param[ i ] : defaultParam[ i ]; 137 } 138 139 // キャッシュの無効化 140 m_CmdCacheVertexNum = 0; 141 } 142 143 //------------------------------------------------------------------------ 144 EnableInterleavedArray(const nn::gr::CTR::Vertex::InterleaveInfo & interleave_info,const uptr physical_addr)145 void Vertex::EnableInterleavedArray( const nn::gr::CTR::Vertex::InterleaveInfo& interleave_info, const uptr physical_addr ) 146 { 147 // 空いているストリームを探す 148 LoadArray* array = NULL; 149 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 150 { 151 if ( m_LoadArray[ i ].IsEnable() == false ) 152 { 153 array = &m_LoadArray[ i ]; 154 break; 155 } 156 } 157 NN_GR_ASSERT( array != NULL ); 158 159 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 160 { 161 if ( interleave_info.symbol[ i ] == NULL ) 162 { 163 array->bind[ i ] = -1; 164 } 165 else 166 { 167 array->bind[ i ] = interleave_info.symbol[ i ]->start; 168 array->physicalAddr = physical_addr; 169 } 170 171 array->type[ i ] = interleave_info.dataType[ i ]; 172 173 array->byte[ i ] = i < interleave_info.dataNum ? PicaDataVertexAttrTypeToByteSize( array->type[ i ] ) : 0; 174 } 175 176 // キャッシュの無効化 177 m_CmdCacheVertexNum = 0; 178 } 179 180 //------------------------------------------------------------------------ 181 DisableAttr_(const bit32 bind_reg)182 void Vertex::DisableAttr_( const bit32 bind_reg ) 183 { 184 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX ); 185 186 // すでに無効化されていたら何もしない 187 if ( !m_IsEnableReg[ bind_reg ] ) return; 188 189 // キャッシュの無効化 190 m_CmdCacheVertexNum = 0; 191 192 if ( m_AttrConst[ bind_reg ].IsEnable() ) 193 { 194 // 固定頂点属性の無効化 195 m_AttrConst[ bind_reg ].Disable(); 196 197 m_IsEnableReg[ bind_reg ] = false; 198 return; 199 } 200 201 202 // ロードアレイの中を探しながら無効化 203 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 204 { 205 if ( ! m_LoadArray[ i ].IsEnable() ) continue; 206 207 for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j ) 208 { 209 if ( m_LoadArray[ i ].bind[ j ] != bind_reg ) continue; 210 211 m_LoadArray[ i ].bind[ j ] = -1; 212 m_IsEnableReg[ bind_reg ] = false; 213 214 // 無効化できた場合、ロードアレイ自体が無効化できないか調べる 215 m_LoadArray[ i ].CheckDisable(); 216 217 return; 218 } 219 } 220 221 NN_GR_ASSERT( m_IsEnableReg[ bind_reg ] == false ); 222 } 223 224 //------------------------------------------------------------------------ 225 CheckDisable()226 void Vertex::LoadArray::CheckDisable() 227 { 228 // 無効化されているなら、特に何もしない 229 if ( !IsEnable() ) return; 230 231 // 有効化されている場合、中身がすべて無効なら無効化する 232 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 233 { 234 if ( bind[ i ] != -1 ) return; 235 } 236 237 physicalAddr = 0; 238 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 239 { 240 byte[ i ] = 0; 241 } 242 } 243 244 //------------------------------------------------------------------------ 245 MakeEnableAttrCommand_(bit32 * command) const246 bit32* Vertex::MakeEnableAttrCommand_( bit32* command ) const 247 { 248 // #define NN_GR_VERTEX_DUMP 249 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 250 bit32 * start = command; 251 #endif 252 253 // 頂点シェーダーの入力レジスタ数を設定 254 bit32* reg0x2b9 = command++;// = vtx_attr_num | 0xa0000000; 255 *command++ = 0x000b02b9; 256 bit32* reg0x242 = command++;// = vtx_attr_num; 257 *command++ = 0x00010242; 258 259 // bind_reg_mapの設定 260 bit32* bind_reg_command = command; 261 *command++ = 0; 262 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP0 ); 263 *command++ = 0; 264 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP1 ); 265 266 // 頂点属性の設定ヘッダー部分 267 bit32* type = &command[ 2 ]; 268 bit32& fixed_attr_mask = command[ 3 ]; 269 *command++ = scBaseAddr; 270 bit32* headerBaseAddr = command++; // = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * m_AttrArrayNum ); 271 *command++ = 0; 272 bit32* reg0x202 = command++; // vtx_attr_num << 28; 273 274 int input_index = 0; 275 int array_num = 0; 276 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 277 { 278 const LoadArray& vtx_array = m_LoadArray[ i ]; 279 280 if ( !vtx_array.IsEnable() ) continue; 281 282 ++array_num; 283 int total_byte = 0; 284 int elem_num = 0; 285 int elem[ 2 ] = { 0, 0 }; 286 for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j ) 287 { 288 if ( vtx_array.byte[ j ] == 0 ) break; 289 total_byte += vtx_array.byte[ j ]; 290 291 if ( vtx_array.bind[ j ] >= 0 ) 292 { 293 elem[ j / 8 ] |= input_index << ( 4 * ( j % 8 ) ); 294 type[ input_index / 8 ] |= vtx_array.type[ j ] << ( 4 * ( input_index % 8 ) ); 295 bind_reg_command[ ( input_index >> 3 ) << 1 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) ); 296 bind_reg_command[ ( input_index >> 3 ) << 1 ] |= vtx_array.bind[ j ] << ( 4 * ( input_index % 8 ) ); 297 ++input_index; 298 ++elem_num; 299 300 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 301 NN_LOG( "+ 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ], elem[0], elem[1] ); 302 #endif 303 } 304 else 305 { 306 elem[ j / 8 ] |= ( ( vtx_array.byte[ j ] >> 2 ) + 0xb ) << ( 4 * ( j % 8 ) ); 307 308 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 309 NN_LOG( "- 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ] >> 2, elem[0], elem[1] ); 310 #endif 311 } 312 } 313 *command++ = vtx_array.physicalAddr - scBaseAddr * 8; 314 *command++ = elem[ 0 ]; 315 *command++ = elem[ 1 ] | total_byte << 16 | elem_num << 28; 316 } 317 *headerBaseAddr = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * array_num ); 318 if ( array_num % 2 ) *command++ = 0; 319 320 // 固定頂点のセットアップ 321 for ( int bind_reg = VERTEX_ATTRIBUTE_MAX-1; bind_reg >= 0; --bind_reg ) 322 { 323 const AttrConst& vtxConst = m_AttrConst[ bind_reg ]; 324 325 if ( !vtxConst.IsEnable() ) continue; 326 327 *command++ = input_index; 328 // 0x232 329 *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FIXED_ATTR , 4 ); 330 *command++ = ( ( Float32ToFloat24( vtxConst.param[3] ) << 8 ) & 0xffffff00 ) | ( ( Float32ToFloat24( vtxConst.param[2] ) >> 16 ) & 0x000000ff ); 331 *command++ = ( ( Float32ToFloat24( vtxConst.param[2] ) << 16 ) & 0xffff0000 ) | ( ( Float32ToFloat24( vtxConst.param[1] ) >> 8 ) & 0x0000ffff ); 332 *command++ = ( ( Float32ToFloat24( vtxConst.param[1] ) << 24 ) & 0xff000000 ) | ( ( Float32ToFloat24( vtxConst.param[0] ) >> 0 ) & 0x00ffffff ); 333 *command++ = 0; // padding 334 335 bind_reg_command[ ( input_index / 8 ) * 2 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) ); 336 bind_reg_command[ ( input_index / 8 ) * 2 ] |= bind_reg << ( 4 * ( input_index % 8 ) ); 337 338 fixed_attr_mask |= ( 1 << input_index + 16 ); 339 ++input_index; 340 } 341 // 0x2b9 342 *reg0x2b9 = (input_index - 1) | 0xa0000000; 343 // 0x242 344 *reg0x242 = input_index - 1; 345 // 0x202 346 *reg0x202 |= (input_index - 1) << 28; 347 348 #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用 349 static int a = 0; 350 if ( ++a == 1 ) 351 { 352 for ( bit32* i = start; i != command; i +=2 ) 353 { 354 NN_LOG( "0x%08x 0x%08x\n", *i, *(i+1) ); 355 } 356 } 357 #endif 358 359 return command; 360 } 361 362 } // namespace CTR 363 } // namespace gr 364 } // namespace nn 365