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