1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ActivateCommand.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: 28084 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/os/os_Memory.h>
19 #include <nw/gfx/gfx_ActivateCommand.h>
20 #include <nw/gfx/gfx_DisplayList.h>
21 #include <nw/gfx/res/gfx_ResVertex.h>
22 #include <nw/gfx/res/gfx_ResShape.h>
23 #include <nw/gfx/gfx_ShaderBinaryInfo.h>
24 
25 namespace nw
26 {
27 namespace gfx
28 {
29 nw::os::IAllocator* CommandCacheManager::s_Allocator = NULL;
30 namespace internal
31 {
32 
33 namespace {
34 
35 // 全ロードアレイをクリアし、固定頂点属性を設定する。
36 const u32 CLEAR_VERTEX_COMMAND[] =
37 {
38     // 固定頂点属性の設定
39     0xBFFF0000,
40     internal::MakeCommandHeader(0x202, 1, false, 0xF),
41 
42     // ロードアレイの無効化
43     0,
44     internal::MakeCommandHeader(0x205        , 1, false, 0xF),
45     0,
46     internal::MakeCommandHeader(0x205 + 3    , 1, false, 0xF),
47     0,
48     internal::MakeCommandHeader(0x205 + 3 * 2, 1, false, 0xF),
49     0,
50     internal::MakeCommandHeader(0x205 + 3 * 3, 1, false, 0xF),
51     0,
52     internal::MakeCommandHeader(0x205 + 3 * 4, 1, false, 0xF),
53     0,
54     internal::MakeCommandHeader(0x205 + 3 * 5, 1, false, 0xF),
55     0,
56     internal::MakeCommandHeader(0x205 + 3 * 6, 1, false, 0xF),
57     0,
58     internal::MakeCommandHeader(0x205 + 3 * 7, 1, false, 0xF),
59     0,
60     internal::MakeCommandHeader(0x205 + 3 * 8, 1, false, 0xF),
61     0,
62     internal::MakeCommandHeader(0x205 + 3 * 9, 1, false, 0xF),
63     0,
64     internal::MakeCommandHeader(0x205 + 3 * 10, 1, false, 0xF),
65     0,
66     internal::MakeCommandHeader(0x205 + 3 * 11, 1, false, 0xF),
67 
68     1,
69     internal::MakeCommandHeader(0x232, 4, true, 0xF),
70     0,
71     0,
72     0,
73     0,
74 
75     2,
76     internal::MakeCommandHeader(0x232, 4, true, 0xF),
77     0,
78     0,
79     0,
80     0,
81 
82     3,
83     internal::MakeCommandHeader(0x232, 4, true, 0xF),
84     0,
85     0,
86     0,
87     0,
88 
89     4,
90     internal::MakeCommandHeader(0x232, 4, true, 0xF),
91     0,
92     0,
93     0,
94     0,
95 
96     5,
97     internal::MakeCommandHeader(0x232, 4, true, 0xF),
98     0,
99     0,
100     0,
101     0,
102 
103     6,
104     internal::MakeCommandHeader(0x232, 4, true, 0xF),
105     0,
106     0,
107     0,
108     0,
109 
110     7,
111     internal::MakeCommandHeader(0x232, 4, true, 0xF),
112     0,
113     0,
114     0,
115     0,
116 
117     8,
118     internal::MakeCommandHeader(0x232, 4, true, 0xF),
119     0,
120     0,
121     0,
122     0,
123 
124     9,
125     internal::MakeCommandHeader(0x232, 4, true, 0xF),
126     0,
127     0,
128     0,
129     0,
130 
131     10,
132     internal::MakeCommandHeader(0x232, 4, true, 0xF),
133     0,
134     0,
135     0,
136     0,
137 
138     11,
139     internal::MakeCommandHeader(0x232, 4, true, 0xF),
140     0,
141     0,
142     0,
143     0
144 };
145 
146 //---------------------------------------------------------------------------
147 //! @brief        SetupActivateVertexAttributeCommand_ で生成されるコマンドサイズを計算します。
148 //!
149 //! @param[in]    shape             頂点設定コマンドを設定するシェイプです。
150 //! @param[in]    shaderProgramDesc 対応するシェーダプログラムです。
151 //!
152 //! @return       コマンドのサイズです。
153 //---------------------------------------------------------------------------
154 template <typename TShape>
155 s32
CalcSetupActivateVertexAttributeCommandSize_(TShape shape,ResShaderProgramDescription shaderProgramDesc)156 CalcSetupActivateVertexAttributeCommandSize_(
157     TShape                      shape,
158     ResShaderProgramDescription shaderProgramDesc
159 )
160 {
161     s32 commandSize = 12;
162 
163     s32 vtxAttrNum = shape.GetVertexAttributesCount();
164 
165     // 頂点ストリームを番号の若い順に設定
166     for ( s32 i = 0; i < vtxAttrNum; ++ i )
167     {
168         ResVertexAttribute attribute = shape.GetVertexAttributes( i );
169 
170         if ( attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM )
171         {
172             commandSize += 6;
173         }
174         else
175         {
176             commandSize += 4;
177         }
178     }
179 
180     if (shaderProgramDesc.GetGeometryShaderIndex() >= 0)
181     {
182         commandSize += 4;
183     }
184 
185     return sizeof(u32) * commandSize;
186 }
187 
188 //---------------------------------------------------------------------------
189 template <typename TShape>
190 s32
CalcSetupDeactivateVertexAttributeCommandSize_(TShape shape,ResShaderProgramDescription shaderProgramDesc)191 CalcSetupDeactivateVertexAttributeCommandSize_(
192     TShape                      shape,
193     ResShaderProgramDescription shaderProgramDesc
194 )
195 {
196     NW_UNUSED_VARIABLE( shaderProgramDesc );
197 
198     int inputIndex = 0; // 内部頂点属性番号
199     s32 vtxAttrNum = shape.GetVertexAttributesCount();
200     s32 commandIndex = 0;
201 
202     // 頂点ストリームを番号の若い順に設定
203     for ( s32 i = 0; i < vtxAttrNum; ++ i )
204     {
205         ResVertexAttribute attribute = shape.GetVertexAttributes( i );
206 
207         // 固定頂点属性は無視する。
208         if ( attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM )
209         {
210             ++inputIndex;
211             continue;
212         }
213 
214         if (attribute.GetFlags() & ResVertexAttributeData::FLAG_INTERLEAVE)
215         {
216             ResInterleavedVertexStream interleave = ResStaticCast<ResInterleavedVertexStream>(attribute);
217             s32 streamCount = interleave.GetVertexStreamsCount();
218             inputIndex += streamCount;
219         }
220         else
221         {
222             ++inputIndex;
223         }
224 
225         commandIndex += 2;
226     }
227 
228     commandIndex += 6;
229 
230     // (0,0,0,0) の固定属性を設定
231     for ( int i = 1; i < inputIndex; ++i )
232     {
233         commandIndex += 6;
234     }
235 
236     return sizeof(u32) * commandIndex;
237 }
238 
239 //---------------------------------------------------------------------------
240 //! @brief        頂点属性の Usage から頂点属性のインデックスに変換します。
241 //!
242 //! @param[in]    shaderProgramDesc シェーダプログラム情報です。
243 //! @param[in]    usage             頂点の種別情報です。
244 //!
245 //! @return       頂点属性のインデックスを返します。
246 //---------------------------------------------------------------------------
247 NW_INLINE s32
GetAttributeIndexFromUsage(ResShaderProgramDescription shaderProgramDesc,s32 usage)248 GetAttributeIndexFromUsage(ResShaderProgramDescription shaderProgramDesc, s32 usage)
249 {
250     return shaderProgramDesc.GetAttributeIndices(usage);
251 }
252 
253 
254 } // namespace
255 
256 //---------------------------------------------------------------------------
257 void
ClearVertexAttribute()258 ClearVertexAttribute()
259 {
260     NWUseCmdlist( CLEAR_VERTEX_COMMAND, sizeof(CLEAR_VERTEX_COMMAND) );
261 }
262 
263 //---------------------------------------------------------------------------
264 template <typename TShape>
265 static s32
SetupActivateVertexAttributeCommand_(CommandBufferInfo & bufferInfo,TShape shape,ResShaderProgramDescription shaderProgramDesc)266 SetupActivateVertexAttributeCommand_(
267     CommandBufferInfo&          bufferInfo,
268     TShape                      shape,
269     ResShaderProgramDescription shaderProgramDesc
270 )
271 {
272     enum
273     {
274         MAX_ATTRIBUTES_NUM        = 12,
275 
276         REG_VTX_SHADER_ATTR_NUM   = 0x2b9, // [3:0] 頂点属性数 - 1
277         REG_VTX_SHADER_ATTR_NUM_2 = 0x242, // [3:0] 頂点族整数 - 1
278         REG_VTX_MAP_0             = 0x2bb, // [31:0] 入力レジスタのインデックス
279         REG_VTX_MAP_1             = 0x2bc, // [15:0] 入力レジスタのインデックス
280         REG_VTX_STREAM_BASE       = 0x200, // [28:1] 頂点アレイのベースアドレス
281         REG_VTX_ARRAY_OFFSET      = 0x203, // [27:0] ロードアレイ0のアドレスオフセット
282         REG_VTX_PARAM_INDEX       = 0x232, // [3:0] 頂点シェーダの入力番号指定
283         REG_GEOM_MAP_0            = 0x28b, // [31:0] 入力レジスタのインデックス
284         REG_GEOM_MAP_1            = 0x28c  // [15:0] 入力レジスタのインデックス
285     };
286 
287     const ShaderBinaryInfo* shaderInfo = shaderProgramDesc.GetShaderBinaryInfo();
288     NW_NULL_ASSERT( shaderInfo );
289 
290     u32 shaderVtxAttrNum = shaderInfo->GetInputRegisterNum( shaderProgramDesc.GetVertexShaderIndex() );
291 
292     // VRAM, FCRAM のメモリマップの中からアドレスの一番小さいものをベースに設定
293     u32 baseAddr = nngxGetPhysicalAddr(nn::gx::GetVramStartAddr(nn::gx::MEM_VRAMA));
294     shape.ref().m_BaseAddress = baseAddr;
295 
296     s32 vtxAttrNum = shape.GetVertexAttributesCount();
297     s32 inputRegNum = shaderVtxAttrNum;
298 
299     u32* command = reinterpret_cast<u32*>( bufferInfo.GetCurrentAddress() );
300 
301     // シェーダの入力レジスタ数を設定。
302     command[0] = (inputRegNum - 1) | 0xa0000000;
303     command[1] = internal::MakeCommandHeader(REG_VTX_SHADER_ATTR_NUM,   1, false, 0xb);
304 
305     command[2] = (inputRegNum - 1);
306     command[3] = internal::MakeCommandHeader(REG_VTX_SHADER_ATTR_NUM_2, 1, false, 0x1);
307 
308     command[4] = 0;
309     command[5] = internal::MakeCommandHeader(REG_VTX_MAP_0,             2, true,  0xF);
310     command[6] = 0;
311     command[7] = 0;
312 
313     command[8] = baseAddr >> 3;
314     command[9] = internal::MakeCommandHeader(REG_VTX_STREAM_BASE,       3, true,  0xF);
315     command[10] = 0;
316     command[11] = static_cast<u32>(inputRegNum - 1) << 28;
317 
318     u32* inputMapTable   = &command[4];  // 0x2bb
319     u32* inputFormat     = &command[10]; // 0x201
320     u32* vertexParamMask = &command[11]; // 0x202
321 
322     int inputIndex = 0; // 内部頂点属性番号
323     int arrayIndex = 0; // ロードアレイ番号
324     u32 commandIndex = 12;
325 
326     u32 usedFlag = 0;
327 
328     // 0x2bb, 0x2bc に頂点ストリームを前から順に詰めて設定する。
329     // その後に、固定頂点属性を設定する。未使用の項目は Deactivate 用のコマンドであらかじめクリアされている前提とする。
330 
331     // 頂点ストリームを番号の若い順に設定
332     for ( s32 i = 0; i < vtxAttrNum; ++ i )
333     {
334         ResVertexAttribute attribute = shape.GetVertexAttributes( i );
335 
336         if ( attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM )
337         {
338             // 固定頂点属性は無視する。
339             continue;
340         }
341 
342         if (attribute.GetFlags() & ResVertexAttributeData::FLAG_INTERLEAVE)
343         // インターリーブフォーマットの場合。
344         {
345             ResInterleavedVertexStream interleave = ResStaticCast<ResInterleavedVertexStream>(attribute);
346 
347             // ロードアレイの設定。
348             // インターリブ形式なので 1 本のロードアレイに複数の要素が入ります。
349             u32 bufferAddr = nngxGetPhysicalAddr( interleave.GetImageAddress() );
350             s32 streamCount = interleave.GetVertexStreamsCount();
351 
352             command[commandIndex    ] = bufferAddr - baseAddr;
353             command[commandIndex + 1] = internal::MakeCommandHeader(REG_VTX_ARRAY_OFFSET + 3 * arrayIndex, 3, true, 0xF);
354             command[commandIndex + 2] = 0;
355             command[commandIndex + 3] = (interleave.GetStride() << 16) | (streamCount << 28);
356 
357             u32* arraySetting = &command[commandIndex + 2];
358             commandIndex += 4;
359 
360             for ( s32 streamIdx = 0; streamIdx < streamCount; ++streamIdx )
361             {
362                 ResVertexStream stream = interleave.GetVertexStreams( streamIdx );
363 
364                 s32 usage = stream.GetUsage();
365                 s32 usageIndex = GetAttributeIndexFromUsage( shaderProgramDesc, usage );
366                 NW_ASSERT(0 <= usageIndex && usageIndex < MAX_ATTRIBUTES_NUM);
367 
368                 inputMapTable[ (inputIndex / 8) * 2 ] |= (usageIndex & 0xf) << (4 * (inputIndex % 8)); // (inputIndex >= 8) ? 2 : 0 のアドレスに書き込む。
369                 usedFlag |= 0x1 << usageIndex;
370 
371                 u32 format    = stream.GetFormatType();
372                 u32 dimension = stream.GetDimension();
373 
374                 inputFormat[ inputIndex / 8 ] |= CommandCacheHelper::GetVertexFormat(dimension, format) << ((inputIndex % 8) * 4);
375 
376                 if (streamIdx < 8)
377                 {
378                     arraySetting[0] |= inputIndex << (streamIdx * 4);
379                 }
380                 else
381                 {
382                     arraySetting[1] |= inputIndex << ((streamIdx - 8) * 4);
383                 }
384 
385                 ++inputIndex;
386             }
387 
388         }
389         else
390         // 非インターリーブフォーマットの場合。
391         {
392             s32 usage = attribute.GetUsage();
393             s32 usageIndex = GetAttributeIndexFromUsage( shaderProgramDesc, usage );
394 
395             NW_ASSERT(0 <= usageIndex && usageIndex < MAX_ATTRIBUTES_NUM);
396             inputMapTable[ (inputIndex / 8) * 2 ] |= (usageIndex & 0xF) << (4 * (inputIndex % 8));
397             usedFlag |= 0x1 << usageIndex;
398 
399             ResVertexStream stream = ResStaticCast<ResVertexStream>(attribute);
400 
401             u32 format    = stream.GetFormatType();
402             u32 dimension = stream.GetDimension();
403 
404             inputFormat[ inputIndex / 8 ] |= CommandCacheHelper::GetVertexFormat(dimension, format) << ((inputIndex % 8) * 4);
405 
406             // ロードアレイの設定
407             u32 bufferAddr = nngxGetPhysicalAddr( stream.GetImageAddress() );
408 
409             // このクラスでは interleave 形式には対応しないので、(0番目の要素 == 内部頂点属性 index 番目)
410             command[commandIndex] = bufferAddr - baseAddr;
411             command[commandIndex + 1] = internal::MakeCommandHeader(REG_VTX_ARRAY_OFFSET + 3 * arrayIndex, 3, true, 0xF);
412             command[commandIndex + 2] = inputIndex;
413             command[commandIndex + 3] = (CommandCacheHelper::GetVertexSize(dimension, format) << 16) + (1 <<  28);
414 
415             ++inputIndex;
416             commandIndex += 4;
417         }
418 
419         ++arrayIndex;
420     }
421 
422     const u32 HEADER_VTX_PARAM_INDEX = internal::MakeCommandHeader(REG_VTX_PARAM_INDEX, 4, true, 0xF);
423 
424     // 頂点ストリームの後に頂点パラメータを設定。
425     for ( s32 i = 0; i < vtxAttrNum; ++ i )
426     {
427         ResVertexAttribute attribute = shape.GetVertexAttributes( i );
428 
429         if ( attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM )
430         {
431             ResVertexParamAttribute param = ResStaticCast<ResVertexParamAttribute>(attribute);
432 
433             s32 usage = param.GetUsage();
434             s32 usageIndex = GetAttributeIndexFromUsage( shaderProgramDesc, usage );
435             NW_ASSERT(0 <= usageIndex && usageIndex < 12);
436             inputMapTable[ (inputIndex / 8) * 2 ] |= (usageIndex & 0xF) << (4 * (inputIndex % 8));
437             usedFlag |= 0x1 << usageIndex;
438 
439             // 頂点パラメータの場合の処理
440 
441             u32 data[4] = { 0, 0, 0, 0 };
442 
443             int count = param.GetAttributeCount();
444             f32* fdata = param.GetAttribute();
445 
446             for (int j = 0; j < count; ++j)
447             {
448                 data[j] = ut::Float24::Float32ToBits24( fdata[j] );
449             }
450 
451             command[commandIndex]     = inputIndex;
452             command[commandIndex + 1] = HEADER_VTX_PARAM_INDEX;
453             command[commandIndex + 2] = (data[3] <<  8) | (data[2] >> 16);
454             command[commandIndex + 3] = (data[2] << 16) | (data[1] >> 8);
455             command[commandIndex + 4] = (data[1] << 24) | (data[0]);
456             command[commandIndex + 5] = 0;
457 
458             vertexParamMask[0] |= 1 << (16 + inputIndex);
459 
460             ++inputIndex;
461             commandIndex += 6;
462         }
463     }
464 
465     // 残りの部分には元々固定頂点属性が設定されているのでフラグだけ立てておく。
466     while ( inputIndex < shaderVtxAttrNum )
467     {
468         s32 usage = shaderVtxAttrNum - 1;
469         s32 usageIndex = GetAttributeIndexFromUsage( shaderProgramDesc, usage );
470         while (usedFlag & (0x1 << usageIndex)) { --usageIndex; }
471         inputMapTable[ (inputIndex / 8) * 2 ] |= (usageIndex & 0xF) << (4 * (inputIndex % 8));
472         usedFlag |= 0x1 << usageIndex;
473 
474     #if 0 // 不具合発生時の確認用コード
475         // 残りの部分には (0,0,0,1) の固定属性を設定
476         command[commandIndex]     = inputIndex;
477         command[commandIndex + 1] = HEADER_VTX_PARAM_INDEX;
478         command[commandIndex + 2] = (ut::Float24::Float32ToBits24( 1.0f ) <<  8);
479         command[commandIndex + 3] = 0;
480         command[commandIndex + 4] = 0;
481         command[commandIndex + 5] = 0;
482         commandIndex += 6;
483     #endif
484 
485         vertexParamMask[0] |= 1 << (16 + inputIndex);
486         ++inputIndex;
487     }
488 
489     const u32 HEADER_GEOM_MAP_0 = internal::MakeCommandHeader(REG_GEOM_MAP_0, 1, false, 0xF);
490     const u32 HEADER_GEOM_MAP_1 = internal::MakeCommandHeader(REG_GEOM_MAP_1, 1, false, 0xF);
491 
492     if (shaderProgramDesc.GetGeometryShaderIndex() >= 0)
493     {
494         // TODO: ジオメトリシェーダの入力マップは、ひとまず 0x76543210, 0xfedcba98 に固定
495         command[commandIndex + 0] = 0x76543210;
496         command[commandIndex + 1] = HEADER_GEOM_MAP_0;
497         command[commandIndex + 2] = 0xfedcba98;
498         command[commandIndex + 3] = HEADER_GEOM_MAP_1;
499         commandIndex += 4;
500     }
501 
502     NW_ENSURE_AND_ASSERT( bufferInfo.ForwardCommand( commandIndex * sizeof(u32) ) );
503 
504     return static_cast<s32>(commandIndex * sizeof(u32));
505 }
506 
507 
508 //---------------------------------------------------------------------------
509 template <typename TShape>
510 static s32
SetupDeactivateVertexAttributeCommand_(CommandBufferInfo & bufferInfo,TShape shape,ResShaderProgramDescription shaderProgramDesc)511 SetupDeactivateVertexAttributeCommand_(
512     CommandBufferInfo&          bufferInfo,
513     TShape                      shape,
514     ResShaderProgramDescription shaderProgramDesc
515 )
516 {
517     NW_UNUSED_VARIABLE(shaderProgramDesc);
518 
519     // NOTE:
520     // ・使用したロードアレイの要素数を 0 にリセットする。
521     // ・使用した頂点の設定を固定頂点属性 (0,0,0,0) にクリアする。
522 
523     enum
524     {
525         REG_VTX_ARRAY_VTXMASK     = 0x202,
526         REG_VTX_ARRAY_OFFSET      = 0x203, // [27:0] ロードアレイ0のアドレスオフセット
527         REG_VTX_PARAM_INDEX       = 0x232, // [3:0] 頂点シェーダの入力番号指定。
528         REG_VTX_MAP_0             = 0x2bb, // [31:0] 入力レジスタのインデックス
529         REG_VTX_MAP_1             = 0x2bc  // [15:0] 入力レジスタのインデックス
530     };
531 
532     s32 vtxAttrNum = shape.GetVertexAttributesCount();
533 
534     u32* command = reinterpret_cast<u32*>(bufferInfo.GetCurrentAddress());
535 
536     int inputIndex = 0; // 内部頂点属性番号
537     int arrayIndex = 0; // ロードアレイ番号
538     u32 commandIndex = 0;
539 
540     // 頂点ストリームを番号の若い順に設定
541     for ( s32 i = 0; i < vtxAttrNum; ++ i )
542     {
543         ResVertexAttribute attribute = shape.GetVertexAttributes( i );
544 
545         // 固定頂点属性は後の処理で無効化する。
546         if ( attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM )
547         {
548             ++inputIndex;
549             continue;
550         }
551 
552         if (attribute.GetFlags() & ResVertexAttributeData::FLAG_INTERLEAVE)
553         {
554             ResInterleavedVertexStream interleave = ResStaticCast<ResInterleavedVertexStream>(attribute);
555 
556             // ロードアレイの無効化
557             command[commandIndex    ] = 0;
558             command[commandIndex + 1] = internal::MakeCommandHeader(REG_VTX_ARRAY_OFFSET + 2 + 3 * arrayIndex, 1, false, 0xF);
559             commandIndex += 2;
560 
561             s32 streamCount = interleave.GetVertexStreamsCount();
562             inputIndex += streamCount;
563         }
564         else
565         {
566             // ロードアレイの無効化
567             command[commandIndex    ] = 0;
568             command[commandIndex + 1] = internal::MakeCommandHeader(REG_VTX_ARRAY_OFFSET + 2 + 3 * arrayIndex, 1, false, 0xF);
569             commandIndex += 2;
570 
571             ++inputIndex;
572         }
573 
574         ++arrayIndex;
575     }
576 
577     // 入力レジスタマップを初期化
578     // HACK: ここで設定していなくても正しく表示されるかもしれません。
579     {
580         const u32 INPUT_MAP0 = 0x76543210;
581         const u32 INPUT_MAP1 = 0x0000ba98;
582 
583         command[commandIndex++] = INPUT_MAP0;
584         command[commandIndex++] = internal::MakeCommandHeader(REG_VTX_MAP_0,             2, true,  0xF);
585         command[commandIndex++] = INPUT_MAP1;
586         command[commandIndex++] = 0;
587     }
588 
589     command[commandIndex++] = (static_cast<u32>(inputIndex - 1) << 28) | (((0x1 << inputIndex) - 2) << 16);
590     command[commandIndex++] = internal::MakeCommandHeader(REG_VTX_ARRAY_VTXMASK, 1, false, 0xF);
591 
592     const u32 HEADER_VTX_PARAM_INDEX = internal::MakeCommandHeader(REG_VTX_PARAM_INDEX, 4, true, 0xF);
593 
594     // (0,0,0,0) の固定属性を設定
595     for ( int i = 1; i < inputIndex; ++i )
596     {
597         command[commandIndex]     = i;
598         command[commandIndex + 1] = HEADER_VTX_PARAM_INDEX;
599         command[commandIndex + 2] = 0;
600         command[commandIndex + 3] = 0;
601         command[commandIndex + 4] = 0;
602         command[commandIndex + 5] = 0;
603         commandIndex += 6;
604     }
605 
606     NW_ENSURE_AND_ASSERT( bufferInfo.ForwardCommand( commandIndex * sizeof(u32) ) );
607 
608     return static_cast<s32>( commandIndex * sizeof(u32) );
609 }
610 
611 //--------------------------------------------------------------------------
612 s32
SetupVertexAttributeCommand(CommandBufferInfo & bufferInfo,ResSeparateDataShape shape,ResShaderProgramDescription shaderProgramDesc)613 SetupVertexAttributeCommand(
614     CommandBufferInfo&          bufferInfo,
615     ResSeparateDataShape        shape,
616     ResShaderProgramDescription shaderProgramDesc
617 )
618 {
619     return SetupActivateVertexAttributeCommand_( bufferInfo, shape, shaderProgramDesc );
620 }
621 
622 //--------------------------------------------------------------------------
623 s32
SetupVertexAttributeCommand(CommandBufferInfo & bufferInfo,ResParticleShape shape,ResShaderProgramDescription shaderProgramDesc)624 SetupVertexAttributeCommand(
625     CommandBufferInfo&          bufferInfo,
626     ResParticleShape            shape,
627     ResShaderProgramDescription shaderProgramDesc
628 )
629 {
630     return SetupActivateVertexAttributeCommand_( bufferInfo, shape, shaderProgramDesc );
631 }
632 
633 //--------------------------------------------------------------------------
634 s32
SetupDeactivateVertexAttributeCommand(CommandBufferInfo & bufferInfo,ResSeparateDataShape shape,ResShaderProgramDescription shaderProgramDesc)635 SetupDeactivateVertexAttributeCommand(
636     CommandBufferInfo&          bufferInfo,
637     ResSeparateDataShape        shape,
638     ResShaderProgramDescription shaderProgramDesc
639 )
640 {
641     return SetupDeactivateVertexAttributeCommand_( bufferInfo, shape, shaderProgramDesc );
642 }
643 
644 //--------------------------------------------------------------------------
645 s32
SetupDeactivateVertexAttributeCommand(CommandBufferInfo & bufferInfo,ResParticleShape shape,ResShaderProgramDescription shaderProgramDesc)646 SetupDeactivateVertexAttributeCommand(
647     CommandBufferInfo&          bufferInfo,
648     ResParticleShape            shape,
649     ResShaderProgramDescription shaderProgramDesc
650 )
651 {
652     return SetupDeactivateVertexAttributeCommand_( bufferInfo, shape, shaderProgramDesc );
653 }
654 
655 //--------------------------------------------------------------------------
656 s32
CalcSetupActivateVertexAttributeCommandSize(ResSeparateDataShape shape,ResShaderProgramDescription shaderProgramDesc)657 CalcSetupActivateVertexAttributeCommandSize(
658     ResSeparateDataShape        shape,
659     ResShaderProgramDescription shaderProgramDesc
660 )
661 {
662     return CalcSetupActivateVertexAttributeCommandSize_( shape, shaderProgramDesc );
663 }
664 
665 //--------------------------------------------------------------------------
666 s32
CalcSetupActivateVertexAttributeCommandSize_(ResParticleShape shape,ResShaderProgramDescription shaderProgramDesc)667 CalcSetupActivateVertexAttributeCommandSize_(
668     ResParticleShape            shape,
669     ResShaderProgramDescription shaderProgramDesc
670 )
671 {
672     return CalcSetupActivateVertexAttributeCommandSize_( shape, shaderProgramDesc );
673 }
674 
675 //--------------------------------------------------------------------------
676 s32
CalcSetupDeactivateVertexAttributeCommandSize(ResSeparateDataShape shape,ResShaderProgramDescription shaderProgramDesc)677 CalcSetupDeactivateVertexAttributeCommandSize(
678     ResSeparateDataShape        shape,
679     ResShaderProgramDescription shaderProgramDesc
680 )
681 {
682     return CalcSetupDeactivateVertexAttributeCommandSize_( shape, shaderProgramDesc );
683 }
684 
685 //--------------------------------------------------------------------------
686 s32
CalcSetupDeactivateVertexAttributeCommandSize_(ResParticleShape shape,ResShaderProgramDescription shaderProgramDesc)687 CalcSetupDeactivateVertexAttributeCommandSize_(
688     ResParticleShape            shape,
689     ResShaderProgramDescription shaderProgramDesc
690 )
691 {
692     return CalcSetupDeactivateVertexAttributeCommandSize_( shape, shaderProgramDesc );
693 }
694 
695 
696 //--------------------------------------------------------------------------
697 s32
SetupShaderProgramMode(bool useGeometry)698 SetupShaderProgramMode(bool useGeometry)
699 {
700     // 初回時と 頂点シェーダとジオメトリシェーダの切り替え時のみ、
701     // 0x229[1:0]のコマンドとダミーコマンドを積む。
702 
703     // ジオメトリシェーダのON/OFF切り替え。
704     // ジオメトリシェーダを使用しない場合には、0x244を0にすることで、
705     // 以後、0x2b0-0x2df の設定が 0x280-0x2af にミラーコピーされる。
706 
707     static u32 USE_GEOMETRY_COMMAND[] =
708     {
709         0x00000000, 0x00900251, 0x00000000, 0x00000000,
710         0x00000000, 0x00000000, 0x00000000, 0x00000000,
711         0x00000000, 0x00000000, 0x00000000, 0x00000000,
712         0x00000000, 0x01d00200, 0x00000000, 0x00000000,
713         0x00000000, 0x00000000, 0x00000000, 0x00000000,
714         0x00000000, 0x00000000, 0x00000000, 0x00000000,
715         0x00000000, 0x00000000, 0x00000000, 0x00000000,
716         0x00000000, 0x00000000, 0x00000000, 0x00000000,
717         0x00000000, 0x00000000, 0x00000000, 0x00000000,
718         0x00000000, 0x00000000, 0x00000000, 0x00000000,
719         0x00000000, 0x00000000, 0x00000000, 0x00000000,
720 
721         0x0, 0x00010229,                                // index : 44, 45
722 
723         0x00000000, 0x01d00200, 0x00000000, 0x00000000,
724         0x00000000, 0x00000000, 0x00000000, 0x00000000,
725         0x00000000, 0x00000000, 0x00000000, 0x00000000,
726         0x00000000, 0x00000000, 0x00000000, 0x00000000,
727         0x00000000, 0x00000000, 0x00000000, 0x00000000,
728         0x00000000, 0x00000000, 0x00000000, 0x00000000,
729         0x00000000, 0x00000000, 0x00000000, 0x00000000,
730         0x00000000, 0x00000000, 0x00000000, 0x00000000,
731     };
732 
733     const u32 IDX_REG_229 = 44;
734 
735     if ( useGeometry )
736     {
737         USE_GEOMETRY_COMMAND[ IDX_REG_229 ] = 0x00000002;
738     }
739     else
740     {
741         USE_GEOMETRY_COMMAND[ IDX_REG_229 ] = 0x0;
742     }
743 
744     NWUseCmdlist<sizeof(USE_GEOMETRY_COMMAND)>( &USE_GEOMETRY_COMMAND[0] );
745 
746     return sizeof(USE_GEOMETRY_COMMAND);
747 }
748 
749 
750 //---------------------------------------------------------------------------
751 //! @brief        GL のモードを取得します。
752 //!
753 //! @param[in]    mode 描画モードです。
754 //! @param[in]    isGeometryShaderEnabled ジオメトリシェーダーが有効かどうかを指定します。
755 //!
756 //! @return       GL のモードです。
757 //---------------------------------------------------------------------------
758 static NW_INLINE GLuint
ToPrimitiveModeGL(u8 mode,bool isGeometryShaderEnabled)759 ToPrimitiveModeGL(u8 mode, bool isGeometryShaderEnabled)
760 {
761     static const GLuint PRIM_MODE_TABLE[] =
762     {
763         GL_TRIANGLES,              // Triangles
764         GL_TRIANGLE_STRIP,         // TriangleStrip
765         GL_TRIANGLE_FAN            // TriangleFan
766     };
767 
768     NW_ASSERT( mode < (sizeof(PRIM_MODE_TABLE) / sizeof(GLuint)) );
769 
770     GLuint glMode = PRIM_MODE_TABLE[ mode ];
771     if (isGeometryShaderEnabled)
772     {
773         glMode = GL_GEOMETRY_PRIMITIVE_DMP;
774     }
775 
776     return glMode;
777 }
778 
779 
780 //--------------------------------------------------------------------------
781 s32
CalcSetupDrawIndexStreamCommand(ResIndexStream indexStream)782 CalcSetupDrawIndexStreamCommand(ResIndexStream indexStream)
783 {
784     NW_UNUSED_VARIABLE( indexStream );
785 
786     return 28 * sizeof(u32);
787 }
788 
789 //--------------------------------------------------------------------------
790 // NOTE: コマンドのサイズが変わる場合は、必ず CalcSetupDrawIndexStreamCommand も合わせて修正する。
791 s32
SetupDrawIndexStreamCommand(CommandBufferInfo & bufferInfo,ResIndexStream indexStream,bool hasGeometryShader)792 SetupDrawIndexStreamCommand(
793     CommandBufferInfo&  bufferInfo,
794     ResIndexStream indexStream,
795     bool hasGeometryShader
796 )
797 {
798     enum
799     {
800         REG_INDEX_STREAM_OFFSET     = 0x227,
801         REG_INDEX_STREAM_COUNT      = 0x228,
802         REG_ELEMENTS_MODE           = 0x229, // [23:16]にはバイトイネーブルでアクセスしてはいけない。
803         REG_ELEMENTS_MODE_2         = 0x253, // [31:16]にはバイトイネーブルでアクセスしてはいけない。
804         REG_ELEMENTS_MODE_3         = 0x25e, // [23:16]にはバイトイネーブルでアクセスしてはいけない。
805         REG_TRIANGLE_INDEX_RESET    = 0x25f,
806         REG_DRAW_READY              = 0x245,
807         REG_DRAW_KICK               = 0x22f,
808         REG_VERTEX_CACHE_CLEAR      = 0x231,
809         REG_COLOR_DEPTH_CACHE_CLEAR = 0x110,
810         REG_COLOR_DEPTH_CACHE_FLUSH = 0x111
811     };
812 
813     GLuint mode = ToPrimitiveModeGL(
814         indexStream.GetPrimitiveMode(),
815         hasGeometryShader);
816 
817     const size_t commandCount = 28;
818     u32* command = reinterpret_cast<u32*>( bufferInfo.GetCurrentAddress() );
819 
820     u32 baseAddr = nngxGetPhysicalAddr(nn::gx::GetVramStartAddr(nn::gx::MEM_VRAMA));
821     u32 bufferAddr = nngxGetPhysicalAddr( indexStream.GetImageAddress() );
822 
823     NW_ASSERT((bufferAddr - baseAddr) < 0x10000000);
824 
825     const u32 HEADER_INDEX_STREAM_OFFSET = internal::MakeCommandHeader(REG_INDEX_STREAM_OFFSET, 1, false, 0xF);
826     const u32 HEADER_INDEX_STREAM_COUNT  = internal::MakeCommandHeader(REG_INDEX_STREAM_COUNT, 1, false, 0xF);
827 
828     command[0] = (bufferAddr - baseAddr);
829     command[1] = HEADER_INDEX_STREAM_OFFSET;
830     command[2] = indexStream.GetStreamCount();
831     command[3] = HEADER_INDEX_STREAM_COUNT;
832 
833     // CTR では GL_UNSIGNED_INT は未対応です。
834     if (indexStream.GetFormatType() == GL_UNSIGNED_SHORT)
835     {
836          command[0] |= 0x80000000;
837          command[2] /= 2;
838     }
839 
840     const u32 HEADER_ELEMENTS_MODE   = internal::MakeCommandHeader(REG_ELEMENTS_MODE, 1, false, 0x2);
841     const u32 HEADER_ELEMENTS_MODE_2 = internal::MakeCommandHeader(REG_ELEMENTS_MODE_2, 1, false, 0x2);
842 
843     if (mode == GL_TRIANGLES)
844     {
845         command[4] = 1 << 8;
846         command[5] = HEADER_ELEMENTS_MODE;
847         command[6] = 1 << 8;
848         command[7] = HEADER_ELEMENTS_MODE_2;
849     }
850     else
851     {
852         command[4] = 0;
853         command[5] = HEADER_ELEMENTS_MODE;
854         command[6] = 0;
855         command[7] = HEADER_ELEMENTS_MODE_2;
856     }
857 
858     switch (mode)
859     {
860     case GL_TRIANGLES:              command[8] = 3 << 8; break;
861     case GL_TRIANGLE_STRIP:         command[8] = 1 << 8; break;
862     case GL_TRIANGLE_FAN:           command[8] = 2 << 8; break;
863     case GL_GEOMETRY_PRIMITIVE_DMP: command[8] = 3 << 8; break;
864     }
865 
866     u32 commandIndex = 9;
867 
868     command[commandIndex++] = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x2);
869     command[commandIndex++] = 1;
870     command[commandIndex++] = internal::MakeCommandHeader(REG_TRIANGLE_INDEX_RESET, 1, false, 0xF);
871     command[commandIndex++] = 0;
872     command[commandIndex++] = internal::MakeCommandHeader(REG_DRAW_READY, 1, false, 0xF);
873     command[commandIndex++] = 1;
874     command[commandIndex++] = internal::MakeCommandHeader(REG_DRAW_KICK, 1, false, 0xF);
875     command[commandIndex++] = 1;
876     command[commandIndex++] = internal::MakeCommandHeader(REG_DRAW_READY, 1, false, 0xF);
877     command[commandIndex++] = 1;
878     command[commandIndex++] = internal::MakeCommandHeader(REG_VERTEX_CACHE_CLEAR, 1, false, 0xF);
879     command[commandIndex++] = 0;
880     command[commandIndex++] = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x8);
881     command[commandIndex++] = 0;
882     command[commandIndex++] = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x8);
883     command[commandIndex++] = 1;
884     command[commandIndex++] = internal::MakeCommandHeader(REG_COLOR_DEPTH_CACHE_FLUSH, 1, false, 0xF);
885     command[commandIndex++] = 1;
886     command[commandIndex++] = internal::MakeCommandHeader(REG_COLOR_DEPTH_CACHE_CLEAR, 1, false, 0xF);
887 
888     NW_ENSURE_AND_ASSERT( bufferInfo.ForwardCommand(commandIndex * sizeof(u32)) );
889 
890     return commandIndex * sizeof(u32);
891 }
892 
893 } // namespace internal
894 
895 } // namespace gfx
896 } // namespace nw
897 
898