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