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: 29908 $
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                 // 頂点情報をリセットします
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                 // 描画頂点数
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                 // 描画キック
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                 // 頂点キャッシュのフラッシュ
62                 *command++ = 0x00000001;
63                 // 0x231
64                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VERTEX_FUNC );
65 
66                 // ダミーコマンド を 2回送ります
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                 // ほかで設定されている可能性があるので無効化しておく
88                 DisableAttr_( bind_reg );
89 
90                 // 空いているストリームを探す
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                 array->physicalAddr = physical_addr;
103                 array->type[ 0 ] = type;
104                 array->bind[ 0 ] = bind_reg;
105                 array->byte[ 0 ] = byte;
106 
107                 for ( int i = 1; i < VERTEX_ATTRIBUTE_MAX; ++i )
108                 {
109                     array->bind[ i ] = -1;
110                     array->byte[ i ] = 0;
111                 }
112 
113                 // キャッシュの無効化
114                 m_CmdCacheVertexNum = 0;
115             }
116 
117             //------------------------------------------------------------------------
118 
EnableAttrAsConst(const BindSymbolVSInput & symbol,const u8 dimension,const f32 param[])119             void Vertex::EnableAttrAsConst( const BindSymbolVSInput& symbol,
120                                             const u8  dimension,
121                                             const f32 param[] )
122             {
123                 const bit32 bind_reg = symbol.start;
124 
125                 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX );
126 
127                 // ほかで設定されている可能性があるので無効化しておく
128                 DisableAttr_( bind_reg );
129 
130                 m_IsEnableReg[ bind_reg ] = true;
131                 m_AttrConst[ bind_reg ].dimension = dimension;
132 
133                 f32 defaultParam[ 4 ] = { 0.f, 0.f, 0.f, 1.f };
134                 for ( int i = 0; i < 4; ++i )
135                 {
136                     m_AttrConst[ bind_reg ].param[ i ] = i < dimension ? param[ i ] : defaultParam[ i ];
137                 }
138 
139                 // キャッシュの無効化
140                 m_CmdCacheVertexNum = 0;
141             }
142 
143             //------------------------------------------------------------------------
144 
EnableInterleavedArray(const nn::gr::CTR::Vertex::InterleaveInfo & interleave_info,const uptr physical_addr)145             void Vertex::EnableInterleavedArray( const nn::gr::CTR::Vertex::InterleaveInfo& interleave_info, const uptr physical_addr )
146             {
147                 // 空いているストリームを探す
148                 LoadArray* array = NULL;
149                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
150                 {
151                     if ( m_LoadArray[ i ].IsEnable() == false )
152                     {
153                         array = &m_LoadArray[ i ];
154                         break;
155                     }
156                 }
157                 NN_GR_ASSERT( array != NULL );
158 
159                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
160                 {
161                     if ( interleave_info.symbol[ i ] == NULL )
162                     {
163                         array->bind[ i ] = -1;
164                     }
165                     else
166                     {
167                         array->bind[ i ] = interleave_info.symbol[ i ]->start;
168                         array->physicalAddr = physical_addr;
169                     }
170 
171                     array->type[ i ] = interleave_info.dataType[ i ];
172 
173                     array->byte[ i ] = i < interleave_info.dataNum ? PicaDataVertexAttrTypeToByteSize( array->type[ i ] ) : 0;
174                 }
175 
176                 // キャッシュの無効化
177                 m_CmdCacheVertexNum = 0;
178             }
179 
180             //------------------------------------------------------------------------
181 
DisableAttr_(const bit32 bind_reg)182             void Vertex::DisableAttr_( const bit32 bind_reg )
183             {
184                 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX );
185 
186                 // すでに無効化されていたら何もしない
187                 if ( !m_IsEnableReg[ bind_reg ] ) return;
188 
189                 // キャッシュの無効化
190                 m_CmdCacheVertexNum = 0;
191 
192                 if ( m_AttrConst[ bind_reg ].IsEnable() )
193                 {
194                     // 固定頂点属性の無効化
195                     m_AttrConst[ bind_reg ].Disable();
196 
197                     m_IsEnableReg[ bind_reg ] = false;
198                     return;
199                 }
200 
201 
202                 // ロードアレイの中を探しながら無効化
203                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
204                 {
205                     if ( ! m_LoadArray[ i ].IsEnable() ) continue;
206 
207                     for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j )
208                     {
209                         if ( m_LoadArray[ i ].bind[ j ] != bind_reg ) continue;
210 
211                         m_LoadArray[ i ].bind[ j ] = -1;
212                         m_IsEnableReg[ bind_reg ] = false;
213 
214                         // 無効化できた場合、ロードアレイ自体が無効化できないか調べる
215                         m_LoadArray[ i ].CheckDisable();
216 
217                         return;
218                     }
219                 }
220 
221                 NN_GR_ASSERT( m_IsEnableReg[ bind_reg ] == false );
222             }
223 
224             //------------------------------------------------------------------------
225 
CheckDisable()226             void Vertex::LoadArray::CheckDisable()
227             {
228                 // 無効化されているなら、特に何もしない
229                 if ( !IsEnable() ) return;
230 
231                 // 有効化されている場合、中身がすべて無効なら無効化する
232                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
233                 {
234                     if ( bind[ i ] != -1 ) return;
235                 }
236 
237                 physicalAddr = 0;
238                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
239                 {
240                     byte[ i ] = 0;
241                 }
242             }
243 
244             //------------------------------------------------------------------------
245 
MakeEnableAttrCommand_(bit32 * command) const246             bit32* Vertex::MakeEnableAttrCommand_( bit32* command ) const
247             {
248             // #define NN_GR_VERTEX_DUMP
249             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
250                 bit32 * start = command;
251             #endif
252 
253                 // 頂点シェーダーの入力レジスタ数を設定
254                 bit32* reg0x2b9 = command++;// = vtx_attr_num | 0xa0000000;
255                 *command++ = 0x000b02b9;
256                 bit32* reg0x242 = command++;// = vtx_attr_num;
257                 *command++ = 0x00010242;
258 
259                 // bind_reg_mapの設定
260                 bit32* bind_reg_command = command;
261                 *command++ = 0;
262                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP0 );
263                 *command++ = 0;
264                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP1 );
265 
266                 // 頂点属性の設定ヘッダー部分
267                 bit32* type = &command[ 2 ];
268                 bit32& fixed_attr_mask = command[ 3 ];
269                 *command++ = scBaseAddr;
270                 bit32* headerBaseAddr = command++; // = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * m_AttrArrayNum );
271                 *command++ = 0;
272                 bit32* reg0x202 = command++; // vtx_attr_num << 28;
273 
274                 int input_index = 0;
275                 int array_num = 0;
276                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
277                 {
278                     const LoadArray& vtx_array = m_LoadArray[ i ];
279 
280                     if ( !vtx_array.IsEnable() ) continue;
281 
282                     ++array_num;
283                     int total_byte = 0;
284                     int elem_num = 0;
285                     int elem[ 2 ] = { 0, 0 };
286                     for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j )
287                     {
288                         if ( vtx_array.byte[ j ] == 0 ) break;
289                         total_byte += vtx_array.byte[ j ];
290 
291                         if ( vtx_array.bind[ j ] >= 0 )
292                         {
293                             elem[ j / 8 ] |= input_index << ( 4 * ( j % 8 ) );
294                             type[ input_index / 8 ] |= vtx_array.type[ j ] << ( 4 * ( input_index % 8 ) );
295                             bind_reg_command[ ( input_index >> 3 ) << 1 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) );
296                             bind_reg_command[ ( input_index >> 3 ) << 1 ] |= vtx_array.bind[ j ] << ( 4 * ( input_index % 8 ) );
297                             ++input_index;
298                             ++elem_num;
299 
300                             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
301                             NN_LOG( "+ 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ], elem[0], elem[1] );
302                             #endif
303                         }
304                         else
305                         {
306                             elem[ j / 8 ] |= ( ( vtx_array.byte[ j ] >> 2 ) + 0xb ) << ( 4 * ( j % 8 ) );
307 
308                             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
309                             NN_LOG( "- 0x%08x 0x%08x 0x%08x\n",  vtx_array.byte[ j ] >> 2, elem[0], elem[1] );
310                             #endif
311                         }
312                     }
313                     *command++ = vtx_array.physicalAddr  - scBaseAddr * 8;
314                     *command++ = elem[ 0 ];
315                     *command++ = elem[ 1 ] | total_byte << 16 | elem_num << 28;
316                 }
317                 *headerBaseAddr = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * array_num );
318                 if ( array_num % 2 ) *command++ = 0;
319 
320                 // 固定頂点のセットアップ
321                 for ( int bind_reg = VERTEX_ATTRIBUTE_MAX-1; bind_reg >= 0; --bind_reg )
322                 {
323                     const AttrConst& vtxConst = m_AttrConst[ bind_reg ];
324 
325                     if ( !vtxConst.IsEnable() ) continue;
326 
327                     *command++ = input_index;
328                     // 0x232
329                     *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FIXED_ATTR , 4 );
330                     *command++ = ( ( Float32ToFloat24( vtxConst.param[3] ) <<  8 ) & 0xffffff00 ) | ( ( Float32ToFloat24( vtxConst.param[2] ) >> 16 ) & 0x000000ff );
331                     *command++ = ( ( Float32ToFloat24( vtxConst.param[2] ) << 16 ) & 0xffff0000 ) | ( ( Float32ToFloat24( vtxConst.param[1] ) >>  8 ) & 0x0000ffff );
332                     *command++ = ( ( Float32ToFloat24( vtxConst.param[1] ) << 24 ) & 0xff000000 ) | ( ( Float32ToFloat24( vtxConst.param[0] ) >>  0 ) & 0x00ffffff );
333                     *command++ = 0; // padding
334 
335                     bind_reg_command[ ( input_index / 8 ) * 2 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) );
336                     bind_reg_command[ ( input_index / 8 ) * 2 ] |= bind_reg << ( 4 * ( input_index % 8 ) );
337 
338                     fixed_attr_mask |= ( 1 << input_index + 16 );
339                     ++input_index;
340                 }
341                 // 0x2b9
342                 *reg0x2b9  = (input_index - 1) | 0xa0000000;
343                 // 0x242
344                 *reg0x242  = input_index - 1;
345                 // 0x202
346                 *reg0x202 |= (input_index - 1) << 28;
347 
348             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
349                 static int a = 0;
350                 if ( ++a == 1 )
351                 {
352                     for ( bit32* i = start; i != command; i +=2 )
353                     {
354                         NN_LOG( "0x%08x 0x%08x\n", *i, *(i+1) );
355                     }
356                 }
357             #endif
358 
359                 return command;
360             }
361 
362         }  // namespace CTR
363     }  // namespace gr
364 } // namespace nn
365