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