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: 38755 $ 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 // Resets vertex information. 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 // Number of vertices to render 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 // Rendering kick 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_BE( PICA_REG_START_DRAW_FUNC0, 0x1 ); 60 61 // Flush vertex cache 62 *command++ = 0x00000001; 63 // 0x231 64 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VERTEX_FUNC ); 65 66 // Send dummy command twice 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 // Disabled because there is a chance it is set somewhere else 88 DisableAttr_( bind_reg ); 89 90 // Search for empty stream 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 // Disable cache 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 // Disabled because there is a chance it is set somewhere else 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 // Disable cache 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 // Search for empty stream 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 // Disable cache 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 // Do nothing if already disabled 188 if ( !m_IsEnableReg[ bind_reg ] ) return; 189 190 // Disable cache 191 m_CmdCacheVertexNum = 0; 192 193 if ( m_AttrConst[ bind_reg ].IsEnable() ) 194 { 195 // Disable fixed vertex attributes 196 m_AttrConst[ bind_reg ].Disable(); 197 198 m_IsEnableReg[ bind_reg ] = false; 199 return; 200 } 201 202 203 // Disable while searching in load arrays 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 // When disabled, checks whether the load array can be disabled 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 // Does nothing specific if disabled 230 if ( !IsEnable() ) 231 { 232 return; 233 } 234 235 // If enabled, disables if all contents is disabled 236 for ( u32 index = 0; index < VERTEX_ATTRIBUTE_MAX; ++index ) 237 { 238 if ( bind[ index ] != -1 ) 239 { 240 return; 241 } 242 } 243 244 physicalAddr = NULL; 245 246 for ( u32 index = 0; index < VERTEX_ATTRIBUTE_MAX; ++index ) 247 { 248 byte[ index ] = 0; 249 } 250 } 251 252 //------------------------------------------------------------------------ 253 DisableAll()254 void Vertex::LoadArray::DisableAll() 255 { 256 physicalAddr = NULL; 257 258 for ( u32 index = 0; index < VERTEX_ATTRIBUTE_MAX; index++ ) 259 { 260 // Initializes at 0x0 261 type[ index ] = PICA_DATA_SIZE_1_BYTE; 262 263 byte[ index ] = 0; 264 265 bind[ index ] = -1; 266 } 267 } 268 269 //------------------------------------------------------------------------ 270 MakeEnableAttrCommand_(bit32 * command) const271 bit32* Vertex::MakeEnableAttrCommand_( bit32* command ) const 272 { 273 // #define NN_GR_VERTEX_DUMP 274 #if defined( NN_GR_VERTEX_DUMP ) // For debugging 275 bit32 * start = command; 276 #endif 277 278 // Sets the vertex shader input register number later 279 bit32* reg0x2b9 = command++; // = vtx_attr_num | 0xa0000000; 280 *command++ = 0x000b02b9; 281 282 bit32* reg0x242 = command++; // = vtx_attr_num; 283 *command++ = 0x00010242; 284 285 // Sets bind_reg_map 286 bit32* bind_reg_command = command; 287 288 // 0x2bb 289 *command++ = 0; 290 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP0 ); 291 292 // 0x2bc 293 *command++ = 0; 294 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP1 ); 295 296 // 0x201 297 bit32* type = &command[ 2 ]; 298 299 // 0x202[27:16] 300 bit32& fixed_attr_mask = command[ 3 ]; 301 302 // 0x200 303 *command++ = scBaseAddr; 304 bit32* headerBaseAddr = command++; // = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * m_AttrArrayNum ); 305 306 // 0x201 307 *command++ = 0; 308 309 // 0x202 310 bit32* reg0x202 = command++; // vtx_attr_num << 28; 311 312 int input_index = 0; 313 int array_num = 0; 314 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i ) 315 { 316 const LoadArray& vtx_array = m_LoadArray[ i ]; 317 318 if ( !vtx_array.IsEnable() ) continue; 319 320 ++array_num; 321 int total_byte = 0; 322 int elem_num = 0; 323 int elem[ 2 ] = { 0, 0 }; 324 325 for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j ) 326 { 327 if ( vtx_array.byte[ j ] == 0 ) break; 328 total_byte += vtx_array.byte[ j ]; 329 330 // If bound 331 if ( vtx_array.bind[ j ] >= 0 ) 332 { 333 // 0x204 + ( 3 * N ) or 0x205 + ( 3 * N ) 334 elem[ j / 8 ] |= input_index << ( 4 * ( j % 8 ) ); 335 336 // 0x201 or 0x202 337 type[ input_index / 8 ] |= vtx_array.type[ j ] << ( 4 * ( input_index % 8 ) ); 338 339 // Set the index of the input register to 0x2bb or 0x2bc 340 bind_reg_command[ ( input_index >> 3 ) << 1 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) ); 341 bind_reg_command[ ( input_index >> 3 ) << 1 ] |= vtx_array.bind[ j ] << ( 4 * ( input_index % 8 ) ); 342 343 ++input_index; 344 345 #if defined( NN_GR_VERTEX_DUMP ) // For debugging 346 NN_LOG( "+ 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ], elem[0], elem[1] ); 347 #endif 348 } 349 // If Padding is used 350 else 351 { 352 // 0x204 + ( 3 * N ) or 0x205 + ( 3 * N ) 353 elem[ j / 8 ] |= ( ( vtx_array.byte[ j ] >> 2 ) + 0xb ) << ( 4 * ( j % 8 ) ); 354 355 #if defined( NN_GR_VERTEX_DUMP ) // For debugging 356 NN_LOG( "- 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ] >> 2, elem[0], elem[1] ); 357 #endif 358 } 359 360 ++elem_num; 361 } 362 363 // 0x203 + ( 3 * N ) 364 *command++ = vtx_array.physicalAddr - scBaseAddr * 8; 365 366 // 0x204 + ( 3 * N ) 367 *command++ = elem[ 0 ]; 368 369 // 0x205 + ( 3 * N ) 370 *command++ = elem[ 1 ] | total_byte << 16 | elem_num << 28; 371 } 372 373 // 0x200 374 *headerBaseAddr = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * array_num ); 375 376 if ( array_num % 2 ) *command++ = 0; 377 378 // Fixed vertex setup 379 for ( int bind_reg = VERTEX_ATTRIBUTE_MAX-1; bind_reg >= 0; --bind_reg ) 380 { 381 const AttrConst& vtxConst = m_AttrConst[ bind_reg ]; 382 383 if ( !vtxConst.IsEnable() ) continue; 384 385 // Index that inputs to vertex shader 386 *command++ = input_index; 387 // 0x232 388 *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FIXED_ATTR , 4 ); 389 // 3 fixed vertex attributes converted to 24-bit values, 0x233, 0x234, 0x235 390 *command++ = ( ( Float32ToFloat24( vtxConst.param[3] ) << 8 ) & 0xffffff00 ) | ( ( Float32ToFloat24( vtxConst.param[2] ) >> 16 ) & 0x000000ff ); 391 *command++ = ( ( Float32ToFloat24( vtxConst.param[2] ) << 16 ) & 0xffff0000 ) | ( ( Float32ToFloat24( vtxConst.param[1] ) >> 8 ) & 0x0000ffff ); 392 *command++ = ( ( Float32ToFloat24( vtxConst.param[1] ) << 24 ) & 0xff000000 ) | ( ( Float32ToFloat24( vtxConst.param[0] ) >> 0 ) & 0x00ffffff ); 393 *command++ = 0; // Padding 394 395 // Set the index of the input register to 0x2bb or 0x2bc 396 bind_reg_command[ ( input_index / 8 ) * 2 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) ); 397 bind_reg_command[ ( input_index / 8 ) * 2 ] |= bind_reg << ( 4 * ( input_index % 8 ) ); 398 399 // 0x202[27:16] Fixed vertex attribute mask 400 fixed_attr_mask |= ( 1 << input_index + 16 ); 401 402 ++input_index; 403 } 404 405 // Set the number of input vertex attributes 406 // 0x2b9 407 *reg0x2b9 = (input_index - 1) | 0xa0000000; 408 // 0x242 409 *reg0x242 = input_index - 1; 410 // 0x202 411 *reg0x202 |= (input_index - 1) << 28; 412 413 #if defined( NN_GR_VERTEX_DUMP ) // For debugging 414 static int a = 0; 415 if ( ++a == 1 ) 416 { 417 for ( bit32* i = start; i != command; i +=2 ) 418 { 419 NN_LOG( "0x%08x 0x%08x\n", *i, *(i+1) ); 420 } 421 } 422 #endif 423 424 return command; 425 } 426 427 } // namespace CTR 428 } // namespace gr 429 } // namespace nn 430