1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     gr_Utility.h
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 #ifndef NN_GR_UTILITY_H_
17 #define NN_GR_UTILITY_H_
18 
19 #include <nn.h>
20 #include <nn/types.h>
21 #include <nn/gx.h>
22 #include <nn/gx/CTR/gx_CommandAccess.h>
23 
24 #include <nn/gr/CTR/gr_Prefix.h>
25 
26 namespace nn
27 {
28     namespace gr
29     {
30         namespace CTR
31         {
32 
33             //------------------------------------------------------------------------------
34 
35             /*!
36                 @brief 3x4行列をwHzyxの順に逆転してコピーします。(ヘッダーあり)
37 
38                 @param[in] dst 結果を書き込む先のポインタです。
39                 @param[in] src 34行列です。
40                 @param[in] header ヘッダです。
41             */
42             void CopyMtx34WithHeader(
43                 f32*  dst,
44                 const nn::math::MTX34* src,
45                 u32   header );
46 
47             /*!
48                 @brief 4x4行列をwHzyxの順に逆転してコピーします。(ヘッダーあり)
49 
50                 @param[in] dst 結果を書き込む先のポインタです。
51                 @param[in] src 44行列です。
52                 @param[in] header ヘッダです。
53             */
54             void CopyMtx44WithHeader(
55                 f32* dst,
56                 const nn::math::MTX44* src,
57                 u32 header );
58 
59             //------------------------------------------------------------------------------------
60 
61             /*!
62                  @brief 34行列を頂点シェーダのユニフォームにセットするコマンドを生成します。
63 
64                  @param[in] command      描画コマンドの書き込み先の先頭アドレスです。
65                  @param[in] location     レジスタの場所です。
66                  @param[in] mtx34        34行列です。
67 
68                  @return    書き込まれた描画コマンドの終端の次のアドレスを返します。
69              */
MakeUniformCommandVS(u32 * command,u8 location,const nn::math::MTX34 & mtx34)70             inline u32* MakeUniformCommandVS( u32* command, u8 location, const nn::math::MTX34& mtx34 )
71             {
72                 *command++ = 0x80000000 | location;
73                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_FLOAT_ADDR );
74                 CopyMtx34WithHeader( (f32*)command, &mtx34, PICA_CMD_HEADER_VS_F32( 3 ) );
75                 return command + 14;
76             }
77 
78             //------------------------------------------------------------------------------------
79 
80             /*!
81                 @brief 44行列を頂点シェーダのユニフォームにセットするコマンドを生成します。
82 
83                 @param[in] command      描画コマンドの書き込み先の先頭アドレスです。
84                 @param[in] location     レジスタの場所です。
85                 @param[in] mtx44        44行列です。
86 
87                 @return    書き込まれた描画コマンドの終端の次のアドレスを返します。
88              */
MakeUniformCommandVS(u32 * command,u8 location,const nn::math::MTX44 & mtx44)89             inline u32* MakeUniformCommandVS( u32* command, u8 location, const nn::math::MTX44& mtx44 )
90             {
91                 *command++ = 0x80000000 | location;
92                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_FLOAT_ADDR );
93                 CopyMtx44WithHeader( (f32*)command, &mtx44, PICA_CMD_HEADER_VS_F32( 4 ) );
94                 return command + 18;
95             }
96 
97             //------------------------------------------------------------------------------------
98 
99             /*!
100                 @brief ベクトルを頂点シェーダのユニフォームにセットするコマンドを生成します。
101 
102                 @param[in] command      描画コマンドの書き込み先の先頭アドレスです。
103                 @param[in] location     レジスタの場所です。
104                 @param[in] vec4         4次元のベクトルです。
105 
106                 @return    書き込まれた描画コマンドの終端の次のアドレスを返します。
107              */
MakeUniformCommandVS(u32 * command,u8 location,const nn::math::VEC4 & vec4)108             inline u32* MakeUniformCommandVS( u32* command, u8 location, const nn::math::VEC4& vec4 )
109             {
110                 *command++ = 0x80000000 | location;
111                 *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FLOAT_ADDR, 5 );
112                 *command++ = nn::math::F32AsU32( vec4.w );
113                 *command++ = nn::math::F32AsU32( vec4.z );
114                 *command++ = nn::math::F32AsU32( vec4.y );
115                 *command++ = nn::math::F32AsU32( vec4.x );
116                 return command;
117             }
118 
119 
120             //------------------------------------------------------------------------------------
121 
122             /*!
123                 @brief ベクトルの配列を頂点シェーダのユニフォームにセットするコマンドを生成します。
124 
125                 @param[in] command      描画コマンドの書き込み先の先頭アドレスです。
126                 @param[in] location     レジスタの場所です。
127                 @param[in] vec4         4次元のベクトルの配列です。
128                 @param[in] num          配列のサイズです。
129 
130                 @return    書き込まれた描画コマンドの終端の次のアドレスを返します。
131              */
MakeUniformCommandVS(u32 * command,u8 location,const nn::math::VEC4 vec4[],const int num)132             inline u32* MakeUniformCommandVS( u32* command, u8 location, const nn::math::VEC4 vec4[], const int num )
133             {
134                 *command++ = 0x80000000 | location;
135                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_FLOAT_ADDR );
136                 *command++ = nn::math::F32AsU32( vec4[0].w );
137                 *command++ = PICA_CMD_HEADER_VS_F32( num );
138                 *command++ = nn::math::F32AsU32( vec4[0].z );
139                 *command++ = nn::math::F32AsU32( vec4[0].y );
140                 *command++ = nn::math::F32AsU32( vec4[0].x );
141 
142                 for ( int i = 1; i < num; ++i )
143                 {
144                     *command++ = nn::math::F32AsU32( vec4[i].w );
145                     *command++ = nn::math::F32AsU32( vec4[i].z );
146                     *command++ = nn::math::F32AsU32( vec4[i].y );
147                     *command++ = nn::math::F32AsU32( vec4[i].x );
148                 }
149 
150                 *command++ = 0; // padding
151 
152                 return command;
153             }
154 
155             //------------------------------------------------------------------------------------
156 
157             /*!
158                 @brief 整数を頂点シェーダのユニフォームにセットするコマンドを生成します。
159 
160                 @param[in] command      描画コマンドの書き込み先の先頭アドレスです。
161                 @param[in] location     レジスタの場所です。
162                 @param[in] x            x 座標の値です。
163                 @param[in] y            y 座標の値です。
164                 @param[in] z            z 座標の値です。
165 
166                 @return    書き込まれた描画コマンドの終端の次のアドレスを返します。
167              */
MakeUniformCommandVS(u32 * command,u8 location,u8 x,u8 y,u8 z)168             inline u32* MakeUniformCommandVS( u32* command, u8 location, u8 x, u8 y, u8 z )
169             {
170                 *command++ = PICA_CMD_DATA_VS_INT( x, y, z );
171                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_INT0 + location );
172                 return command;
173             }
174 
175             //------------------------------------------------------------------------------------
176 
177             /*!
178                 @brief 34行列をジオメトリシェーダのユニフォームにセットするコマンドを生成します。
179 
180                 @param[in] command      描画コマンドの書き込み先の先頭アドレスです。
181                 @param[in] location     レジスタの場所です。
182                 @param[in] mtx34        34行列です。
183 
184                 @return    書き込まれた描画コマンドの終端の次のアドレスを返します。
185              */
MakeUniformCommandGS(u32 * command,u8 location,const nn::math::MTX34 & mtx34)186             inline u32* MakeUniformCommandGS( u32* command, u8 location, const nn::math::MTX34& mtx34 )
187             {
188                 *command++ = 0x80000000 | location;
189                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_FLOAT_ADDR );
190                 CopyMtx34WithHeader( (f32*)command, &mtx34, PICA_CMD_HEADER_GS_F32( 3 ) );
191                 return command + 14;
192             }
193 
194             //------------------------------------------------------------------------------------
195 
196             /*!
197                 @brief 44行列をジオメトリシェーダのユニフォームにセットするコマンドを生成します。
198 
199                 @param[in] command      描画コマンドの書き込み先の先頭アドレスです。
200                 @param[in] location     レジスタの場所です。
201                 @param[in] mtx44        44行列です。
202 
203                 @return    書き込まれた描画コマンドの終端の次のアドレスを返します。
204              */
MakeUniformCommandGS(u32 * command,u8 location,const nn::math::MTX44 & mtx44)205             inline u32* MakeUniformCommandGS( u32* command, u8 location, const nn::math::MTX44& mtx44 )
206             {
207                 *command++ = 0x80000000 | location;
208                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_FLOAT_ADDR );
209                 CopyMtx44WithHeader( (f32*)command, &mtx44, PICA_CMD_HEADER_GS_F32( 4 ) );
210                 return command + 18;
211             }
212 
213             //------------------------------------------------------------------------------------
214 
215             /*!
216                 @brief ベクトルをジオメトリシェーダのユニフォームにセットするコマンドを生成します.
217 
218                 @param[in] command      描画コマンドの書き込み先の先頭アドレスです。
219                 @param[in] location     レジスタの場所です。
220                 @param[in] vec4         4次元のベクトルです。
221 
222                 @return    書き込まれた描画コマンドの終端の次のアドレスを返します。
223              */
MakeUniformCommandGS(u32 * command,u8 location,const nn::math::VEC4 & vec4)224             inline u32* MakeUniformCommandGS( u32* command, u8 location, const nn::math::VEC4& vec4 )
225             {
226                 *command++ = 0x80000000 | location;
227                 *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_GS_FLOAT_ADDR, 5 );
228                 *command++ = nn::math::F32AsU32( vec4.w ); // a
229                 *command++ = nn::math::F32AsU32( vec4.z ); // b
230                 *command++ = nn::math::F32AsU32( vec4.y ); // g
231                 *command++ = nn::math::F32AsU32( vec4.x ); // r
232                 return command;
233             }
234 
235             //------------------------------------------------------------------------------------
236 
237             /*!
238                 @brief ベクトルの配列をジオメトリシェーダのユニフォームにセットするコマンドを生成します。
239 
240                 @param[in] command      描画コマンドの書き込み先の先頭アドレスです。
241                 @param[in] location     レジスタの場所です。
242                 @param[in] vec4         4次元のベクトルの配列です。
243                 @param[in] num          配列のサイズです。
244 
245                 @return    書き込まれた描画コマンドの終端の次のアドレスを返します。
246              */
MakeUniformCommandGS(u32 * command,u8 location,const nn::math::VEC4 vec4[],const int num)247             inline u32* MakeUniformCommandGS( u32* command, u8 location, const nn::math::VEC4 vec4[], const int num )
248             {
249                 *command++ = 0x80000000 | location;
250                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_FLOAT_ADDR );
251                 *command++ = nn::math::F32AsU32( vec4[0].w );
252                 *command++ = PICA_CMD_HEADER_GS_F32( num );
253                 *command++ = nn::math::F32AsU32( vec4[0].z );
254                 *command++ = nn::math::F32AsU32( vec4[0].y );
255                 *command++ = nn::math::F32AsU32( vec4[0].x );
256 
257                 for ( int i = 1; i < num; ++i )
258                 {
259                     *command++ = nn::math::F32AsU32( vec4[i].w );
260                     *command++ = nn::math::F32AsU32( vec4[i].z );
261                     *command++ = nn::math::F32AsU32( vec4[i].y );
262                     *command++ = nn::math::F32AsU32( vec4[i].x );
263                 }
264 
265                 *command++ = 0; // padding
266 
267                 return command;
268             }
269 
270             //------------------------------------------------------------------------------------
271 
272             /*!
273                 @brief 整数をジオメトリシェーダのユニフォームにセットするコマンドを生成します。
274 
275                 @param[in] command      描画コマンドの書き込み先の先頭アドレスです。
276                 @param[in] location     レジスタの場所です。
277                 @param[in] x            x 座標の値です。
278                 @param[in] y            y 座標の値です。
279                 @param[in] z            z 座標の値です。
280 
281                 @return    書き込まれた描画コマンドの終端の次のアドレスを返します。
282              */
MakeUniformCommandGS(u32 * command,u8 location,u8 x,u8 y,u8 z)283             inline u32* MakeUniformCommandGS( u32* command, u8 location, u8 x, u8 y, u8 z )
284             {
285                 *command++ = PICA_CMD_DATA_GS_INT( x, y, z );
286                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_INT0 + location );
287                 return command;
288             }
289 
290             //------------------------------------------------------------------------------------
291 
292             /*!
293                 @brief float32 を u8 に変換します。
294 
295                 @param[in] val      変換前の値です。
296 
297                 @return             変換後の値です。
298             */
FloatToUnsignedByte(f32 val)299             inline u8 FloatToUnsignedByte(
300                 f32 val
301                 )
302             {
303                 return ( u8 )( 0.5f + ( val < 0.f ? 0.f : ( 1.f < val ? 1.f : val ) )  * ( 0xff ) );
304             }
305 
306             //------------------------------------------------------------------------------------
307 
308             /*!
309                 @brief float32 を クランプせずに u8 に変換します。
310 
311                 @param[in] val      変換前の値です。
312 
313                 @return             変換後の値です
314             */
FloatToUnsignedByteNoClamp(f32 val)315             inline u8 FloatToUnsignedByteNoClamp(
316                 f32 val
317                 )
318             {
319                 return ( u8 )( 0.5f + val * 0xff );
320             }
321 
322             //------------------------------------------------------------------------------------
323 
324             /*!
325                 @brief float32 から float16 に変換します。
326 
327                 @param[in] val      変換前の値です。
328 
329                 @return             変換後の値です
330             */
Float32ToFloat16(f32 val)331             inline u16 Float32ToFloat16( f32 val )
332             {
333                 static const int bias_ = 128 - (1 << (5 - 1));
334 
335                 u32 uval_ = *(u32*)&val;
336                 int e_ = (uval_ & 0x7fffffff) ? (((uval_ >> 23) & 0xff) - bias_) : 0;
337                 if (e_ >= 0)
338                 {
339                     return ( u16 )( ((uval_ & 0x7fffff) >> (23 - 10)) | (e_ << 10) | ((uval_ >> 31) << (10 + 5)) );
340                 }
341                 return ( u16 )((uval_ >> 31) << (10 + 5));
342             }
343 
344             //------------------------------------------------------------------------------------
345 
346             /*!
347                 @brief float32 から float24 に変換します。
348 
349                 @param[in] val      変換前の値です。
350 
351                 @return             変換後の値です
352             */
Float32ToFloat24(f32 val)353             inline u32 Float32ToFloat24( f32 val )
354             {
355                 static const int bias_ = 128 - (1 << (7 - 1));
356                 u32 uval_   = *(unsigned*)&val;
357                 s32 e_      = (uval_ & 0x7fffffff) ? (((uval_ >> 23) & 0xff) - bias_) : 0;
358 
359                 return e_ >= 0 ? ((uval_ & 0x7fffff) >> (23 - 16)) | (e_ << 16) | ((uval_ >> 31) << (16 + 7)) : ((uval_ >> 31) << (16 + 7));
360             }
361 
362             //------------------------------------------------------------------------------------
363 
364             /*!
365                 @brief float32 から float20 に変換します。
366 
367                 @param[in] val      変換前の値です。
368 
369                 @return             変換後の値です
370             */
Float32ToFloat20(f32 val)371             inline u32 Float32ToFloat20( f32 val )
372             {
373                 static const int bias_ = 128 - (1 << (7 - 1));
374                 u32 uval_   = *(unsigned*)&val;
375                 s32 e_      = (uval_ & 0x7fffffff) ? (((uval_ >> 23) & 0xff) - bias_) : 0;
376 
377                 return e_ >= 0 ? ((uval_ & 0x7fffff) >> (23 - 12)) | (e_ << 12) | ((uval_ >> 31) << (12 + 7)) : ((uval_ >> 31) << (12 + 7));
378             }
379 
380             //------------------------------------------------------------------------------------
381 
382             /*!
383                 @brief float32 から float31 に変換します。
384 
385                 @param[in] val      変換前の値です。
386 
387                 @return             変換後の値です
388             */
Float32ToFloat31(f32 val)389             inline u32 Float32ToFloat31( f32 val )
390             {
391                 unsigned uval_, m_;
392                 int e_;
393                 float f_ = val;
394                 static const int bias_ = 128 - (1 << (7 - 1));
395                 uval_ = *(unsigned*)&f_;
396                 e_ = (uval_ & 0x7fffffff) ? (((uval_ >> 23) & 0xff) - bias_) : 0;
397                 m_ = (uval_ & 0x7fffff) >> (23 - 23);
398                 return e_ >= 0 ? m_ | (e_ << 23) | ((uval_ >> 31) << (23 + 7)) : ((uval_ >> 31) << (23 + 7));
399             }
400 
401             //------------------------------------------------------------------------------------
402 
403             /*!
404                 @brief float32 から 符号なし fixed12 に変換します。
405 
406                 @param[in] val      変換前の値です。
407 
408                 @return             変換後の値です
409             */
Float32ToUnsignedFix12(f32 val)410             inline u32 Float32ToUnsignedFix12( f32 val )
411             {
412                 unsigned v_ = *(unsigned*)&val;
413                 if( val <= 0 || (v_ & 0x7f800000) == 0x7f800000 )
414                     return 0;
415 
416                 unsigned uval_;
417 
418                 val *= 1 << (12 - 0);
419                 if (val >= (1 << 12))
420                     uval_ = (1 << 12) - 1;
421                 else
422                     uval_ = (unsigned)(val);
423 
424                 return uval_;
425             }
426 
427             //------------------------------------------------------------------------------------
428 
429             /*!
430                 @brief float32 から 符号あり fixed12 に変換します。
431 
432                 @param[in] val      変換前の値です。
433 
434                 @return             変換後の値です
435             */
Float32ToFix12(f32 val)436             inline u32 Float32ToFix12( f32 val )
437             {
438                 unsigned v_ = *(unsigned*)&val;
439                 if( val == 0.f || (v_ & 0x7f800000) == 0x7f800000 )
440                     return 0;
441 
442                 int ret;
443 
444                 val *= (1 << (12 - 1));
445 
446                 if( val < 0 )
447                 {
448                     ret = 1 << (12 - 1);
449                     val = -val;
450                 }
451                 else
452                     ret = 0;
453 
454                 if( val >= (1 << (12 - 1)) )
455                     val  = (1 << (12 - 1)) - 1;
456 
457                 ret |= (unsigned)(val);
458                 return ret;
459             }
460 
461             //------------------------------------------------------------------------------------
462 
463             /*!
464                 @brief float32 から fixed13 ( fraction 8) に変換します。
465 
466                 @param[in] val      変換前の値です。
467 
468                 @return             変換後の値です
469             */
Float32ToFix13Fraction8(f32 val)470             inline u32 Float32ToFix13Fraction8( f32 val )
471             {
472                 unsigned v_ = *(unsigned*)&val;
473                 if( val == 0.f || (v_ & 0x7f800000) == 0x7f800000 )
474                     return 0;
475 
476                 val += 0.5f * (1 << 5);
477                 val *= 1 << (13 - 5);
478                 if (val < 0)
479                     val = 0;
480                 else if (val >= (1 << 13))
481                     val = (1 << 13) - 1;
482 
483                 return (val >= (1 << (13 - 1))) ? (unsigned)(val - (1 << (13 - 1))) : (unsigned)(val + (1 << (13 - 1)));
484             }
485 
486             //------------------------------------------------------------------------------------
487 
488             /*!
489                 @brief float32 から fixed11 ( fraction 8) に変換します。
490 
491                 @param[in] val      変換前の値です。
492 
493                 @return             変換後の値です
494             */
Float32ToFix13Fraction11(f32 val)495             inline u32 Float32ToFix13Fraction11( f32 val )
496             {
497                 unsigned v_ = *(unsigned*)&val;
498                 if( val == 0.f || (v_ & 0x7f800000) == 0x7f800000 )
499                     return 0;
500 
501                 val += 0.5f * (1 << 2);
502                 val *= 1 << (13 - 2);
503                 if (val < 0)
504                     val = 0;
505                 else if (val >= (1 << 13))
506                     val = (1 << 13) - 1;
507 
508                 return (val >= (1 << (13 - 1))) ? (unsigned)(val - (1 << (13 - 1))) : (unsigned)(val + (1 << (13 - 1)));
509             }
510 
511             //------------------------------------------------------------------------------------
512 
513             /*!
514                 @brief float32 から 符号無し fixed11 に変換します。
515             */
Float32ToUnsignedFix11(f32 val)516             inline u32 Float32ToUnsignedFix11( f32 val )
517             {
518                 unsigned v_ = *(unsigned*)&val;
519                 if( val <= 0 || (v_ & 0x7f800000) == 0x7f800000 )
520                     return 0;
521 
522                 unsigned uval_;
523 
524                 val *= 1 << (11 - 0);
525                 if (val >= (1 << 11))
526                     uval_ = (1 << 11) - 1;
527                 else
528                     uval_ = (unsigned)(val);
529 
530                 return uval_;
531             }
532 
533             //------------------------------------------------------------------------------------
534 
535             /*!
536                 @brief 頂点配列の型から、バイトサイズを求めます。
537 
538                 @param[in] type      頂点配列の型です。
539 
540                 @return             バイトサイズです。
541             */
PicaDataVertexAttrTypeToByteSize(const PicaDataVertexAttrType type)542             inline u32 PicaDataVertexAttrTypeToByteSize( const PicaDataVertexAttrType type )
543             {
544                 switch ( type )
545                 {
546                     case PICA_DATA_SIZE_1_BYTE          : return 1 * sizeof(  s8 );
547                     case PICA_DATA_SIZE_1_UNSIGNED_BYTE : return 1 * sizeof(  u8 );
548                     case PICA_DATA_SIZE_1_SHORT         : return 1 * sizeof( s16 );
549                     case PICA_DATA_SIZE_1_FLOAT         : return 1 * sizeof( f32 );
550                     case PICA_DATA_SIZE_2_BYTE          : return 2 * sizeof(  s8 );
551                     case PICA_DATA_SIZE_2_UNSIGNED_BYTE : return 2 * sizeof(  u8 );
552                     case PICA_DATA_SIZE_2_SHORT         : return 2 * sizeof( s16 );
553                     case PICA_DATA_SIZE_2_FLOAT         : return 2 * sizeof( f32 );
554                     case PICA_DATA_SIZE_3_BYTE          : return 3 * sizeof(  s8 );
555                     case PICA_DATA_SIZE_3_UNSIGNED_BYTE : return 3 * sizeof(  u8 );
556                     case PICA_DATA_SIZE_3_SHORT         : return 3 * sizeof( s16 );
557                     case PICA_DATA_SIZE_3_FLOAT         : return 3 * sizeof( f32 );
558                     case PICA_DATA_SIZE_4_BYTE          : return 4 * sizeof(  s8 );
559                     case PICA_DATA_SIZE_4_UNSIGNED_BYTE : return 4 * sizeof(  u8 );
560                     case PICA_DATA_SIZE_4_SHORT         : return 4 * sizeof( s16 );
561                     case PICA_DATA_SIZE_4_FLOAT         : return 4 * sizeof( f32 );
562                 }
563                 return 0;
564             }
565 
566         } // namespace CTR
567     } // namespace gr
568 } // namespace nn
569 
570 #endif // NN_GR_UTILITY_H_
571