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