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: 26237 $
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 u32 scBaseAddr = nngxGetPhysicalAddr( nngxGetVramStartAddr( nn::gx::MEM_VRAMA ) ) >> 3;
26 
27             //------------------------------------------------------------------------
28 
MakeDrawCommand(u32 * command,const IndexStream & index_stream) const29             u32* Vertex::MakeDrawCommand( u32* command, const IndexStream& index_stream ) const
30             {
31                 u32 fmt  = index_stream.isUnsignedByte ? 0x00000000 : 0x80000000;
32 
33                 u32 addr = index_stream.physicalAddr - scBaseAddr * 8;
34 
35                 // offset
36                 *command++ = fmt | addr;
37                 // 0x227
38                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_INDEX_ARRAY_ADDR_OFFSET );
39 
40                 // 描画頂点数
41                 *command++ = index_stream.drawVtxNum;
42                 // 0x228
43                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_DRAW_VERTEX_NUM );
44 
45                 // ジオメトリシェーダー関連の設定 on
46                 *command++ = 0x00000000;
47                 // 0x245
48                 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_START_DRAW_FUNC0, 0x1 );
49 
50                 // 描画キック
51                 *command++ = 0x00000001;
52                 // 0x22f
53                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_START_DRAW_ELEMENT );
54 
55                 // ジオメトリシェーダー関連の設定 off
56                 *command++ = 0x00000001;
57                 // 0x245
58                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_START_DRAW_FUNC0 );
59 
60                 // 頂点キャッシュのフラッシュ
61                 *command++ = 0x00000001;
62                 // 0x231
63                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VERTEX_FUNC );
64 
65                 return command;
66             }
67 
68             //------------------------------------------------------------------------
69 
EnableAttrAsArray(const BindSymbolVSInput & symbol,const u32 physical_addr,const PicaDataVertexAttrType type)70             void Vertex::EnableAttrAsArray( const BindSymbolVSInput& symbol,
71                                             const u32 physical_addr,
72                                             const PicaDataVertexAttrType type )
73             {
74                 const u32 bind_reg = symbol.start;
75                 const u32 byte     = PicaDataVertexAttrTypeToByteSize( type );
76                 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX );
77 
78                 // ほかで設定されている可能性があるので無効化しておく
79                 DisableAttr_( bind_reg );
80 
81                 // 空いているストリームを探す
82                 LoadArray* array = NULL;
83                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
84                 {
85                     if ( m_LoadArray[ i ].IsEnable() == false )
86                     {
87                         array = &m_LoadArray[ i ];
88                         break;
89                     }
90                 }
91                 NN_GR_ASSERT( array != NULL );
92 
93                 array->physicalAddr = physical_addr;
94                 array->type[ 0 ] = type;
95                 array->bind[ 0 ] = bind_reg;
96                 array->byte[ 0 ] = byte;
97 
98                 for ( int i = 1; i < VERTEX_ATTRIBUTE_MAX; ++i )
99                 {
100                     array->bind[ i ] = -1;
101                     array->byte[ i ] = 0;
102                 }
103 
104                 // キャッシュの無効化
105                 m_CmdCacheVertexNum = 0;
106             }
107 
108             //------------------------------------------------------------------------
109 
EnableAttrAsConst(const BindSymbolVSInput & symbol,const u8 dimension,const f32 param[])110             void Vertex::EnableAttrAsConst( const BindSymbolVSInput& symbol,
111                                             const u8  dimension,
112                                             const f32 param[] )
113             {
114                 const u32 bind_reg = symbol.start;
115 
116                 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX );
117 
118                 // ほかで設定されている可能性があるので無効化しておく
119                 DisableAttr_( bind_reg );
120 
121                 m_IsEnableReg[ bind_reg ] = true;
122                 m_AttrConst[ bind_reg ].dimension = dimension;
123 
124                 f32 defaultParam[ 4 ] = { 0.f, 0.f, 0.f, 1.f };
125                 for ( int i = 0; i < 4; ++i )
126                 {
127                     m_AttrConst[ bind_reg ].param[ i ] = i < dimension ? param[ i ] : defaultParam[ i ];
128                 }
129 
130                 // キャッシュの無効化
131                 m_CmdCacheVertexNum = 0;
132             }
133 
134             //------------------------------------------------------------------------
135 
EnableInterleavedArray(const nn::gr::CTR::Vertex::InterleaveInfo & interleave_info,const u32 physical_addr)136             void Vertex::EnableInterleavedArray( const nn::gr::CTR::Vertex::InterleaveInfo& interleave_info, const u32 physical_addr )
137             {
138                 // 空いているストリームを探す
139                 LoadArray* array = NULL;
140                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
141                 {
142                     if ( m_LoadArray[ i ].IsEnable() == false )
143                     {
144                         array = &m_LoadArray[ i ];
145                         break;
146                     }
147                 }
148                 NN_GR_ASSERT( array != NULL );
149 
150                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
151                 {
152                     if ( interleave_info.symbol[ i ] == NULL )
153                     {
154                         array->bind[ i ] = -1;
155                     }
156                     else
157                     {
158                         array->bind[ i ] = interleave_info.symbol[ i ]->start;
159                         array->physicalAddr = physical_addr;
160                     }
161 
162                     array->type[ i ] = interleave_info.dataType[ i ];
163 
164                     array->byte[ i ] = i < interleave_info.dataNum ? PicaDataVertexAttrTypeToByteSize( array->type[ i ] ) : 0;
165                 }
166 
167                 // キャッシュの無効化
168                 m_CmdCacheVertexNum = 0;
169             }
170 
171             //------------------------------------------------------------------------
172 
DisableAttr_(const u32 bind_reg)173             void Vertex::DisableAttr_( const u32 bind_reg )
174             {
175                 NN_GR_ASSERT( bind_reg < VERTEX_ATTRIBUTE_MAX );
176 
177                 // すでに無効化されていたら何もしない
178                 if ( !m_IsEnableReg[ bind_reg ] ) return;
179 
180                 // キャッシュの無効化
181                 m_CmdCacheVertexNum = 0;
182 
183                 if ( m_AttrConst[ bind_reg ].IsEnable() )
184                 {
185                     // 固定頂点属性の無効化
186                     m_AttrConst[ bind_reg ].Disable();
187 
188                     m_IsEnableReg[ bind_reg ] = false;
189                     return;
190                 }
191 
192 
193                 // ロードアレイの中を探しながら無効化
194                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
195                 {
196                     if ( ! m_LoadArray[ i ].IsEnable() ) continue;
197 
198                     for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j )
199                     {
200                         if ( m_LoadArray[ i ].bind[ j ] != bind_reg ) continue;
201 
202                         m_LoadArray[ i ].bind[ j ] = -1;
203                         m_IsEnableReg[ bind_reg ] = false;
204 
205                         // 無効化できた場合、ロードアレイ自体が無効化できないか調べる
206                         m_LoadArray[ i ].CheckDisable();
207 
208                         return;
209                     }
210                 }
211 
212                 NN_GR_ASSERT( m_IsEnableReg[ bind_reg ] == false );
213             }
214 
215             //------------------------------------------------------------------------
216 
CheckDisable()217             void Vertex::LoadArray::CheckDisable()
218             {
219                 // 無効化されているなら、特に何もしない
220                 if ( !IsEnable() ) return;
221 
222                 // 有効化されている場合、中身がすべて無効なら無効化する
223                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
224                 {
225                     if ( bind[ i ] != -1 ) return;
226                 }
227 
228                 physicalAddr = 0;
229                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
230                 {
231                     byte[ i ] = 0;
232                 }
233             }
234 
235             //------------------------------------------------------------------------
236 
MakeEnableAttrCommand_(u32 * command) const237             u32* Vertex::MakeEnableAttrCommand_( u32* command ) const
238             {
239             // #define NN_GR_VERTEX_DUMP
240             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
241                 u32 * start = command;
242             #endif
243 
244                 // 頂点シェーダーの入力レジスタ数を設定
245                 u32* reg0x2b9 = command++;// = vtx_attr_num | 0xa0000000;
246                 *command++ = 0x000b02b9;
247                 u32* reg0x242 = command++;// = vtx_attr_num;
248                 *command++ = 0x00010242;
249 
250                 // bind_reg_mapの設定
251                 u32* bind_reg_command = command;
252                 *command++ = 0;
253                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP0 );
254                 *command++ = 0;
255                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP1 );
256 
257                 // 頂点属性の設定ヘッダー部分
258                 u32* type = &command[ 2 ];
259                 u32& fixed_attr_mask = command[ 3 ];
260                 *command++ = scBaseAddr;
261                 u32* headerBaseAddr = command++; // = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * m_AttrArrayNum );
262                 *command++ = 0;
263                 u32* reg0x202 = command++; // vtx_attr_num << 28;
264 
265                 int input_index = 0;
266                 int array_num = 0;
267                 for ( int i = 0; i < VERTEX_ATTRIBUTE_MAX; ++i )
268                 {
269                     const LoadArray& vtx_array = m_LoadArray[ i ];
270 
271                     if ( !vtx_array.IsEnable() ) continue;
272 
273                     ++array_num;
274                     int total_byte = 0;
275                     int elem_num = 0;
276                     int elem[ 2 ] = { 0, 0 };
277                     for ( int j = 0; j < VERTEX_ATTRIBUTE_MAX; ++j )
278                     {
279                         if ( vtx_array.byte[ j ] == 0 ) break;
280                         total_byte += vtx_array.byte[ j ];
281 
282                         if ( vtx_array.bind[ j ] >= 0 )
283                         {
284                             elem[ j / 8 ] |= input_index << ( 4 * ( j % 8 ) );
285                             type[ input_index / 8 ] |= vtx_array.type[ j ] << ( 4 * ( input_index % 8 ) );
286                             bind_reg_command[ ( input_index >> 3 ) << 1 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) );
287                             bind_reg_command[ ( input_index >> 3 ) << 1 ] |= vtx_array.bind[ j ] << ( 4 * ( input_index % 8 ) );
288                             ++input_index;
289                             ++elem_num;
290 
291                             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
292                             NN_LOG( "+ 0x%08x 0x%08x 0x%08x\n", vtx_array.byte[ j ], elem[0], elem[1] );
293                             #endif
294                         }
295                         else
296                         {
297                             elem[ j / 8 ] |= ( ( vtx_array.byte[ j ] >> 2 ) + 0xb ) << ( 4 * ( j % 8 ) );
298 
299                             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
300                             NN_LOG( "- 0x%08x 0x%08x 0x%08x\n",  vtx_array.byte[ j ] >> 2, elem[0], elem[1] );
301                             #endif
302                         }
303                     }
304                     *command++ = vtx_array.physicalAddr  - scBaseAddr * 8;
305                     *command++ = elem[ 0 ];
306                     *command++ = elem[ 1 ] | total_byte << 16 | elem_num << 28;
307                 }
308                 *headerBaseAddr = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 3 + 3 * array_num );
309                 if ( array_num % 2 ) *command++ = 0;
310 
311                 // 固定頂点のセットアップ
312                 for ( int bind_reg = VERTEX_ATTRIBUTE_MAX-1; bind_reg >= 0; --bind_reg )
313                 {
314                     const AttrConst& vtxConst = m_AttrConst[ bind_reg ];
315 
316                     if ( !vtxConst.IsEnable() ) continue;
317                     *command++ = input_index;
318                     // 0x232
319                     *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FIXED_ATTR , 4 );
320                     *command++ = ( ( Float32ToFloat24( vtxConst.param[3] ) <<  8 ) & 0xffffff00 ) | ( ( Float32ToFloat24( vtxConst.param[2] ) >> 16 ) & 0x000000ff );
321                     *command++ = ( ( Float32ToFloat24( vtxConst.param[2] ) << 16 ) & 0xffff0000 ) | ( ( Float32ToFloat24( vtxConst.param[1] ) >>  8 ) & 0x0000ffff );
322                     *command++ = ( ( Float32ToFloat24( vtxConst.param[1] ) << 24 ) & 0xff000000 ) | ( ( Float32ToFloat24( vtxConst.param[0] ) >>  0 ) & 0x00ffffff );
323                     *command++ = 0; // padding
324 
325                     bind_reg_command[ ( input_index / 8 ) * 2 ] &= ~( 0xf << ( 4 * ( input_index % 8 ) ) );
326                     bind_reg_command[ ( input_index / 8 ) * 2 ] |= bind_reg << ( 4 * ( input_index % 8 ) );
327 
328                     fixed_attr_mask |= ( 1 << input_index + 16 );
329                     ++input_index;
330                 }
331                 // 0x2b9
332                 *reg0x2b9  = (input_index - 1) | 0xa0000000;
333                 // 0x242
334                 *reg0x242  = input_index - 1;
335                 // 0x202
336                 *reg0x202 |= (input_index - 1) << 28;
337 
338             #if defined( NN_GR_VERTEX_DUMP ) // デバッグ用
339                 static int a = 0;
340                 if ( ++a == 1 )
341                 {
342                     for ( u32* i = start; i != command; i +=2 )
343                     {
344                         NN_LOG( "0x%08x 0x%08x\n", *i, *(i+1) );
345                     }
346                 }
347             #endif
348 
349                 return command;
350             }
351 
352         }  // namespace CTR
353     }  // namespace gr
354 } // namespace nn
355