1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     gr_Vertex.cpp
4 
5   Copyright (C)2009-2012 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: 46347 $
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                 // Render vertex count
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                 // Render 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 it may be set somewhere else
88                 DisableAttr_( bind_reg );
89 
90                 // Search for an 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 it may be 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 an 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 if searching in the load array
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 if the load array itself 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                 // Do nothing if already disabled
230                 if ( !IsEnable() )
231                 {
232                     return;
233                 }
234 
235                 // When enabled, disable if all content is invalid
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                     // Initialize with 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                 // Set the vertex shader input register count 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                 // Set 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                     int maxAlign   = 1;
325 
326                     for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j )
327                     {
328                         // Consider padding automatically inserted depending on the order of all elements type
329                         switch (vtx_array.type[ j ])
330                         {
331                         case PICA_DATA_SIZE_1_SHORT:
332                         case PICA_DATA_SIZE_2_SHORT:
333                         case PICA_DATA_SIZE_3_SHORT:
334                         case PICA_DATA_SIZE_4_SHORT:
335                             total_byte = ((total_byte + 1) & ~0x1);
336                             if (maxAlign < 2) { maxAlign = 2; }
337                         break;
338 
339                         case PICA_DATA_SIZE_1_FLOAT:
340                         case PICA_DATA_SIZE_2_FLOAT:
341                         case PICA_DATA_SIZE_3_FLOAT:
342                         case PICA_DATA_SIZE_4_FLOAT:
343                             total_byte = ((total_byte + 3) & ~0x3);
344                             if (maxAlign < 4) { maxAlign = 4; }
345                         break;
346 
347                         default:
348                         break;
349                         }
350 
351                         if ( vtx_array.byte[ j ] == 0 ) break;
352                         total_byte += vtx_array.byte[ j ];
353 
354                         // When bound
355                         if ( vtx_array.bind[ j ] >= 0 )
356                         {
357                             // 0x204 + ( 3 * N ) or 0x205 + ( 3 * N )
358                             elem[ j / 8 ] |= input_index << ( 4 * ( j % 8 ) );
359 
360                             // 0x201 or 0x202
361                             type[ input_index / 8 ] |= vtx_array.type[ j ] << ( 4 * ( input_index % 8 ) );
362 
363                             // Set the input register index in 0x2bb or 0x2bc
364                             bind_reg_command[ ( input_index >> 3 ) << 1 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) );
365                             bind_reg_command[ ( input_index >> 3 ) << 1 ] |= vtx_array.bind[ j ] << ( 4 * ( input_index % 8 ) );
366 
367                             ++input_index;
368 
369                             #if defined( NN_GR_VERTEX_DUMP ) // For debugging
370                             NN_LOG( "+ 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ], elem[0], elem[1] );
371                             #endif
372                         }
373                         // For Padding
374                         else
375                         {
376                             // 0x204 + ( 3 * N ) or 0x205 + ( 3 * N )
377                             elem[ j / 8 ] |= ( ( vtx_array.byte[ j ] >> 2 ) + 0xb ) << ( 4 * ( j % 8 ) );
378 
379                             #if defined( NN_GR_VERTEX_DUMP ) // For debugging
380                             NN_LOG( "- 0x%08x 0x%08x 0x%08x\n",  vtx_array.byte[ j ] >> 2, elem[0], elem[1] );
381                             #endif
382                         }
383 
384                         ++elem_num;
385                     }
386 
387                     // 0x203 + ( 3 * N )
388                     *command++ = vtx_array.physicalAddr  - scBaseAddr * 8;
389 
390                     // 0x204 + ( 3 * N )
391                     *command++ = elem[ 0 ];
392 
393                     // 0x205 + ( 3 * N )
394                     // Strides for each vertex is a multiple of the size of the largest type of the vertex attributes included in the vertex data structure
395                     // Padding automatically inserted must be considered
396                     *command++ = elem[ 1 ] | ((total_byte + (maxAlign - 1)) & ~(maxAlign - 1)) << 16 | elem_num << 28;
397                 }
398 
399                 // 0x200
400                 *headerBaseAddr = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * array_num );
401 
402                 if ( array_num % 2 ) *command++ = 0;
403 
404                 // Fixed vertex setup
405                 for ( int bind_reg = VERTEX_ATTRIBUTE_MAX-1; bind_reg >= 0; --bind_reg )
406                 {
407                     const AttrConst& vtxConst = m_AttrConst[ bind_reg ];
408 
409                     if ( !vtxConst.IsEnable() ) continue;
410 
411                     // Index to input to the vertex shader
412                     *command++ = input_index;
413                     // 0x232
414                     *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FIXED_ATTR , 4 );
415                     // The 3 data portions of the fixed vertex attributes converted to 24 bit: 0x233, 0x234, 0x235
416                     *command++ = ( ( Float32ToFloat24( vtxConst.param[3] ) <<  8 ) & 0xffffff00 ) | ( ( Float32ToFloat24( vtxConst.param[2] ) >> 16 ) & 0x000000ff );
417                     *command++ = ( ( Float32ToFloat24( vtxConst.param[2] ) << 16 ) & 0xffff0000 ) | ( ( Float32ToFloat24( vtxConst.param[1] ) >>  8 ) & 0x0000ffff );
418                     *command++ = ( ( Float32ToFloat24( vtxConst.param[1] ) << 24 ) & 0xff000000 ) | ( ( Float32ToFloat24( vtxConst.param[0] ) >>  0 ) & 0x00ffffff );
419                     *command++ = 0; // Padding
420 
421                     // Set the input register index in 0x2bb or 0x2bc
422                     bind_reg_command[ ( input_index / 8 ) * 2 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) );
423                     bind_reg_command[ ( input_index / 8 ) * 2 ] |= bind_reg << ( 4 * ( input_index % 8 ) );
424 
425                     // 0x202[27:16] Fixed vertex attribute mask
426                     fixed_attr_mask |= ( 1 << input_index + 16 );
427 
428                     ++input_index;
429                 }
430 
431                 // Vertex attribute input count setting
432                 // 0x2b9
433                 *reg0x2b9  = (input_index - 1) | 0xa0000000;
434                 // 0x242
435                 *reg0x242  = input_index - 1;
436                 // 0x202
437                 *reg0x202 |= (input_index - 1) << 28;
438 
439             #if defined( NN_GR_VERTEX_DUMP ) // For debugging
440                 static int a = 0;
441                 if ( ++a == 1 )
442                 {
443                     for ( bit32* i = start; i != command; i +=2 )
444                     {
445                         NN_LOG( "0x%08x 0x%08x\n", *i, *(i+1) );
446                     }
447                 }
448             #endif
449 
450                 return command;
451             }
452 
453         }  // namespace CTR
454     }  // namespace gr
455 } // namespace nn
456