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