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