1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: gr_Vertex.cpp 4 Copyright (C)2010 Nintendo Co., Ltd. All rights reserved. 5 These coded instructions, statements, and computer programs contain 6 proprietary information of Nintendo of America Inc. and/or Nintendo 7 Company Ltd., and are protected by Federal copyright law. They may 8 not be disclosed to third parties or copied or duplicated in any form, 9 in whole or in part, without the prior written consent of Nintendo. 10 $Rev: 37048 $ 11 *--------------------------------------------------------------------------- 12 13 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( PICA_REG_START_DRAW_FUNC0 ); 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