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