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: 37389 $
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                 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                 // キャッシュの無効化
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                 // ほかで設定されている可能性があるので無効化しておく
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                 // キャッシュの無効化
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                 // 空いているストリームを探す
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                 // キャッシュの無効化
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                 // すでに無効化されていたら何もしない
188                 if ( !m_IsEnableReg[ bind_reg ] ) return;
189 
190                 // キャッシュの無効化
191                 m_CmdCacheVertexNum = 0;
192 
193                 if ( m_AttrConst[ bind_reg ].IsEnable() )
194                 {
195                     // 固定頂点属性の無効化
196                     m_AttrConst[ bind_reg ].Disable();
197 
198                     m_IsEnableReg[ bind_reg ] = false;
199                     return;
200                 }
201 
202 
203                 // ロードアレイの中を探しながら無効化
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                         // 無効化できた場合、ロードアレイ自体が無効化できないか調べる
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                 // 無効化されているなら、特に何もしない
230                 if ( !IsEnable() ) return;
231 
232                 // 有効化されている場合、中身がすべて無効なら無効化する
233                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
234                 {
235                     if ( bind[ i ] != -1 ) return;
236                 }
237 
238                 physicalAddr = 0;
239                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
240                 {
241                     byte[ i ] = 0;
242                 }
243             }
244 
245             //------------------------------------------------------------------------
246 
MakeEnableAttrCommand_(bit32 * command) const247             bit32* Vertex::MakeEnableAttrCommand_( bit32* command ) const
248             {
249             // #define NN_GR_VERTEX_DUMP
250             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
251                 bit32 * start = command;
252             #endif
253 
254                 // 頂点シェーダーの入力レジスタ数を後で設定
255                 bit32* reg0x2b9 = command++; // = vtx_attr_num | 0xa0000000;
256                 *command++ = 0x000b02b9;
257 
258                 bit32* reg0x242 = command++; // = vtx_attr_num;
259                 *command++ = 0x00010242;
260 
261                 // bind_reg_mapの設定
262                 bit32* bind_reg_command = command;
263 
264                 // 0x2bb
265                 *command++ = 0;
266                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP0 );
267 
268                 // 0x2bc
269                 *command++ = 0;
270                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP1 );
271 
272                 // 0x201
273                 bit32* type = &command[ 2 ];
274 
275                 // 0x202[27:16]
276                 bit32& fixed_attr_mask = command[ 3 ];
277 
278                 // 0x200
279                 *command++            = scBaseAddr;
280                 bit32* headerBaseAddr = command++; // = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * m_AttrArrayNum );
281 
282                 // 0x201
283                 *command++            = 0;
284 
285                 // 0x202
286                 bit32* reg0x202       = command++; // vtx_attr_num << 28;
287 
288                 int input_index = 0;
289                 int array_num   = 0;
290                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
291                 {
292                     const LoadArray& vtx_array = m_LoadArray[ i ];
293 
294                     if ( !vtx_array.IsEnable() ) continue;
295 
296                     ++array_num;
297                     int total_byte = 0;
298                     int elem_num   = 0;
299                     int elem[ 2 ]  = { 0, 0 };
300 
301                     for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j )
302                     {
303                         if ( vtx_array.byte[ j ] == 0 ) break;
304                         total_byte += vtx_array.byte[ j ];
305 
306                         // Bind されているとき
307                         if ( vtx_array.bind[ j ] >= 0 )
308                         {
309                             // 0x204 + ( 3 * N ) or 0x205 + ( 3 * N )
310                             elem[ j / 8 ] |= input_index << ( 4 * ( j % 8 ) );
311 
312                             // 0x201 or 0x202
313                             type[ input_index / 8 ] |= vtx_array.type[ j ] << ( 4 * ( input_index % 8 ) );
314 
315                             // 0x2bb or 0x2bc に入力レジスタのインデックスを設定
316                             bind_reg_command[ ( input_index >> 3 ) << 1 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) );
317                             bind_reg_command[ ( input_index >> 3 ) << 1 ] |= vtx_array.bind[ j ] << ( 4 * ( input_index % 8 ) );
318 
319                             ++input_index;
320 
321                             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
322                             NN_LOG( "+ 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ], elem[0], elem[1] );
323                             #endif
324                         }
325                         // Padding のとき
326                         else
327                         {
328                             // 0x204 + ( 3 * N ) or 0x205 + ( 3 * N )
329                             elem[ j / 8 ] |= ( ( vtx_array.byte[ j ] >> 2 ) + 0xb ) << ( 4 * ( j % 8 ) );
330 
331                             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
332                             NN_LOG( "- 0x%08x 0x%08x 0x%08x\n",  vtx_array.byte[ j ] >> 2, elem[0], elem[1] );
333                             #endif
334                         }
335 
336                         ++elem_num;
337                     }
338 
339                     // 0x203 + ( 3 * N )
340                     *command++ = vtx_array.physicalAddr  - scBaseAddr * 8;
341 
342                     // 0x204 + ( 3 * N )
343                     *command++ = elem[ 0 ];
344 
345                     // 0x205 + ( 3 * N )
346                     *command++ = elem[ 1 ] | total_byte << 16 | elem_num << 28;
347                 }
348 
349                 // 0x200
350                 *headerBaseAddr = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * array_num );
351 
352                 if ( array_num % 2 ) *command++ = 0;
353 
354                 // 固定頂点のセットアップ
355                 for ( int bind_reg = VERTEX_ATTRIBUTE_MAX-1; bind_reg >= 0; --bind_reg )
356                 {
357                     const AttrConst& vtxConst = m_AttrConst[ bind_reg ];
358 
359                     if ( !vtxConst.IsEnable() ) continue;
360 
361                     // 頂点シェーダへ入力するインデックス
362                     *command++ = input_index;
363                     // 0x232
364                     *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FIXED_ATTR , 4 );
365                     // 固定頂点属性を 24bit に変換した 3 つのデータ, 0x233, 0x234, 0x235
366                     *command++ = ( ( Float32ToFloat24( vtxConst.param[3] ) <<  8 ) & 0xffffff00 ) | ( ( Float32ToFloat24( vtxConst.param[2] ) >> 16 ) & 0x000000ff );
367                     *command++ = ( ( Float32ToFloat24( vtxConst.param[2] ) << 16 ) & 0xffff0000 ) | ( ( Float32ToFloat24( vtxConst.param[1] ) >>  8 ) & 0x0000ffff );
368                     *command++ = ( ( Float32ToFloat24( vtxConst.param[1] ) << 24 ) & 0xff000000 ) | ( ( Float32ToFloat24( vtxConst.param[0] ) >>  0 ) & 0x00ffffff );
369                     *command++ = 0; // padding
370 
371                     // 0x2bb or 0x2bc に入力レジスタのインデックスを設定
372                     bind_reg_command[ ( input_index / 8 ) * 2 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) );
373                     bind_reg_command[ ( input_index / 8 ) * 2 ] |= bind_reg << ( 4 * ( input_index % 8 ) );
374 
375                     // 0x202[27:16] 固定頂点属性マスク
376                     fixed_attr_mask |= ( 1 << input_index + 16 );
377 
378                     ++input_index;
379                 }
380 
381                 // 頂点属性の入力数の設定
382                 // 0x2b9
383                 *reg0x2b9  = (input_index - 1) | 0xa0000000;
384                 // 0x242
385                 *reg0x242  = input_index - 1;
386                 // 0x202
387                 *reg0x202 |= (input_index - 1) << 28;
388 
389             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
390                 static int a = 0;
391                 if ( ++a == 1 )
392                 {
393                     for ( bit32* i = start; i != command; i +=2 )
394                     {
395                         NN_LOG( "0x%08x 0x%08x\n", *i, *(i+1) );
396                     }
397                 }
398             #endif
399 
400                 return command;
401             }
402 
403         }  // namespace CTR
404     }  // namespace gr
405 } // namespace nn
406