1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ShaderBinaryInfo.cpp
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: 27937 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/gfx/gfx_CommandUtil.h>
19 #include <nw/gfx/gfx_ShaderBinaryInfo.h>
20 
21 namespace nw
22 {
23 namespace gfx
24 {
25 
26 //---------------------------------------------------------------------------
27 void
AnalyzeBinary()28 ShaderBinaryInfo::AnalyzeBinary()
29 {
30     const u32* binary = m_pShaderBinary;
31 
32     NW_ASSERT( *binary == ut::ReverseEndian('DVLB') );
33     ++binary;
34 
35     NW_ASSERT( *binary < EXE_IMAGE_MAX );
36     m_ExeImageCount = *binary;
37     ++binary;
38 
39     for ( int i = 0; i < m_ExeImageCount; ++i )
40     {
41         m_ExeImageInfo[ i ] = reinterpret_cast< const ExeImageInfo* >( (u8*)m_pShaderBinary + *binary );
42         NW_ASSERT( m_ExeImageInfo[ i ]->signature == ut::ReverseEndian('DVLE') );
43 
44         if ( m_ExeImageInfo[ i ]->isGeometryShader )
45         {
46             ++m_GeometryShaderCount;
47         }
48 
49         ++binary;
50     }
51 
52     const u32* packageInfo = binary;
53     NW_ASSERT( *binary == ut::ReverseEndian('DVLP') ); // DVLP
54     ++binary;
55     ++binary;
56 
57     m_pInstruction = static_cast<const u32*>( ut::AddOffsetToPtr( packageInfo, *binary ) );
58     ++binary;
59 
60     m_InstructionCount = *binary;
61     ++binary;
62 
63     const u32* swizzle = static_cast<const u32*>( ut::AddOffsetToPtr( packageInfo, *binary ) );
64     ++binary;
65 
66     m_SwizzleCount = *binary;
67     NW_ASSERT( m_SwizzleCount < SWIZZLE_PATTERN_MAX );
68     ++binary;
69 
70     // リンカ用のメタ情報はスキップして値だけ保存する。
71     for ( int i = 0; i < m_SwizzleCount; i++ )
72     {
73         m_Swizzle[ i ] = swizzle[ i * 2 ];
74     }
75 }
76 
77 //---------------------------------------------------------------------------
78 s32
GetCommonCommandSize() const79 ShaderBinaryInfo::GetCommonCommandSize() const
80 {
81     s32 size = 0;
82 
83     // PutEnableMirroringShaderSetting の分。
84     size += sizeof(u32) * 2;
85 
86     size += GetSwizzleCommandSize();
87     size += GetProgramCommandSize();
88 
89     return size;
90 }
91 
92 
93 //---------------------------------------------------------------------------
94 s32
GetShaderProgramCommandSize(s32 vertexIndex,s32 geometryIndex) const95 ShaderBinaryInfo::GetShaderProgramCommandSize( s32 vertexIndex, s32 geometryIndex ) const
96 {
97     s32 size = 0;
98 
99     size += 2 * sizeof(u32); // PutEnableMirroringShaderSetting の分
100 
101     size += this->GetConstRegCommandSize( vertexIndex );
102 
103     if ( geometryIndex >= 0 )
104     {
105         size += this->GetConstRegCommandSize( geometryIndex );
106     }
107 
108     size += this->GetOutAttrCommandSize( vertexIndex, geometryIndex );
109 
110     return size;
111 }
112 
113 //---------------------------------------------------------------------------
114 s32
GetProgramCommandSize() const115 ShaderBinaryInfo::GetProgramCommandSize() const
116 {
117     enum { VS_INSTRUCTION_MAX = 512 };
118 
119     u32 vertexInstructionCount = ut::Min( m_InstructionCount, u32(VS_INSTRUCTION_MAX) );
120 
121     s32 size = 0;
122 
123     size += 2 * sizeof(u32);
124     size += this->GetLoadCommandSize( vertexInstructionCount );
125     size += 2 * sizeof(u32);
126 
127     if ( this->GetGeometryShaderCount() > 0 )
128     {
129         size += 2 * sizeof(u32);
130         size += this->GetLoadCommandSize( m_InstructionCount );
131         size += 2 * sizeof(u32);
132     }
133 
134     return size;
135 }
136 
137 //---------------------------------------------------------------------------
138 s32
GetSwizzleCommandSize() const139 ShaderBinaryInfo::GetSwizzleCommandSize() const
140 {
141     s32 size = 0;
142 
143     size += 2 * sizeof(u32);
144     size += this->GetLoadCommandSize( m_SwizzleCount );
145 
146     if ( this->GetGeometryShaderCount() > 0 )
147     {
148         size += 2 * sizeof(u32);
149         size += this->GetLoadCommandSize( m_SwizzleCount );
150     }
151 
152     return size;
153 }
154 
155 //---------------------------------------------------------------------------
156 s32
GetPrepareCommandSize() const157 ShaderBinaryInfo::GetPrepareCommandSize() const
158 {
159     return 0;
160 }
161 
162 //---------------------------------------------------------------------------
163 s32
GetConstRegCommandSize(s32 shaderIndex) const164 ShaderBinaryInfo::GetConstRegCommandSize(s32 shaderIndex) const
165 {
166     s32 size = 0;
167     const s32 INT_COMMAND_SIZE = 2;
168     const s32 FLOAT_COMMAND_SIZE = 6;
169 
170     bool isGeometry = this->IsGeometryShader( shaderIndex );
171 
172     // プログラム情報
173     const ExeImageInfo* exeInfo = m_ExeImageInfo[ shaderIndex ];
174 
175     // 定数レジスタ情報
176     struct SetupInfo
177     {
178         u16 type;
179         u16 index;
180         u32 value[4];
181     };
182 
183     enum { TYPE_BOOL = 0, TYPE_INT = 1, TYPE_FLOAT = 2 };
184 
185     const SetupInfo* setupInfoTable =
186         static_cast<const SetupInfo*>( ut::AddOffsetToPtr( exeInfo, exeInfo->setupOffset) );
187 
188     // 定数レジスタのコマンド生成
189     for ( int i = 0; i < exeInfo->setupCount; ++i )
190     {
191         const SetupInfo& info = setupInfoTable[ i ];
192 
193         switch ( info.type )
194         {
195         case TYPE_BOOL:
196             break;
197 
198         case TYPE_INT:
199             size += INT_COMMAND_SIZE * sizeof(u32);
200             break;
201 
202         case TYPE_FLOAT:
203             size += FLOAT_COMMAND_SIZE * sizeof(u32);
204             break;
205         }
206     }
207 
208     return size;
209 }
210 
211 //---------------------------------------------------------------------------
212 s32
GetOutAttrCommandSize(s32 vertexIndex,s32 geometryIndex) const213 ShaderBinaryInfo::GetOutAttrCommandSize(s32 vertexIndex, s32 geometryIndex) const
214 {
215     NW_UNUSED_VARIABLE(vertexIndex);
216 
217     const s32 GEOMETRY_SETTING_COMMAND_SIZE = 8;
218     const s32 SHADER_PROGRAM_COMMAND_SIZE = 24;
219     const s32 GEOMETRY_COMMAND_SIZE = 6;
220 
221     s32 size = 0;
222 
223     bool hasGeometry = geometryIndex >= 0;
224     u32 geometrySettingCommandSize = (GEOMETRY_SETTING_COMMAND_SIZE - (hasGeometry ? 0 : 2)) * sizeof(u32);
225 
226     size += geometrySettingCommandSize;
227     size += SHADER_PROGRAM_COMMAND_SIZE * sizeof(u32);
228 
229     if ( hasGeometry )
230     {
231         size += GEOMETRY_COMMAND_SIZE * sizeof(u32);
232     }
233 
234     return size;
235 }
236 
237 
238 //---------------------------------------------------------------------------
239 // NOTE: コマンドのサイズが変わる場合は、必ず GetCommonCommandSize も合わせて修正する。
240 s32
BuildCommonCommand(u32 * bufferAddress,u32 bufferSize) const241 ShaderBinaryInfo::BuildCommonCommand( u32* bufferAddress, u32 bufferSize ) const
242 {
243     SafeBuffer buffer(bufferAddress, bufferSize);
244 
245     // シェーダバイナリの転送コマンドを生成します。
246     // その他の頂点の設定コマンド等は、ShaderProgramDescription 側に持ちます。
247 
248     // ジオメトリシェーダのインストラクションの前方部分には、
249     // 頂点シェーダと同じ命令が格納されているので、ResShaderBinary が
250     // 同じであればシェーダバイナリの再転送は必要ない。
251     //
252     // この為、ジオメトリシェーダがある場合には必ずジオメトリ分のバイナリも転送する。
253 
254     if ( this->GetGeometryShaderCount() > 0 )
255     {
256         this->PutEnableMirroringShaderSetting( buffer, false );
257     }
258     else
259     {
260         this->PutEnableMirroringShaderSetting( buffer, true );
261     }
262 
263     this->BuildSwizzleCommand( buffer );
264     this->BuildProgramCommand( buffer );
265 
266     return buffer.UsedSize();
267 }
268 
269 
270 //---------------------------------------------------------------------------
271 // NOTE: コマンドのサイズが変わる場合は、必ず GetProgramCommandSize も合わせて修正する。
272 void
BuildProgramCommand(SafeBuffer & buffer) const273 ShaderBinaryInfo::BuildProgramCommand( SafeBuffer& buffer ) const
274 {
275     // あらかじめ、PutEnableMirroringShaderSetting でミラーリングが有効に
276     // 設定した状態で呼び出される事が前提となっています。
277 
278     // この関数から抜ける際には、MirroringShaderSetting の値は不定となります。
279 
280     // まず先頭から512命令以内の部分は、頂点・ジオメトリ共用部分として送信する。
281 
282     enum { VS_INSTRUCTION_MAX = 512 };
283 
284     u32 vertexInstructionCount = ut::Min( m_InstructionCount, u32(VS_INSTRUCTION_MAX) );
285 
286     const u32 VS_COMMAND[] =
287     {
288         0,
289         internal::MakeCommandHeader( PICA_REG_VS_PROG_ADDR, 1, false, 0xF )
290     };
291 
292     buffer.Write( &VS_COMMAND[0], sizeof(VS_COMMAND) );
293 
294     // 頂点部分のインストラクションのロード。
295     this->PutLoadCommand( buffer,
296                           PICA_REG_VS_PROG_DATA0,
297                           &m_pInstruction[ 0 ],
298                           vertexInstructionCount );
299 
300     const u32 VS_RENEWAL_COMMAND[] =
301     {
302         1,
303         internal::MakeCommandHeader( PICA_REG_VS_PROG_RENEWAL_END, 1, false, 0xF )
304     };
305 
306     buffer.Write( &VS_RENEWAL_COMMAND[0], sizeof(VS_RENEWAL_COMMAND) );
307 
308     if ( this->GetGeometryShaderCount() > 0 )
309     {
310         const u32 GS_COMMAND[] =
311         {
312             0,
313             internal::MakeCommandHeader( PICA_REG_GS_PROG_ADDR, 1, false, 0xF )
314         };
315 
316         buffer.Write( &GS_COMMAND[0], sizeof(GS_COMMAND) );
317 
318         // 頂点部分のインストラクションのロード。
319         this->PutLoadCommand( buffer,
320                               PICA_REG_GS_PROG_DATA0,
321                               &m_pInstruction[ 0 ],
322                               m_InstructionCount );
323 
324         const u32 GS_RENEWAL_COMMAND[] =
325         {
326             1,
327             internal::MakeCommandHeader( PICA_REG_GS_PROG_RENEWAL_END, 1, false, 0xF )
328         };
329 
330         buffer.Write( &GS_RENEWAL_COMMAND[0], sizeof(GS_RENEWAL_COMMAND) );
331     }
332 }
333 
334 
335 //---------------------------------------------------------------------------
336 // NOTE: コマンドのサイズが変わる場合は、必ず GetSwizzleCommandSize も合わせて修正する。
337 void
BuildSwizzleCommand(SafeBuffer & buffer) const338 ShaderBinaryInfo::BuildSwizzleCommand( SafeBuffer& buffer ) const
339 {
340     // あらかじめ、PutEnableMirroringShaderSetting でミラーリングが有効に
341     // 設定した状態で呼び出される事が前提となっています。
342 
343     const u32 COMMAND[] =
344     {
345         0,
346         internal::MakeCommandHeader( PICA_REG_VS_PROG_SWIZZLE_ADDR, 1, false, 0xF )
347     };
348 
349     buffer.Write( &COMMAND[0], sizeof(COMMAND) );
350 
351     NW_ASSERT( m_SwizzleCount > 0 );
352 
353     // Swizzleパターンのロード
354     this->PutLoadCommand( buffer,
355                           PICA_REG_VS_PROG_SWIZZLE_DATA0,
356                           &m_Swizzle[0],
357                           m_SwizzleCount );
358 
359     if ( this->GetGeometryShaderCount() > 0 )
360     {
361         const u32 GS_COMMAND[] =
362         {
363             0,
364             internal::MakeCommandHeader( PICA_REG_GS_PROG_SWIZZLE_ADDR, 1, false, 0xF )
365         };
366 
367         buffer.Write( &GS_COMMAND[0], sizeof(GS_COMMAND) );
368 
369         NW_ASSERT( m_SwizzleCount > 0 );
370 
371         // Swizzleパターンのロード
372         this->PutLoadCommand( buffer,
373                               PICA_REG_GS_PROG_SWIZZLE_DATA0,
374                               &m_Swizzle[0],
375                               m_SwizzleCount );
376     }
377 }
378 
379 
380 //---------------------------------------------------------------------------
381 // NOTE: コマンドのサイズが変わる場合は、必ず GetShaderProgramCommandSize も合わせて修正する。
382 s32
BuildShaderProgramCommand(s32 vertexIndex,s32 geometryIndex,u32 * bufferAddress,u32 bufferSize) const383 ShaderBinaryInfo::BuildShaderProgramCommand( s32 vertexIndex, s32 geometryIndex, u32* bufferAddress, u32 bufferSize ) const
384 {
385     SafeBuffer buffer(bufferAddress, bufferSize);
386 
387     NW_ASSERT( ! this->IsGeometryShader( vertexIndex ) );
388     NW_ASSERT( 0 <= vertexIndex && vertexIndex < this->GetShaderCount() );
389     NW_ASSERT( geometryIndex < 0 || this->IsGeometryShader( geometryIndex ) );
390     NW_ASSERT( geometryIndex < this->GetShaderCount() );
391 
392     if ( geometryIndex < 0 )
393     {
394         this->PutEnableMirroringShaderSetting( buffer, true );
395     }
396     else
397     {
398         this->PutEnableMirroringShaderSetting( buffer, false );
399     }
400 
401     this->BuildConstRegCommand( buffer, vertexIndex );
402 
403     if ( geometryIndex >= 0 )
404     {
405         this->BuildConstRegCommand( buffer, geometryIndex );
406     }
407 
408     this->BuildOutAttrCommand( buffer, vertexIndex, geometryIndex );
409 
410     return buffer.UsedSize();
411 }
412 
413 
414 //---------------------------------------------------------------------------
415 // NOTE: コマンドのサイズが変わる場合は、必ず GetPrepareCommandSize も合わせて修正する。
416 void
BuildPrepareCommand(SafeBuffer & buffer) const417 ShaderBinaryInfo::BuildPrepareCommand( SafeBuffer& buffer ) const
418 {
419     NW_UNUSED_VARIABLE(buffer);
420 
421     // tugal では次のコマンドを生成している。
422     // ・ジオメトリシェーダの有効化とパイプライン掃除用のダミーコマンド。
423     // ・0x25e[8:9] へのプリミティブ形状設定。
424     // ・0x244 への頂点・ジオメトリ設定のミラーリング設定。
425     // NW では、これらは必要な場合のみ設定するようにする。
426 }
427 
428 
429 //---------------------------------------------------------------------------
430 // NOTE: コマンドのサイズが変わる場合は、必ず GetConstRegCommandSize も合わせて修正する。
431 void
BuildConstRegCommand(SafeBuffer & buffer,s32 shaderIndex) const432 ShaderBinaryInfo::BuildConstRegCommand( SafeBuffer& buffer, s32 shaderIndex ) const
433 {
434     bool isGeometry = this->IsGeometryShader( shaderIndex );
435 
436     u32 regFloat    = PICA_REG_VS_FLOAT_ADDR; // 0x2c0
437     u32 regInteger  = PICA_REG_VS_INT0;       // 0x2b1
438 
439     if ( isGeometry )
440     {
441         regFloat    = PICA_REG_GS_FLOAT_ADDR; // 0x290
442         regInteger  = PICA_REG_GS_INT0;       // 0x281
443     }
444 
445     // プログラム情報
446     const ExeImageInfo* exeInfo = m_ExeImageInfo[ shaderIndex ];
447 
448     // 定数レジスタ情報
449     struct SetupInfo
450     {
451         u16 type;
452         u16 index;
453         u32 value[4];
454     };
455 
456     enum { TYPE_BOOL = 0, TYPE_INT = 1, TYPE_FLOAT = 2 };
457 
458     const SetupInfo* setupInfoTable =
459         static_cast<const SetupInfo*>( ut::AddOffsetToPtr( exeInfo, exeInfo->setupOffset) );
460 
461     // 定数レジスタのコマンド生成
462     for ( int i = 0; i < exeInfo->setupCount; ++i )
463     {
464         const SetupInfo& info = setupInfoTable[ i ];
465         const u32* value = info.value;
466 
467         switch ( info.type )
468         {
469         case TYPE_BOOL:
470             break;
471 
472         case TYPE_INT:
473             {
474                 const u32 COMMAND[] =
475                 {
476                     value[ 0 ],
477                     internal::MakeCommandHeader(regInteger + info.index, 1, false, 0xF)
478                 };
479 
480                 buffer.Write( &COMMAND[0], sizeof(COMMAND) );
481             }
482             break;
483 
484         case TYPE_FLOAT:
485 
486             {
487                 const u32 COMMAND[] =
488                 {
489                     info.index,  // 24 bit モード
490                     internal::MakeCommandHeader( regFloat, 4, true, 0xF ),
491                     ( value[ 3 ] <<  8 & 0xffffff00 ) | ( value[ 2 ] >> 16 & 0x000000ff ),
492                     ( value[ 2 ] << 16 & 0xffff0000 ) | ( value[ 1 ] >>  8 & 0x0000ffff ),
493                     ( value[ 1 ] << 24 & 0xff000000 ) | ( value[ 0 ] >>  0 & 0x00ffffff ),
494                     0, // padding
495                 };
496 
497                 buffer.Write( &COMMAND[0], sizeof(COMMAND) );
498             }
499             break;
500         }
501     }
502 }
503 
504 //---------------------------------------------------------------------------
505 // NOTE: コマンドのサイズが変わる場合は、必ず GetOutAttrCommandSize も合わせて修正する。
506 void
BuildOutAttrCommand(SafeBuffer & buffer,s32 vertexIndex,s32 geometryIndex) const507 ShaderBinaryInfo::BuildOutAttrCommand( SafeBuffer& buffer, s32 vertexIndex, s32 geometryIndex ) const
508 {
509     bool hasGeometry = geometryIndex >= 0;
510 
511     u32 vertexOutputMask;
512     u32 vertexOutputNum;
513     u32 shaderOutputMask;
514     u32 shaderOutputNum;
515     u32 shaderOutputMap[7];
516     u32 clockControl = 0x01030703; // クロック制御はひとまず全て有効。
517     u32 vertexEntry;
518     u32 geometryInputNum;
519     u32 geometryEntry;
520     bool isTextureOutput = false;
521 
522     this->GetOutputRegisterNum( vertexIndex, &vertexOutputNum, &vertexOutputMask );
523     this->GetShaderOutputRegisterNum( vertexIndex, geometryIndex, &shaderOutputNum, &shaderOutputMask );
524     this->GetShaderOutputRegisterMap( vertexIndex, geometryIndex, &shaderOutputMap[0] );
525     vertexEntry = this->GetEntryAddress( vertexIndex );
526 
527     u32 GEOMETRY_SETTING_COMMAND[] =
528     {
529         0x00000000, 0x000f0252,
530         0x00000000, 0x00010254,
531         0x00000000, 0x00080229,
532         0x00000000, 0x00020289,
533     };
534 
535     if ( hasGeometry )
536     {
537         enum { IDX_REG_252 = 0, IDX_REG_254 = 2, IDX_REG_229 = 4, IDX_REG_289 = 6 };
538 
539         geometryInputNum = vertexOutputNum;
540         geometryEntry = this->GetEntryAddress( geometryIndex );
541 
542         u32 geometryMode = this->GetGeometryDataMode( geometryIndex );
543 
544         GEOMETRY_SETTING_COMMAND[ IDX_REG_252 ] |= geometryMode & 0x3;
545 
546         switch ( geometryMode )
547         {
548         case 0: // normal mode
549             break;
550         case 1: // subdivision mode
551             {
552                 GEOMETRY_SETTING_COMMAND[ IDX_REG_229 ] |= 1u << 31;
553                 GEOMETRY_SETTING_COMMAND[ IDX_REG_289 ] |= 1 << 8;
554 
555                 u32 geomMainVertexNum = this->GetGeometryMainVertexNum( geometryIndex );
556 
557                 GEOMETRY_SETTING_COMMAND[ IDX_REG_254 ] |= geomMainVertexNum;
558             }
559             break;
560         case 2: // constant data mode
561             {
562                 GEOMETRY_SETTING_COMMAND[ IDX_REG_289 ] |= 1 << 8;
563 
564                 u32 geomPatchSize = this->GetGeometryPatchSize( geometryIndex );
565                 u32 geomStartIndex = this->GetGeometryStartIndex( geometryIndex );
566 
567                 GEOMETRY_SETTING_COMMAND[ IDX_REG_252 ] |= (geomPatchSize - 1) << 8;
568                 GEOMETRY_SETTING_COMMAND[ IDX_REG_252 ] |= (vertexOutputNum - 1) << 12;
569                 GEOMETRY_SETTING_COMMAND[ IDX_REG_252 ] |= geomStartIndex << 16;
570                 GEOMETRY_SETTING_COMMAND[ IDX_REG_252 ] |= 1 << 24;
571             }
572             break;
573         default:
574             NW_FATAL_ERROR("Invalid geometry mode");
575         }
576     }
577 
578     // 頂点入出力レジスタ設定
579     const u32 SHADER_PROGRAM_COMMAND[] =
580     {
581         vertexOutputMask,    0x000f02bd, // 頂点出力マスク (vtx)
582         vertexOutputNum - 1, 0x000f0251, // 出力レジスタ数 - 1 (vtx)
583         vertexOutputNum - 1, 0x000f024a, // 出力レジスタ数 - 1 (vtx)
584         shaderOutputNum - 1, 0x0001025e, // 出力レジスタ数 - 1 (vtx/geom)
585         shaderOutputNum,     0x000f004f, // 出力レジスタ数 (vtx/geom)
586         shaderOutputMap[0],  0x806f0050, // 出力レジスタ0のフォーマット
587         shaderOutputMap[1],  shaderOutputMap[2], // 出力レジスタ1,2のフォーマット
588         shaderOutputMap[3],  shaderOutputMap[4], // 出力レジスタ3,4のフォーマット
589         shaderOutputMap[5],  shaderOutputMap[6], // 出力レジスタ5,6のフォーマット
590         0x00000001, 0x000f0064, // テクスチャ座標が出力される場合は1
591         clockControl,        0x000f006f, // シェーダクロック制御
592         0x7fff0000 | vertexEntry, 0x000f02ba, // 頂点シェーダ開始アドレス
593     };
594 
595     u32 geometrySettingCommandSize = sizeof(GEOMETRY_SETTING_COMMAND) - sizeof(u32) * (hasGeometry ? 0 : 2);
596     buffer.Write( &GEOMETRY_SETTING_COMMAND[0], geometrySettingCommandSize );
597     buffer.Write( &SHADER_PROGRAM_COMMAND[0], sizeof(SHADER_PROGRAM_COMMAND) );
598 
599     if ( hasGeometry )
600     {
601         // ジオメトリ入出力レジスタ設定
602         const u32 GEOMETRY_COMMAND[] =
603         {
604             shaderOutputMask, 0x000f028d, // ジオメトリ出力マスク
605             0x08000000 | (geometryInputNum - 1), 0x00090289, // ジオメトリシェーダの入力レジスタ数 - 1
606             0x7fff0000 | geometryEntry, 0x000f028a,          // ジオメトリシェーダの開始アドレス
607         };
608 
609         buffer.Write( &GEOMETRY_COMMAND[0], sizeof(GEOMETRY_COMMAND) );
610     }
611 }
612 
613 //---------------------------------------------------------------------------
614 void
PutEnableMirroringShaderSetting(SafeBuffer & buffer,bool enableMirroring) const615 ShaderBinaryInfo::PutEnableMirroringShaderSetting(SafeBuffer& buffer, bool enableMirroring) const
616 {
617     const u32 COMMAND[] =
618     {
619         enableMirroring ? 0 : 1,
620         internal::MakeCommandHeader( PICA_REG_VS_COM_MODE, 1, false, 0x1 )
621     };
622 
623     buffer.Write( &COMMAND[0], sizeof(COMMAND) );
624 }
625 
626 //---------------------------------------------------------------------------
627 // NOTE: コマンドのサイズが変わる場合は、必ず GetLoadCommandSize も合わせて修正する。
628 void
PutLoadCommand(SafeBuffer & buffer,u32 regAddr,const u32 * src,u32 count) const629 ShaderBinaryInfo::PutLoadCommand(
630     SafeBuffer& buffer,
631     u32 regAddr,
632     const u32* src,
633     u32 count
634 ) const
635 {
636     enum { WRITE_MAX = 128 };
637 
638     u32 restCount = count;
639     u32 index = 0;
640 
641     while ( true )
642     {
643         u32 countPerCommand = ut::Min( restCount, u32(WRITE_MAX) );
644 
645         const u32 COMMAND[] =
646         {
647             src[index],
648             internal::MakeCommandHeader( regAddr, countPerCommand, false, 0xF )
649         };
650 
651         buffer.Write( &COMMAND[0], sizeof(COMMAND) );
652         buffer.Write( &src[index + 1], (countPerCommand - 1) * sizeof(u32) );
653 
654         if ( (countPerCommand % 2) == 0 )
655         {
656             buffer.Write( 0 ); // パディング挿入
657         }
658 
659         index += countPerCommand;
660         restCount -= countPerCommand;
661 
662         if (restCount == 0)
663         {
664             break;
665         }
666     }
667 }
668 
669 //---------------------------------------------------------------------------
670 s32
GetLoadCommandSize(u32 count) const671 ShaderBinaryInfo::GetLoadCommandSize(u32 count) const
672 {
673     enum { WRITE_MAX = 128 };
674 
675     s32 commandSize = 0;
676     u32 restCount = count;
677 
678     while ( true )
679     {
680         u32 countPerCommand = ut::Min( restCount, u32(WRITE_MAX) );
681 
682         commandSize += 2 * sizeof(u32);
683         commandSize += (countPerCommand - 1) * sizeof(u32);
684 
685         if ( (countPerCommand % 2) == 0 )
686         {
687             commandSize += sizeof(u32);
688         }
689 
690         restCount -= countPerCommand;
691 
692         if (restCount == 0)
693         {
694             break;
695         }
696     }
697 
698     return commandSize;
699 }
700 
701 
702 } // namespace gfx
703 } // namespace nw
704