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