1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ShaderBinaryInfo.h
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  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   $Revision: 28011 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NW_GFX_SHADERBINARYINFO_H_
17 #define NW_GFX_SHADERBINARYINFO_H_
18 
19 #include <GLES2/gl2.h>
20 #include <GLES2/gl2ext.h>
21 
22 #include <nw/types.h>
23 #include <nw/ut/ut_Inlines.h>
24 #include <nw/gfx/gfx_CommandUtil.h>
25 
26 // シェーダバイナリの解析等のシェーダ用のドライバ層です。
27 
28 namespace nw
29 {
30 namespace gfx
31 {
32 
33 //---------------------------------------------------------------------------
34 //! @brief        シェーダバイナリを解析し、コマンドの生成等の処理をおこなうクラスです。
35 //---------------------------------------------------------------------------
36 class ShaderBinaryInfo
37 {
38 private:
39     class SafeBuffer;
40 
41 public:
42     // シンボルの型
43     enum SymbolType
44     {
45         SYMBOL_TYPE_INVALID,  //!< 不正な型。
46         SYMBOL_TYPE_INPUT,    //!< 頂点属性。(v0 ... v15)
47         SYMBOL_TYPE_FLOAT,    //!< 浮動小数定数レジスタ。 (c0 ... c95)
48         SYMBOL_TYPE_INT,      //!< 整数定数レジスタ。(i0 ... i3)
49         SYMBOL_TYPE_BOOL      //!< ブール定数レジスタ。(b0 ... b15)
50     };
51 
52     //---------------------------------------------------------------------------
53     //! @brief        コンストラクタです。
54     //!
55     //! @param[in]    shaderBinary シェーダバイナリへのポインタです。
56     //---------------------------------------------------------------------------
ShaderBinaryInfo(const void * shaderBinary)57     ShaderBinaryInfo( const void* shaderBinary )
58      : m_pShaderBinary( reinterpret_cast<const u32*>(shaderBinary) ),
59        m_ExeImageCount( 0 ),
60        m_pInstruction( NULL ),
61        m_InstructionCount( 0 ),
62        m_SwizzleCount( 0 ),
63        m_GeometryShaderCount( 0 )
64     {
65         for (int i = 0; i < EXE_IMAGE_MAX; ++i)
66         {
67             m_ExeImageInfo[ i ] = NULL;
68         }
69 
70         // デバッグビルド以外では、m_Swizzle のクリア処理は行なわない。
71     #if defined(NW_DEBUG)
72         for (int i = 0; i < SWIZZLE_PATTERN_MAX; ++i)
73         {
74             m_Swizzle[ i ] = 0;
75         }
76     #endif
77     }
78 
79     //---------------------------------------------------------------------------
80     //! @brief        シェーダバイナリ転送用コマンドのサイズを取得します。
81     //!
82     //! @return       シェーダバイナリ転送用に必要なコマンドサイズです。
83     //---------------------------------------------------------------------------
84     s32 GetCommonCommandSize() const;
85 
86     //---------------------------------------------------------------------------
87     //! @brief        指定したバッファにシェーダバイナリ転送用のコマンドを作成します。
88     //!
89     //! @param[out]   bufferAddress コマンドを生成するバッファのアドレスです。
90     //! @param[in]    bufferSize    バッファの最大サイズです。
91     //!
92     //! @return       出力したコマンドサイズです。
93     //---------------------------------------------------------------------------
94     s32 BuildCommonCommand( u32* bufferAddress, u32 bufferSize ) const;
95 
96     //---------------------------------------------------------------------------
97     //! @brief        カレントのコマンドバッファにシェーダバイナリ転送用のコマンドを
98     //!               作成します。
99     //!
100     //! @return       出力したコマンドサイズです。
101     //---------------------------------------------------------------------------
BuildCommonCommand()102     s32 BuildCommonCommand() const
103     {
104         u32* currentBuffer = static_cast<u32*>( internal::NWGetCurrentCmdBuffer() );
105         u32* cmdBufferEnd  = static_cast<u32*>( internal::NWGetCmdBufferEnd() );
106         u32   bufferSize = ut::GetOffsetFromPtr( currentBuffer, cmdBufferEnd );
107 
108         s32 result = this->BuildCommonCommand( currentBuffer, bufferSize );
109 
110         if ( result > 0 )
111         {
112             internal::NWForwardCurrentCmdBuffer( result );
113         }
114 
115         return result;
116     }
117 
118     //---------------------------------------------------------------------------
119     //! @brief        シェーダプログラム設定用コマンドのサイズを取得します。
120     //!
121     //! @param[in]    vertexIndex    頂点シェーダのインデックスを指定します。
122     //! @param[in]    geometryIndex  ジオメトリシェーダのインデックスを指定します。
123     //!
124     //! @return       シェーダプログラム設定用に必要なコマンドサイズです。
125     //---------------------------------------------------------------------------
126     s32 GetShaderProgramCommandSize( s32 vertexIndex, s32 geometryIndex ) const;
127 
128     //---------------------------------------------------------------------------
129     //! @brief        シェーダプログラム設定用のコマンドを作成します。
130     //!
131     //! @param[in]    vertexIndex    頂点シェーダのインデックスを指定します。
132     //! @param[in]    geometryIndex  ジオメトリシェーダのインデックスを指定します。
133     //! @param[out]   bufferAddress  コマンドを生成するバッファのアドレスです。
134     //! @param[in]    bufferSize     バッファの最大サイズです。
135     //!
136     //! @return       出力したコマンドサイズです。
137     //---------------------------------------------------------------------------
138     s32 BuildShaderProgramCommand( s32 vertexIndex, s32 geometryIndex, u32* bufferAddress, u32 bufferSize ) const;
139 
140     //---------------------------------------------------------------------------
141     //! @brief        指定したバッファにシェーダプログラム設定用のコマンドを作成します。
142     //!
143     //! @param[in]    vertexIndex    頂点シェーダのインデックスです。
144     //! @param[in]    geometryIndex  ジオメトリシェーダのインデックスです。
145     //!
146     //! @return       出力したコマンドサイズです。
147     //---------------------------------------------------------------------------
BuildShaderProgramCommand(s32 vertexIndex,s32 geometryIndex)148     s32 BuildShaderProgramCommand( s32 vertexIndex, s32 geometryIndex ) const
149     {
150         u32* currentBuffer = static_cast<u32*>( internal::NWGetCurrentCmdBuffer() );
151         u32* cmdBufferEnd  = static_cast<u32*>( internal::NWGetCmdBufferEnd() );
152         u32   bufferSize = ut::GetOffsetFromPtr( currentBuffer, cmdBufferEnd );
153 
154         s32 result = this->BuildShaderProgramCommand( vertexIndex, geometryIndex, currentBuffer, bufferSize );
155 
156         if ( result > 0 )
157         {
158             internal::NWForwardCurrentCmdBuffer( result );
159         }
160 
161         return result;
162     }
163 
164     //---------------------------------------------------------------------------
165     //! @name         シェーダプログラムの情報へのアクセサ
166     //@{
167 
168     //---------------------------------------------------------------------------
169     //! @brief        ジオメトリシェーダかどうかを取得します。
170     //!
171     //! @param[in]    shaderIndex シェーダインデックスです。
172     //!
173     //! @return       指定したシェーダがジオメトリシェーダであれば true を返します。
174     //---------------------------------------------------------------------------
IsGeometryShader(s32 shaderIndex)175     bool IsGeometryShader(s32 shaderIndex) const
176     {
177         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
178 
179         return exeInfo->isGeometryShader ? true : false;
180     }
181 
182     //---------------------------------------------------------------------------
183     //! @brief        頂点ユニフォームインデックスを取得します。
184     //!
185     //! @param[in]    shaderIndex シェーダインデックスです。
186     //! @param[in]    name        頂点ユニフォームの名前です。
187     //!
188     //! @return       対応する頂点インデックスと型情報の組み合わせを取得します。
189     //---------------------------------------------------------------------------
190     // NOTE: コンパイラの不具合で、pair が正しく返せない場合があるので、noinline にしておく。
191     __declspec(noinline) ::std::pair<s32, SymbolType>
SearchUniformIndex(s32 shaderIndex,const char * name)192     SearchUniformIndex(s32 shaderIndex, const char* name) const
193     {
194         enum { BEGIN_INPUT = 0, BEGIN_FLOAT = 16, BEGIN_INT = 112, BEGIN_BOOL = 120, END_SYMBOL = 136 };
195 
196         // 出力属性情報
197         struct BindSymbolInfo
198         {
199             u32 nameIndex;
200             u32 regIndex;
201         };
202 
203         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
204 
205         const BindSymbolInfo* bindSymbolInfoTable = static_cast<const BindSymbolInfo*>( ut::AddOffsetToPtr(exeInfo, exeInfo->bindSymbolOffset) );
206         const char* stringTable = static_cast<const char*>( ut::AddOffsetToPtr(exeInfo, exeInfo->stringOffset) );
207 
208         SymbolType symbolType  = SYMBOL_TYPE_INVALID;
209         s32        symbolIndex = -1;
210 
211         u32 nameLen = std::strlen( name );
212         for (int i = 0; i < static_cast<int>(exeInfo->bindSymbolCount); ++i)
213         {
214             const BindSymbolInfo& info = bindSymbolInfoTable[ i ];
215 
216             const char* symbolName = &stringTable[ info.nameIndex ];
217 
218             if ( std::strncmp( name, symbolName, nameLen ) != 0 ) { continue; }
219             if ( symbolName[ nameLen ] != '\0' && symbolName[ nameLen ] != '.' ) { continue; }
220 
221             symbolIndex = static_cast<s32>( info.regIndex & 0x0000ffff );
222 
223             if ( END_SYMBOL <= symbolIndex )      { symbolIndex = -1; }
224             else if (BEGIN_BOOL <= symbolIndex  ) { symbolType = SYMBOL_TYPE_BOOL;  symbolIndex = symbolIndex - BEGIN_BOOL;  }
225             else if (BEGIN_INT <= symbolIndex   ) { symbolType = SYMBOL_TYPE_INT;   symbolIndex = symbolIndex - BEGIN_INT;   }
226             else if (BEGIN_FLOAT <= symbolIndex ) { symbolType = SYMBOL_TYPE_FLOAT; symbolIndex = symbolIndex - BEGIN_FLOAT; }
227             else                                  { symbolType = SYMBOL_TYPE_INPUT; symbolIndex = symbolIndex; }
228 
229             break;
230         }
231 
232         return std::make_pair(symbolIndex, symbolType);
233     }
234 
235     //---------------------------------------------------------------------------
236     //! @brief        頂点ユニフォームインデックスを取得します。
237     //!
238     //! @param[in]    shaderIndex シェーダインデックスです。
239     //! @param[in]    symbolType  レジスタの種類です。
240     //! @param[in]    index       レジスタのインデックスです。
241     //!
242     //! @return       対応する頂点インデックスとジオメトリシェーダフラグの組み合わせを取得します。
243     //---------------------------------------------------------------------------
244     const char*
SearchUniformIndex(s32 shaderIndex,SymbolType symbolType,s32 index)245     SearchUniformIndex(s32 shaderIndex, SymbolType symbolType, s32 index) const
246     {
247         enum { BEGIN_INPUT = 0, BEGIN_FLOAT = 16, BEGIN_INT = 112, BEGIN_BOOL = 120, END_SYMBOL = 136 };
248 
249         // 出力属性情報
250         struct BindSymbolInfo
251         {
252             u32 nameIndex;
253             u32 regIndex;
254         };
255 
256         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
257 
258         const BindSymbolInfo* bindSymbolInfoTable
259             = static_cast<const BindSymbolInfo*>( ut::AddOffsetToPtr( exeInfo, exeInfo->bindSymbolOffset ) );
260         const char* stringTable = static_cast<const char*>( ut::AddOffsetToPtr( exeInfo, exeInfo->stringOffset ) );
261 
262         s32 targetIndex = 0;
263 
264         switch ( symbolType )
265         {
266         case SYMBOL_TYPE_INPUT: { targetIndex = BEGIN_INPUT + index; } break;
267         case SYMBOL_TYPE_FLOAT: { targetIndex = BEGIN_FLOAT + index; } break;
268         case SYMBOL_TYPE_INT  : { targetIndex = BEGIN_INT   + index; } break;
269         case SYMBOL_TYPE_BOOL : { targetIndex = BEGIN_BOOL  + index; } break;
270         default: NW_FATAL_ERROR("Unknown symbolType");
271         }
272 
273         for (int i = 0; i < static_cast<int>(exeInfo->bindSymbolCount); ++i)
274         {
275             const BindSymbolInfo& info = bindSymbolInfoTable[ i ];
276 
277             s32 symbolIndex = static_cast<s32>( info.regIndex & 0x0000ffff );
278 
279             if (symbolIndex == targetIndex)
280             {
281                 return &stringTable[ info.nameIndex ];
282             }
283         }
284 
285         return NULL;
286     }
287 
288     //---------------------------------------------------------------------------
289     //! @brief        トータルのシンボル数を取得します。
290     //!
291     //! @param[in]    shaderIndex シェーダインデックスです。
292     //! @param[in]    symbolType  レジスタの種類です。
293     //!
294     //! @return       入力タイプ
295     //---------------------------------------------------------------------------
SearchBinadSymbolCount(s32 shaderIndex,SymbolType symbolType)296     int SearchBinadSymbolCount(s32 shaderIndex, SymbolType symbolType) const
297     {
298         enum
299         {
300             BEGIN_INPUT = 0,   END_INPUT = 15,
301             BEGIN_FLOAT = 16,  END_FLOAT = 111,
302             BEGIN_INT   = 112, END_INT   = 119,
303             BEGIN_BOOL  = 120, END_BOOL  = 135,
304             END_SYMBOL  = 136
305         };
306 
307         // 出力属性情報
308         struct BindSymbolInfo
309         {
310             u32 nameIndex;
311             u32 regIndex;
312         };
313 
314         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
315 
316         const BindSymbolInfo* bindSymbolInfoTable =
317             static_cast<const BindSymbolInfo*>(
318                 ut::AddOffsetToPtr( exeInfo, exeInfo->bindSymbolOffset )
319             );
320 
321         s32 count = 0;
322 
323         for (int i = 0; i < static_cast<int>(exeInfo->bindSymbolCount); ++i)
324         {
325             const BindSymbolInfo& info = bindSymbolInfoTable[ i ];
326 
327             s32 symbolIndex = static_cast<s32>( info.regIndex & 0x0000ffff );
328 
329             switch ( symbolType )
330             {
331             case SYMBOL_TYPE_INPUT:
332                 if (BEGIN_INPUT <= symbolIndex && symbolIndex <= END_INPUT)
333                 {
334                     ++count;
335                 }
336                 break;
337             case SYMBOL_TYPE_FLOAT:
338                 if (BEGIN_FLOAT <= symbolIndex && symbolIndex <= END_FLOAT)
339                 {
340                     ++count;
341                 }
342                 break;
343             case SYMBOL_TYPE_INT:
344                 if (BEGIN_INT <= symbolIndex && symbolIndex <= END_INT)
345                 {
346                     ++count;
347                 }
348                 break;
349             case SYMBOL_TYPE_BOOL:
350                 if (BEGIN_BOOL <= symbolIndex && symbolIndex <= END_BOOL)
351                 {
352                     ++count;
353                 }
354                 break;
355             default: NW_FATAL_ERROR("Unknown symbolType");
356             }
357         }
358 
359         return count;
360     }
361 
362 
363     //---------------------------------------------------------------------------
364     //! @brief        頂点 bool レジスタの定数値を取得します。
365     //!
366     //! @param[in]    shaderIndex シェーダインデックスです。
367     //!
368     //! @return       対応するシェーダプログラムの定数 bool 値を取得します。
369     //---------------------------------------------------------------------------
GetBoolConstant(s32 shaderIndex)370     u32 GetBoolConstant(s32 shaderIndex) const
371     {
372         enum { TYPE_BOOL = 0, TYPE_INT = 1, TYPE_FLOAT = 2 };
373 
374         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
375 
376         // 定数レジスタ情報
377         struct SetupInfo
378         {
379             u16 type;
380             u16 index;
381             u32 value[4];
382         };
383 
384         const SetupInfo* setupInfoTable =
385             static_cast<const SetupInfo*>( ut::AddOffsetToPtr( exeInfo, exeInfo->setupOffset) );
386 
387         u32 boolMap = 0;
388 
389         for ( int i = 0; i < static_cast<int>(exeInfo->setupCount); ++i )
390         {
391             const SetupInfo& info = setupInfoTable[ i ];
392             const u32* value = info.value;
393 
394             if (info.type == TYPE_BOOL)
395             {
396                 boolMap |= (value[ 0 ] & 0x1) << info.index;
397             }
398         }
399 
400         return boolMap;
401     }
402 
403     //---------------------------------------------------------------------------
404     //! @brief        シェーダのアトリビュート数を取得します。
405     //!
406     //! @param[in]    shaderIndex シェーダインデックスです。
407     //!
408     //! @return       対応するシェーダプログラムのアトリビュート数を取得します。
409     //---------------------------------------------------------------------------
GetInputRegisterNum(s32 shaderIndex)410     u32 GetInputRegisterNum(s32 shaderIndex) const
411     {
412         enum { MAX_INPUT = 16 }; // ジオメトリシェーダは 16まで。
413 
414         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo( shaderIndex );
415 
416         u32 mask = exeInfo->inputMask;
417         s32 count = 0;
418 
419         for (int i = 0; i < 16; ++i)
420         {
421             if (mask & (1 << i))
422             {
423                 ++count;
424             }
425         }
426 
427         return count;
428     }
429 
430     //---------------------------------------------------------------------------
431     //! @brief        シェーダの出力数を取得します。
432     //!
433     //! @param[in]    shaderIndex シェーダインデックスです。
434     //!
435     //! @return       対応するシェーダプログラムの入力数を取得します。
436     //---------------------------------------------------------------------------
GetOutputRegisterNum(s32 shaderIndex)437     u32 GetOutputRegisterNum(s32 shaderIndex) const
438     {
439         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
440 
441         u32 mask = exeInfo->outputMask;
442         s32 count = 0;
443 
444         for (int i = 0; i < 16; ++i)
445         {
446             if (mask & (1 << i))
447             {
448                 ++count;
449             }
450         }
451 
452         return count;
453     }
454 
455     //---------------------------------------------------------------------------
456     //! @brief        頂点シェーダの出力レジスタ数を取得します。
457     //!
458     //! @param[in]    shaderIndex シェーダインデックスです。
459     //! @param[in]    pNum    出力レジスタ数を取得する為のポインタです。
460     //! @param[in]    pMask   出力レジスタマスクを取得する為のポインタです。
461     //---------------------------------------------------------------------------
GetOutputRegisterNum(s32 shaderIndex,u32 * pNum,u32 * pMask)462     void GetOutputRegisterNum(s32 shaderIndex, u32* pNum, u32* pMask) const
463     {
464         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
465 
466         u32 mask = exeInfo->outputMask;
467         s32 count = 0;
468 
469         for (int i = 0; i < 16; ++i)
470         {
471             if (mask & (1 << i))
472             {
473                 ++count;
474             }
475         }
476 
477         if (pNum)  { *pNum  = u32(count); }
478         if (pMask) { *pMask = u32(mask); }
479     }
480 
481     //---------------------------------------------------------------------------
482     //! @brief        シェーダの出力レジスタ数を取得します。
483     //!
484     //! @param[in]    vertexIndex 頂点シェーダーのインデックスです。
485     //! @param[in]    geometryIndex ジオメトリシェーダーのインデックスです。
486     //! @param[in]    pNum    出力レジスタ数を取得する為のポインタです。
487     //! @param[in]    pMask   出力レジスタマスクを取得する為のポインタです。
488     //---------------------------------------------------------------------------
GetShaderOutputRegisterNum(s32 vertexIndex,s32 geometryIndex,u32 * pNum,u32 * pMask)489     void GetShaderOutputRegisterNum(s32 vertexIndex, s32 geometryIndex, u32* pNum, u32* pMask) const
490     {
491         const ExeImageInfo* exeInfo = NULL;
492 
493         if (geometryIndex >= 0)
494         {
495             exeInfo= this->GetShaderProgramInfo(geometryIndex);
496         }
497         else
498         {
499             exeInfo = this->GetShaderProgramInfo(vertexIndex);
500         }
501 
502         NW_NULL_ASSERT( exeInfo );
503 
504         u32 mask = exeInfo->outputMask;
505         s32 count = 0;
506 
507         for (int i = 0; i < 16; ++i)
508         {
509             if (mask & (1 << i))
510             {
511                 ++count;
512             }
513         }
514 
515         if (pNum)  { *pNum  = u32(count); }
516         if (pMask) { *pMask = u32(mask); }
517     }
518 
519     //---------------------------------------------------------------------------
520     //! @brief        シェーダの出力レジスタフォーマットを取得します。
521     //!
522     //! @param[in]    vertexIndex 頂点シェーダーのインデックスです。
523     //! @param[in]    geometryIndex ジオメトリシェーダーのインデックスです。
524     //! @param[in]    pOutputFormat  シェーダの出力レジスタマップを取得する為の
525     //!                              サイズ7の配列へのポインタです。
526     //---------------------------------------------------------------------------
GetShaderOutputRegisterMap(s32 vertexIndex,s32 geometryIndex,u32 pOutputFormat[7])527     void GetShaderOutputRegisterMap(s32 vertexIndex, s32 geometryIndex, u32 pOutputFormat[7]) const
528     {
529         // とりあえず tugal から移植しました。要確認。
530 
531         enum { OUT_ATTR_INDEX_MAX = 7, OUT_ATTR_DIMENTION_MAX = 4, VS_OUT_ATTR_INDEX_MAX = 16 };
532 
533         u32 outNum  = 0;
534         u32 useTex  = 0;
535         u32 clock   = 0;
536         u32 outMask = 0;
537 
538         NW_UNUSED_VARIABLE( useTex );
539 
540         // 出力属性情報
541         struct OutmapInfo
542         {
543             u16 type;
544             u16 index;
545             u16 mask;
546             u16 reserve;
547         };
548 
549         enum { OUTPUT_REG_NUM = 7 };
550         const ExeImageInfo* exeInfo = NULL;
551 
552         if (geometryIndex >= 0)
553         {
554             exeInfo = this->GetShaderProgramInfo(geometryIndex);
555         }
556         else
557         {
558             exeInfo = this->GetShaderProgramInfo(vertexIndex);
559         }
560 
561         NW_NULL_ASSERT( exeInfo );
562 
563         const OutmapInfo* outmapInfoTable = static_cast<const OutmapInfo*>( ut::AddOffsetToPtr( exeInfo, exeInfo->outmapOffset ) );
564 
565         if ( pOutputFormat )
566         {
567             for ( int outputIndex = 0; outputIndex < OUTPUT_REG_NUM; ++outputIndex )
568             {
569                 pOutputFormat[ outputIndex ] = 0x1f1f1f1f;
570 
571                 for ( int i = 0; i < static_cast<int>(exeInfo->outmapCount); ++i )
572                 {
573                     u32 c = 0;
574                     const OutmapInfo& outmapInfo = outmapInfoTable[ i ];
575 
576                     for ( int j = 0; outmapInfo.index == outputIndex && j <  OUT_ATTR_DIMENTION_MAX; ++j )
577                     {
578                         if ( ( outmapInfo.mask & ( 1 << j ) ) == 0 ) { continue; }
579 
580                         int value = 0x1f;
581                         switch ( outmapInfo.type )
582                         {
583                         case 0 :
584                             {
585                                 value = 0x00 + c++;
586                                 if (c == 2) { clock |= 1 <<  0; }
587                             }
588                             break; // position
589                         case 1 :
590                             {
591                                 value = 0x04 + c++;
592                                 clock |= 1 << 24;
593                             }
594                             break; // quaternion
595                         case 2 :
596                             {
597                                 value = 0x08 + c++;
598                                 clock |= 1 <<  1;
599                             }
600                             break; // color
601                         case 3 :
602                             {
603                                 if (c < 2) { value = 0x0c + c++; }
604                                 useTex = 1;
605                                 clock |= 1 <<  8;
606                             }
607                             break; // texcoord0
608                         case 4 :
609                             {
610                                 value = 0x10;
611                                 useTex = 1;
612                                 clock |= 3 << 16;
613                             }
614                             break; // texcoord0w
615                         case 5 :
616                             {
617                                 if (c < 2) { value = 0x0e + c++; }
618                                 useTex = 1;
619                                 clock |= 1 <<  9;
620                             }
621                             break; // texcoord1
622                         case 6 :
623                             {
624                                 if (c < 2) { value = 0x16 + c++; }
625                                 useTex = 1;
626                                 clock |= 1 << 10;
627                             }
628                             break; // texcoord2
629                         case 8 :
630                             {
631                                 if (c < 3) { value = 0x12 + c++; }
632                                 clock |= 1 << 24;
633                             }
634                             break; // view
635                         }
636 
637                         pOutputFormat[ outputIndex ] = pOutputFormat[ outputIndex ] & ~( 0xff << ( j * 8 ) ) | value << ( j * 8 );
638                     }
639                 }
640 
641                 if (pOutputFormat[ outputIndex ] != 0x1f1f1f1f)
642                 {
643                     outMask |= ( 1 << outputIndex );
644                     ++outNum;
645                 }
646             }
647         }
648     }
649 
650     //---------------------------------------------------------------------------
651     //! @brief        頂点シェーダの開始アドレスを取得します。
652     //!
653     //! @param[in]    shaderIndex シェーダインデックスです。
654     //!
655     //! @return       頂点シェーダの開始アドレスです。
656     //---------------------------------------------------------------------------
GetEntryAddress(s32 shaderIndex)657     u32 GetEntryAddress(s32 shaderIndex) const
658     {
659         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
660 
661         return exeInfo->mainAddress;
662     }
663 
664     //---------------------------------------------------------------------------
665     //! @brief        ジオメトリシェーダのデータモードを取得します。
666     //!
667     //! @param[in]    shaderIndex シェーダインデックスです。
668     //!
669     //! @return       ジオメトリシェーダのデータモードです。
670     //---------------------------------------------------------------------------
GetGeometryDataMode(s32 shaderIndex)671     u32 GetGeometryDataMode(s32 shaderIndex) const
672     {
673         NW_ASSERT( this->IsGeometryShader( shaderIndex ) );
674 
675         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
676 
677         return exeInfo->gsDataMode;
678     }
679 
680     //---------------------------------------------------------------------------
681     //! @brief        ジオメトリシェーダの gs_main_vertex_num の値 を取得します。
682     //!
683     //! @param[in]    shaderIndex シェーダインデックスです。
684     //!
685     //! @return       ジオメトリシェーダの gs_main_vertex_num の値です。
686     //---------------------------------------------------------------------------
GetGeometryMainVertexNum(s32 shaderIndex)687     u32 GetGeometryMainVertexNum(s32 shaderIndex) const
688     {
689         NW_ASSERT( this->IsGeometryShader( shaderIndex ) );
690 
691         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
692 
693         return exeInfo->gsPatchSize;
694     }
695 
696     //---------------------------------------------------------------------------
697     //! @brief        ジオメトリシェーダの gs_patch_size の値を取得します。
698     //!
699     //! @param[in]    shaderIndex シェーダインデックスです。
700     //!
701     //! @return       ジオメトリシェーダのスタートインデックスです。
702     //---------------------------------------------------------------------------
GetGeometryPatchSize(s32 shaderIndex)703     u32 GetGeometryPatchSize(s32 shaderIndex) const
704     {
705         NW_ASSERT( this->IsGeometryShader( shaderIndex ) );
706 
707         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
708 
709         return exeInfo->gsVertexNum;
710     }
711 
712     //---------------------------------------------------------------------------
713     //! @brief        ジオメトリシェーダのスタートインデックスを取得します。
714     //!
715     //! @param[in]    shaderIndex シェーダインデックスです。
716     //!
717     //! @return       ジオメトリシェーダのスタートインデックスです。
718     //---------------------------------------------------------------------------
GetGeometryStartIndex(s32 shaderIndex)719     u32 GetGeometryStartIndex(s32 shaderIndex) const
720     {
721         NW_ASSERT( this->IsGeometryShader( shaderIndex ) );
722 
723         const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex);
724 
725         return exeInfo->gsVertexStartIndex;
726     }
727 
728     //@}
729 
730     //---------------------------------------------------------------------------
731     //! @brief        シェーダバイナリの解析をおこないます。
732     //---------------------------------------------------------------------------
733     void AnalyzeBinary();
734 
735 private:
736     enum
737     {
738         EXE_IMAGE_MAX = 32,
739         SWIZZLE_PATTERN_MAX = 128,
740         DUMMY_DATA_NUM_251 = 10,
741         DUMMY_DATA_NUM_200 = 30,
742         PADDING_DATA = 0xead0fead
743     };
744 
745     // シェーダバイナリの実行イメージ情報のヘッダ構造体です。
746     struct ExeImageInfo
747     {
748         u32 signature;
749         u16 version;
750         u8  isGeometryShader;
751         u8  outputMaps;
752         u32 mainAddress;
753         u32 endAddress;
754         u16 inputMask;
755         u16 outputMask;
756         u8  gsDataMode;
757         u8  gsVertexStartIndex;
758         u8  gsPatchSize;
759         u8  gsVertexNum;
760         u32 setupOffset;
761         u32 setupCount;
762         u32 labelOffset;
763         u32 labelCount;
764         u32 outmapOffset;
765         u32 outmapCount;
766         u32 bindSymbolOffset;
767         u32 bindSymbolCount;
768         u32 stringOffset;
769         u32 stringCount;
770     };
771 
772     const u32* m_pShaderBinary;
773     u32        m_ExeImageCount;
774     const ExeImageInfo* m_ExeImageInfo[ EXE_IMAGE_MAX ];
775     const u32* m_pInstruction;
776     u32        m_InstructionCount;
777     u32        m_Swizzle[ SWIZZLE_PATTERN_MAX ];
778     u32        m_SwizzleCount;
779     s32        m_GeometryShaderCount;
780 
781     //---------------------------------------------------------------------------
782     //! @brief        シェーダプログラムの情報を取得します。
783     //!
784     //! @param[in]    shaderIndex シェーダインデックスです。
785     //!
786     //! @return       シェーダプログラム情報を格納した生の構造体を返します。
787     //---------------------------------------------------------------------------
GetShaderProgramInfo(s32 shaderIndex)788     const ExeImageInfo* GetShaderProgramInfo( s32 shaderIndex ) const
789     {
790         NW_ASSERT( 0 <= shaderIndex && shaderIndex < static_cast<s32>(m_ExeImageCount) );
791 
792         return m_ExeImageInfo[ shaderIndex ];
793     }
794 
795     //---------------------------------------------------------------------------
796     //! @brief        シェーダバイナリ中に含んでいる、シェーダの数を取得します。
797     //!               頂点シェーダ、ジオメトリシェーダを含めた数を返します。
798     //!               リンクした main 関数の数と等しくなります。
799     //!
800     //! @return       頂点シェーダとジオメトリシェーダを合わせた数です。
801     //---------------------------------------------------------------------------
GetShaderCount()802     s32 GetShaderCount() const
803     {
804         return m_ExeImageCount;
805     }
806 
807     //---------------------------------------------------------------------------
808     //! @brief        シェーダバイナリ中に含んでいる、ジオメトリシェーダーの数を取得します。
809     //!               0 であれば、このシェーダバイナリでは必ず頂点シェーダのみという事になります。
810     //!
811     //! @return       ジオメトリシェーダの数です。
812     //---------------------------------------------------------------------------
GetGeometryShaderCount()813     s32 GetGeometryShaderCount() const
814     {
815         return m_GeometryShaderCount;
816     }
817 
818     // プログラムロードのコマンド生成
819     void BuildProgramCommand( SafeBuffer& buffer ) const;
820 
821     // Swizzle パターンロードのコマンド生成
822     void BuildSwizzleCommand( SafeBuffer& buffer ) const;
823 
824     // ジオメトリシェーダー使用設定コマンドを生成
825     void BuildPrepareCommand( SafeBuffer& buffer ) const;
826 
827     // 定数レジスタのコマンド生成
828     void BuildConstRegCommand( SafeBuffer& buffer, s32 shaderIndex ) const;
829 
830     // シェーダー出力属性のコマンド生成
831     void BuildOutAttrCommand( SafeBuffer& buffer, s32 vertexIndex, s32 geometryIndex ) const;
832 
833     // プログラムロードのコマンドサイズを取得
834     s32 GetProgramCommandSize() const;
835     // Swizzle パターンロードのコマンドサイズを取得
836     s32 GetSwizzleCommandSize() const;
837     // ジオメトリシェーダー使用設定コマンドサイズを取得
838     s32 GetPrepareCommandSize() const;
839     // 定数レジスタのコマンドサイズを取得
840     s32 GetConstRegCommandSize( s32 shaderIndex ) const;
841     // シェーダー出力属性のコマンドサイズを取得
842     s32 GetOutAttrCommandSize( s32 vertexIndex, s32 geometryIndex ) const;
843 
844     // データ転送コマンドのサイズを取得
845     s32 GetLoadCommandSize( u32 count ) const;
846 
847     //---------------------------------------------------------------------------
848     //! @brief        ポートレジスタに対して大量のデータを書き込みます。
849     //!               128バイト以上のデータも指定可能です。
850     //!
851     //! @param[out]   buffer  コマンド書き込み先のバッファです。
852     //! @param[in]    regAddr 書き込み先レジスタです。
853     //! @param[in]    src     書き込み元データです。
854     //! @param[in]    count   データ数です。(32bit で 1)
855     //---------------------------------------------------------------------------
856     void PutLoadCommand( SafeBuffer& buffer, u32 regAddr, const u32* src, u32 count ) const;
857 
858     // 頂点シェーダから、共用シェーダのミラーモードを有効にします。
859     void PutEnableMirroringShaderSetting( SafeBuffer& buffer, bool enableMirroring ) const;
860 
861     //---------------------------------------------------------------------------
862     //! @brief        バッファに対して安全に書き込みをおこなうためのクラスです。
863     //---------------------------------------------------------------------------
864     class SafeBuffer
865     {
866     public:
867         typedef SafeBuffer Self;
868         //---------------------------------------------------------------------------
869         //! @brief        コンストラクタです。
870         //!
871         //! @param[out]   start   バッファの先頭アドレスです。
872         //! @param[in]    size    バッファサイズです。
873         //---------------------------------------------------------------------------
SafeBuffer(u32 * start,s32 size)874         SafeBuffer(u32* start, s32 size)
875          : m_StartAddress( start ),
876            m_CurrentAddress( start ),
877            m_EndAddress( static_cast<u32*>( ut::AddOffsetToPtr(start, size) ) ),
878            m_IsFinished( false ) {}
879 
StartAddress()880         const u32* StartAddress() const { return m_StartAddress; }
EndAddress()881         const u32* EndAddress() const { return m_EndAddress; }
CurrentAddress()882         const u32* CurrentAddress() const { return m_EndAddress; }
BufferSize()883         s32  BufferSize() const { return ut::GetOffsetFromPtr(m_StartAddress, m_EndAddress); }
UsedSize()884         s32  UsedSize() const { return ut::GetOffsetFromPtr(m_StartAddress, m_CurrentAddress); }
885 
IsFinished()886         bool IsFinished() const { return m_IsFinished; }
887 
888         operator const u32*() const { return m_CurrentAddress; }
889         Self& operator++() { return this->MoveAddress(sizeof(u32)); }
890         Self  operator++(int) { Self tmp = *this; (void)this->MoveAddress(sizeof(u32)); return tmp; }
891         Self& operator+=(s32 count) { return this->MoveAddress(count * sizeof(u32)); }
892 
893         //---------------------------------------------------------------------------
894         //! @brief        指定したサイズのデータが書き込めるかどうかの確認をおこないます。
895         //!               残りサイズが足りない場合には、終了処理をおこない、IsFinished() が
896         //!               true を返すようになります。
897         //!
898         //! @param[in]    size    書き込みデータサイズです。
899         //!
900         //! @return       残り容量に問題がなければ true, 容量が足りなければ false を返します。
901         //---------------------------------------------------------------------------
VerifyWriteSize(int size)902         bool VerifyWriteSize(int size)
903         {
904             if (ut::AddOffsetToPtr(m_CurrentAddress, size) <= m_EndAddress)
905             {
906                 return true;
907             }
908             else
909             {
910                 m_IsFinished = true;
911                 return false;
912             }
913         }
914 
915         //---------------------------------------------------------------------------
916         //! @brief        データの書き込みを行ないます。
917         //!               空き容量が足りない場合には中途半端なデータの書き込みは行なわず
918         //!               負のエラーコードを返して終了します。
919         //!               容量の問題で書き込みに失敗すると、それ以降 IsFinished() が true を
920         //!               返すようになります。
921         //!
922         //! @param[in]    src     書き込み元のデータです。
923         //! @param[in]    size    書き込みデータサイズです。
924         //!
925         //! @return       書き込みをおこなったデータサイズを返します。
926         //!               書き込みに失敗した場合には負のエラーコードを返します。
927         //---------------------------------------------------------------------------
Write(const u32 * src,s32 size)928         s32  Write(const u32* src, s32 size)
929         {
930             if (size <= 0) { return -1; }
931             if (!this->VerifyWriteSize(size)) { return -1; }
932             nw::os::MemCpy(m_CurrentAddress, src, size);
933             this->MoveAddress(size);
934 
935             return size;
936         }
937 
Write(u32 src)938         s32 Write(u32 src)
939         {
940             if (!this->VerifyWriteSize(sizeof(u32))) { return -1; }
941             *m_CurrentAddress = src;
942             ++m_CurrentAddress;
943             return sizeof(u32);
944         }
945 
946     private:
947         u32* m_StartAddress;
948         u32* m_CurrentAddress;
949         u32* m_EndAddress;
950         bool m_IsFinished;
951 
MoveAddress(s32 size)952         Self& MoveAddress(s32 size)
953         {
954             m_CurrentAddress = static_cast<u32*>( ut::AddOffsetToPtr(m_CurrentAddress, size) );
955             NW_ASSERT(m_CurrentAddress <= m_EndAddress);
956             return *this;
957         }
958     };
959 };
960 
961 } // namespace gfx
962 } // namespace nw
963 
964 #endif // NW_GFX_SHADERBINARYINFO_H_
965