1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ParticleShape.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: 25788 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nn/gx.h>
19 
20 #include <nw/gfx/gfx_ParticleShape.h>
21 #include <nw/gfx/gfx_ISceneVisitor.h>
22 #include <nw/gfx/res/gfx_ResVertex.h>
23 
24 #include <nw/ut/ut_ResUtil.h>
25 #include <nw/ut/ut_ResDictionary.h>
26 #include <nw/ut/ut_Foreach.h>
27 
28 namespace nw
29 {
30 namespace gfx
31 {
32 
33 NW_UT_RUNTIME_TYPEINFO_DEFINITION(ParticleShape, SceneObject);
34 
35 static const int MAX_ATTRIBUTES_NUM = 12;
36 
37 //----------------------------------------
38 static void
SetupParticleVertexAttributeCommand(ParticleShape * shape,ParticleSet * particleSet,ParticleBuffer bufferSide)39 SetupParticleVertexAttributeCommand(
40     ParticleShape* shape,
41     ParticleSet* particleSet,
42     ParticleBuffer bufferSide)
43 {
44     ParticleCollection* collection = particleSet->GetParticleCollection();
45 
46     enum
47     {
48         REG_VTX_SHADER_ATTR_NUM   = 0x2b9, // [3:0] 頂点属性数 - 1
49         REG_VTX_SHADER_ATTR_NUM_2 = 0x242, // [3:0] 頂点族整数 - 1
50         REG_VTX_MAP_0             = 0x2bb, // [31:0] 入力レジスタのインデックス
51         REG_VTX_MAP_1             = 0x2bc, // [15:0] 入力レジスタのインデックス
52         REG_VTX_STREAM_BASE       = 0x200, // [28:1] 頂点アレイのベースアドレス
53         REG_VTX_ARRAY_OFFSET      = 0x203, // [27:0] ロードアレイ0のアドレスオフセット
54         REG_VTX_PARAM_INDEX       = 0x232, // [3:0] 頂点シェーダの入力番号指定
55         REG_GEOM_MAP_0            = 0x28b, // [31:0] 入力レジスタのインデックス
56         REG_GEOM_MAP_1            = 0x28c  // [15:0] 入力レジスタのインデックス
57     };
58 
59     u32 baseAddr = nngxGetPhysicalAddr(nn::gx::GetVramStartAddr(nn::gx::MEM_VRAMA));
60 
61     s32 vtxAttrNum = shape->GetVertexAttributesCount();
62 
63     u32* command = reinterpret_cast<u32*>(shape->m_CommandCache[bufferSide]);
64 
65     const u32 HEADER_VTX_SHADER_ATTR_NUM   = internal::MakeCommandHeader(REG_VTX_SHADER_ATTR_NUM, 1, false, 0xb);
66     const u32 HEADER_VTX_SHADER_ATTR_NUM_2 = internal::MakeCommandHeader(REG_VTX_SHADER_ATTR_NUM_2, 1, false, 0x1);
67     const u32 HEADER_VTX_MAP_0             = internal::MakeCommandHeader(REG_VTX_MAP_0, 2, true, 0xF);
68 
69 
70     command[0] = (vtxAttrNum - 1) | 0xa0000000;
71     command[1] = HEADER_VTX_SHADER_ATTR_NUM;
72 
73     command[2] = (vtxAttrNum - 1);
74     command[3] = HEADER_VTX_SHADER_ATTR_NUM_2;
75 
76     command[4] = 0;
77     command[5] = HEADER_VTX_MAP_0;
78     command[6] = 0;
79     command[7] = 0;
80 
81     NW_ASSERT((baseAddr & 0x0f) == 0);
82     command[8] = baseAddr >> 3;
83     command[9] = internal::MakeCommandHeader(REG_VTX_STREAM_BASE, 3 + vtxAttrNum * 3, true, 0xF);
84     command[10] = 0;
85     command[11] = static_cast<u32>(vtxAttrNum - 1) << 28;
86 
87     u32* inputTable  = &command[4];
88     u32* inputFormat = &command[10];
89     u32* vertexParamMask = &command[11];
90 
91     int inputIndex = 0; // 内部頂点属性番号
92     u32 commandIndex = 12;
93 
94     u32 usedFlag = 0;
95 
96     // 頂点ストリームを番号の若い順に設定
97     for (s32 i = 0; i < shape->GetVertexAttributesCount(); ++i)
98     {
99         if (shape->IsVertexStream(i))
100         {
101             s32 usage = shape->GetVertexAttributeUsage(i);
102             NW_ASSERT(0 <= usage && usage < 12);
103             inputTable[ (inputIndex / 8) * 2 ] |= (usage & 0xF) << (4 * (inputIndex % 8));
104             usedFlag |= 0x1 << usage;
105 
106             u32 format    = shape->GetVertexAttributeFormatType(i);
107             u32 dimension = shape->GetVertexAttributeDimension(i);
108 
109             inputFormat[ inputIndex / 8 ] |= internal::CommandCacheHelper::GetVertexFormat(dimension, format) << ((inputIndex % 8) * 4);
110 
111             // ロードアレイの設定
112             u8* streamPtr = shape->GetVertexStreamPtr(i, bufferSide);
113             NW_NULL_ASSERT(streamPtr);
114             u32 bufferAddr = nngxGetPhysicalAddr(reinterpret_cast<uptr>(streamPtr));
115 
116             shape->SetVertexAttributeCommandPtr(i, bufferSide, &command[commandIndex]);
117 
118             // このクラスでは interleave 形式には対応しないので、(0番目の要素 == 内部頂点属性 index 番目)
119             NW_ASSERT((bufferAddr - baseAddr) < 0x10000000);
120             command[commandIndex++] = bufferAddr - baseAddr;
121             command[commandIndex++] = inputIndex;
122             command[commandIndex++] = (internal::CommandCacheHelper::GetVertexSize(dimension, format) << 16) + (1 <<  28);
123 
124             ++inputIndex;
125         }
126     }
127 
128     // パラメータの分を設定
129     for (s32 i = inputIndex; i < vtxAttrNum; ++i)
130     {
131         command[commandIndex++] = 0;
132         command[commandIndex++] = 0;
133         command[commandIndex++] = 0;
134     }
135 
136     // 64bit単位になるようにパディング
137     if ((commandIndex & 1) == 1)
138     {
139         command[commandIndex++] = 0;
140     }
141 
142     // 頂点ストリームの後に頂点パラメータを設定。
143     for (s32 i = 0; i < shape->GetVertexAttributesCount(); ++i)
144     {
145         if (!shape->IsVertexStream(i))
146         {
147             s32 usage = shape->GetVertexAttributeUsage(i);
148             NW_ASSERT(0 <= usage && usage < 12);
149             inputTable[ (inputIndex / 8) * 2 ] |= (usage & 0xF) << (4 * (inputIndex % 8));
150             usedFlag |= 0x1 << usage;
151 
152             // 頂点パラメータの場合の処理
153 
154             u32 data[4] = { 0, 0, 0, 0 };
155 
156             int count = shape->GetVertexAttributeDimension(i);
157             f32* fdata = shape->GetVertexParameter(i);
158 
159             for (int j = 0; j < count; ++j)
160             {
161                 data[j] = ut::Float24::Float32ToBits24(fdata[j]);
162             }
163 
164             const u32 HEADER_VTX_PARAM_INDEX = internal::MakeCommandHeader(REG_VTX_PARAM_INDEX, 4, true, 0xF);
165 
166             shape->SetVertexAttributeCommandPtr(i, bufferSide, &command[commandIndex + 2]);
167 
168             command[commandIndex]     = inputIndex;
169             command[commandIndex + 1] = HEADER_VTX_PARAM_INDEX;
170             command[commandIndex + 2] = (data[3] <<  8) | (data[2] >> 16);
171             command[commandIndex + 3] = (data[2] << 16) | (data[1] >> 8);
172             command[commandIndex + 4] = (data[1] << 24) | (data[0]);
173             command[commandIndex + 5] = 0;
174 
175             vertexParamMask[0] |= 1 << (16 + inputIndex);
176 
177             ++inputIndex;
178             commandIndex += 6;
179         }
180     }
181 
182     const u32 HEADER_GEOM_MAP_0 = internal::MakeCommandHeader(REG_GEOM_MAP_0, 2, true, 0xF);
183 
184     command[commandIndex + 0] = 0x76543210;
185     command[commandIndex + 1] = HEADER_GEOM_MAP_0;
186     command[commandIndex + 2] = 0xfedcba98;
187     command[commandIndex + 3] = 0;
188     commandIndex += 4;
189 
190     shape->m_CommandCacheSize[bufferSide] = commandIndex * sizeof(u32);
191 }
192 
193 
194 //----------------------------------------
195 static void
SetupDeactivateParticleVertexAttributeCommand(ParticleShape * shape)196 SetupDeactivateParticleVertexAttributeCommand(
197     ParticleShape* shape)
198 {
199     enum
200     {
201         REG_VTX_ARRAY_OFFSET      = 0x203, // [27:0] ロードアレイ0のアドレスオフセット
202         REG_VTX_PARAM_INDEX       = 0x232  // [3:0] 頂点シェーダの入力番号指定
203     };
204 
205     s32 vtxAttrNum = shape->GetVertexAttributesCount();
206 
207     u32* command = reinterpret_cast<u32*>(shape->m_DeactivateVertexCommandCache);
208 
209     shape->m_DeactivateVertexCommandCache = command;
210 
211     int inputIndex = 0; // 内部頂点属性番号
212     u32 commandIndex = 0;
213 
214     // 頂点ストリームを番号の若い順に設定
215     for (s32 i = 0; i < vtxAttrNum; ++i)
216     {
217         if (shape->IsVertexStream(i))
218         {
219             // ロードアレイの無効化
220             // このクラスでは interleave 形式には対応しないので、(0番目の要素 == 内部頂点属性 index 番目)
221             command[commandIndex++] = 0;
222             command[commandIndex++] = internal::MakeCommandHeader(REG_VTX_ARRAY_OFFSET + 2 + 3 * inputIndex, 1, false, 0xF);
223 
224             ++inputIndex;
225         }
226     }
227 
228     const u32 HEADER_VTX_PARAM_INDEX = internal::MakeCommandHeader(REG_VTX_PARAM_INDEX, 4, true, 0xF);
229 
230     // (0,0,0,0) の固定属性を設定
231     for ( int i = 0; i < inputIndex; ++i )
232     {
233         command[commandIndex++] = i;
234         command[commandIndex++] = HEADER_VTX_PARAM_INDEX;
235         command[commandIndex++] = 0;
236         command[commandIndex++] = 0;
237         command[commandIndex++] = 0;
238         command[commandIndex++] = 0;
239     }
240 
241     shape->m_DeactivateVertexCommandCacheSize = commandIndex * sizeof(u32);
242 
243     NW_ASSERT( shape->m_DeactivateVertexCommandCacheSize <=  sizeof(u32) * (MAX_ATTRIBUTES_NUM * 8) );
244 }
245 
246 static const int PrimitiveCommandSize = 26;
247 
248 //----------------------------------------
249 static void
CreatePrimitiveCommandCache(ParticleShape * shape,ResParticleSet resParticleSet)250 CreatePrimitiveCommandCache(
251     ParticleShape* shape,
252     ResParticleSet resParticleSet)
253 {
254     enum
255     {
256         REG_VERTEX_UNIFORM_BOOL     = 0x2b0,
257 
258         REG_ELEMENTS_MODE           = 0x229, // [23:16]にはバイトイネーブルでアクセスしてはいけない。
259         REG_ELEMENTS_MODE_2         = 0x253, // [31:16]にはバイトイネーブルでアクセスしてはいけない。
260         REG_ELEMENTS_MODE_3         = 0x25e, // [31:16]にはバイトイネーブルでアクセスしてはいけない。
261         REG_TRIANGLE_INDEX_RESET    = 0x25f,
262         REG_DRAW_READY              = 0x245,
263         REG_DRAW_KICK               = 0x22f,
264         REG_VERTEX_CACHE_CLEAR      = 0x231,
265         REG_COLOR_DEPTH_CACHE_CLEAR = 0x110,
266         REG_COLOR_DEPTH_CACHE_FLUSH = 0x111
267     };
268 
269     u32* command = reinterpret_cast<u32*>(shape->m_PrimitiveCommandCache);
270 
271     u32 commandIndex = 0;
272 
273     s32 type;
274     switch (resParticleSet.GetParticleShapeBuilder().GetTypeInfo())
275     {
276     case ResParticleBillboardShapeBuilder::TYPE_INFO:
277         type = 0;
278         break;
279     case ResParticleWorldBillboardShapeBuilder::TYPE_INFO:
280         type = 8;
281         break;
282     case ResParticleYBillboardShapeBuilder::TYPE_INFO:
283         type = 2 | 1;
284         break;
285     case ResParticleXyPlaneShapeBuilder::TYPE_INFO:
286         type = 4 | 1;
287         break;
288     default:
289         NW_FATAL_ERROR("unknown shapebuilder type");
290         break;
291     }
292 
293     const u32 HEADER_VERTEX_UNIFORM_BOOL     = internal::MakeCommandHeader(REG_VERTEX_UNIFORM_BOOL, 5, true, 0xF);
294 
295     const u32 HEADER_ELEMENTS_MODE           = internal::MakeCommandHeader(REG_ELEMENTS_MODE, 1, false, 0x2);
296     const u32 HEADER_ELEMENTS_MODE_2         = internal::MakeCommandHeader(REG_ELEMENTS_MODE_2, 1, false, 0x2);
297     const u32 HEADER_ELEMENTS_MODE_3         = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x2);
298     const u32 HEADER_TRIANGLE_INDEX_RESET    = internal::MakeCommandHeader(REG_TRIANGLE_INDEX_RESET, 1, false, 0xF);
299     const u32 HEADER_DRAW_READY              = internal::MakeCommandHeader(REG_DRAW_READY, 1, false, 0xF);
300     const u32 HEADER_DRAW_KICK               = internal::MakeCommandHeader(REG_DRAW_KICK, 1, false, 0xF);
301     const u32 HEADER_VERTEX_CACHE_CLEAR      = internal::MakeCommandHeader(REG_VERTEX_CACHE_CLEAR, 1, false, 0xF);
302     const u32 HEADER_COLOR_DEPTH_CACHE_FLUSH = internal::MakeCommandHeader(REG_COLOR_DEPTH_CACHE_FLUSH, 1, false, 0xF);
303     const u32 HEADER_COLOR_DEPTH_CACHE_CLEAR = internal::MakeCommandHeader(REG_COLOR_DEPTH_CACHE_CLEAR, 1, false, 0xF);
304 
305     command[commandIndex++] = 0x7fff0000 | (type << 1); // bit0は予約されているため、bit1から配置する
306     command[commandIndex++] = HEADER_VERTEX_UNIFORM_BOOL;
307     command[commandIndex++] = 0;
308     command[commandIndex++] = 0;
309     command[commandIndex++] = 0;
310     command[commandIndex++] = 0;
311 
312     command[commandIndex++] = 0;
313     command[commandIndex++] = HEADER_ELEMENTS_MODE;
314     command[commandIndex++] = 0;
315     command[commandIndex++] = HEADER_ELEMENTS_MODE_2;
316     command[commandIndex++] = 3 << 8;
317     command[commandIndex++] = HEADER_ELEMENTS_MODE_3;
318     command[commandIndex++] = 1;
319     command[commandIndex++] = HEADER_TRIANGLE_INDEX_RESET;
320     command[commandIndex++] = 0;
321     command[commandIndex++] = HEADER_DRAW_READY;
322     command[commandIndex++] = 1;
323     command[commandIndex++] = HEADER_DRAW_KICK;
324     command[commandIndex++] = 1;
325     command[commandIndex++] = HEADER_DRAW_READY;
326     command[commandIndex++] = 1;
327     command[commandIndex++] = HEADER_VERTEX_CACHE_CLEAR;
328     command[commandIndex++] = 1;
329     command[commandIndex++] = HEADER_COLOR_DEPTH_CACHE_FLUSH;
330     command[commandIndex++] = 1;
331     command[commandIndex++] = HEADER_COLOR_DEPTH_CACHE_CLEAR;
332 
333     NW_ASSERT(commandIndex == PrimitiveCommandSize);
334 
335     shape->m_PrimitiveCommandCacheSize = commandIndex * sizeof(u32);
336 }
337 
338 //----------------------------------------
339 void
CreateCommandCache(ParticleSet * particleSet)340 ParticleShape::CreateCommandCache(
341     ParticleSet* particleSet
342 )
343 {
344     for (int side = 0; side < 2; ++side)
345     {
346         SetupParticleVertexAttributeCommand(
347             this,
348             particleSet,
349             (ParticleBuffer)side);
350     }
351 
352     SetupDeactivateParticleVertexAttributeCommand(this);
353 
354     CreatePrimitiveCommandCache(
355         this,
356         particleSet->GetResParticleSet());
357 }
358 
359 void
GetMemorySizeInternal(os::MemorySizeCalculator * pSize,int capacity)360 ParticleShape::GetMemorySizeInternal(
361     os::MemorySizeCalculator* pSize,
362     int capacity)
363 {
364     os::MemorySizeCalculator& size = *pSize;
365 
366     const int streamSize = (capacity + internal::PARTICLE_SIMD_WIDTH_MAX) * sizeof(u16);
367     const int drawCommandCacheSize = sizeof(u32) * (12 + MAX_ATTRIBUTES_NUM * 6 + MAX_ATTRIBUTES_NUM * 4 + 4);
368     const int primitiveCommandCacheSize = sizeof(u32) * PrimitiveCommandSize;
369     const int deactivateVertexCommandCacheSize = sizeof(u32) * (MAX_ATTRIBUTES_NUM * 8);
370 
371     int deviceMemorySize = 0;
372     if (size.GetAlignment() < 32)
373     {
374         deviceMemorySize += 32 - size.GetAlignment(); // 最悪値
375     }
376 
377     deviceMemorySize = ut::RoundUp(deviceMemorySize, 32);
378     deviceMemorySize += streamSize;
379     deviceMemorySize = ut::RoundUp(deviceMemorySize, 32);
380     deviceMemorySize += streamSize;
381 
382     int nodeMemorySize = sizeof(ParticleShape);
383     nodeMemorySize = ut::RoundUp(nodeMemorySize, 32);
384     nodeMemorySize += drawCommandCacheSize;
385     nodeMemorySize = ut::RoundUp(nodeMemorySize, 32);
386     nodeMemorySize += drawCommandCacheSize;
387     nodeMemorySize = ut::RoundUp(nodeMemorySize, 32);
388     nodeMemorySize += deactivateVertexCommandCacheSize;
389     nodeMemorySize = ut::RoundUp(nodeMemorySize, 32);
390     nodeMemorySize += primitiveCommandCacheSize;
391     nodeMemorySize = ut::RoundUp(nodeMemorySize, 32);
392 
393     size.Add(nodeMemorySize, 32);
394 }
395 
396 void
GetDeviceMemorySizeInternal(os::MemorySizeCalculator * pSize,int capacity)397 ParticleShape::GetDeviceMemorySizeInternal(
398     os::MemorySizeCalculator* pSize,
399     int capacity)
400 {
401     os::MemorySizeCalculator& size = *pSize;
402 
403     const int streamSize = (capacity + internal::PARTICLE_SIMD_WIDTH_MAX) * sizeof(u16);
404     const int drawCommandCacheSize = sizeof(u32) * (12 + MAX_ATTRIBUTES_NUM * 6 + MAX_ATTRIBUTES_NUM * 4 + 4);
405     const int primitiveCommandCacheSize = sizeof(u32) * PrimitiveCommandSize;
406     const int deactivateVertexCommandCacheSize = sizeof(u32) * (MAX_ATTRIBUTES_NUM * 8);
407 
408     int deviceMemorySize = 0;
409     if (size.GetAlignment() < 32)
410     {
411         deviceMemorySize += 32 - size.GetAlignment(); // 最悪値
412     }
413 
414     deviceMemorySize = ut::RoundUp(deviceMemorySize, 32);
415     deviceMemorySize += streamSize;
416     deviceMemorySize = ut::RoundUp(deviceMemorySize, 32);
417     deviceMemorySize += streamSize;
418 
419     size.Add(deviceMemorySize, 32);
420 }
421 
422 //----------------------------------------
423 ParticleShape*
Create(ResSceneObject resource,int capacity,os::IAllocator * mainAllocator,os::IAllocator * deviceAllocator)424 ParticleShape::Create(
425     ResSceneObject resource,
426     int capacity,
427     os::IAllocator* mainAllocator,
428     os::IAllocator* deviceAllocator
429 )
430 {
431     NW_NULL_ASSERT(mainAllocator);
432     NW_NULL_ASSERT(deviceAllocator);
433 
434     ResParticleShape resNode = ResDynamicCast<ResParticleShape>(resource);
435     NW_ASSERT(resNode.IsValid());
436 
437     const int streamSize = (capacity + internal::PARTICLE_SIMD_WIDTH_MAX) * sizeof(u16);
438     const int drawCommandCacheSize = sizeof(u32) * (12 + MAX_ATTRIBUTES_NUM * 6 + MAX_ATTRIBUTES_NUM * 4 + 4);
439     const int primitiveCommandCacheSize = sizeof(u32) * PrimitiveCommandSize;
440     const int deactivateVertexCommandCacheSize = sizeof(u32) * (MAX_ATTRIBUTES_NUM * 8);
441 
442     int deviceMemorySize = 0;
443     deviceMemorySize = ut::RoundUp(deviceMemorySize, 32);
444     deviceMemorySize += streamSize;
445     deviceMemorySize = ut::RoundUp(deviceMemorySize, 32);
446     deviceMemorySize += streamSize;
447 
448     int nodeMemorySize = sizeof(ParticleShape);
449     nodeMemorySize = ut::RoundUp(nodeMemorySize, 32);
450     nodeMemorySize += drawCommandCacheSize;
451     nodeMemorySize = ut::RoundUp(nodeMemorySize, 32);
452     nodeMemorySize += drawCommandCacheSize;
453     nodeMemorySize = ut::RoundUp(nodeMemorySize, 32);
454     nodeMemorySize += deactivateVertexCommandCacheSize;
455     nodeMemorySize = ut::RoundUp(nodeMemorySize, 32);
456     nodeMemorySize += primitiveCommandCacheSize;
457     nodeMemorySize = ut::RoundUp(nodeMemorySize, 32);
458 
459     u8* devicememory = reinterpret_cast<u8*>(deviceAllocator->Alloc(deviceMemorySize, 32));
460     if (devicememory == NULL)
461     {
462         return NULL;
463     }
464 
465     u8* nodememory = reinterpret_cast<u8*>(mainAllocator->Alloc(nodeMemorySize, 32));
466     if (nodememory == NULL)
467     {
468         deviceAllocator->Free(devicememory);
469         return NULL;
470     }
471 
472     ParticleShape* node = new(nodememory) ParticleShape(
473         capacity,
474         mainAllocator,
475         deviceAllocator,
476         devicememory,
477         resNode);
478     nodememory += sizeof(ParticleShape);
479 
480     for (int i = 0; i < 2; ++i)
481     {
482         devicememory = reinterpret_cast<u8*>(ut::RoundUp(devicememory, 32));
483         node->m_PrimitiveBuffer[i] = devicememory;
484         devicememory += streamSize;
485 
486         //std::memset(node->m_PrimitiveBuffer[i], 0, streamSize);
487 
488         u32 baseAddr = nngxGetPhysicalAddr(nn::gx::GetVramStartAddr(nn::gx::MEM_VRAMA));
489         u32 bufferAddr = nngxGetPhysicalAddr(reinterpret_cast<uptr>(node->m_PrimitiveBuffer[i]));
490 
491         NW_ASSERT((bufferAddr - baseAddr) < 0x10000000);
492         node->m_PrimitiveBufferOffset[i] = bufferAddr - baseAddr;
493     }
494 
495     for (int side = 0; side < 2; ++side)
496     {
497         nodememory = reinterpret_cast<u8*>(ut::RoundUp(nodememory, 32));
498         node->m_CommandCache[side] = reinterpret_cast<u32*>(nodememory);
499         nodememory += drawCommandCacheSize;
500     }
501 
502     nodememory = reinterpret_cast<u8*>(ut::RoundUp(nodememory, 32));
503     node->m_DeactivateVertexCommandCache = reinterpret_cast<u32*>(nodememory);
504     nodememory += deactivateVertexCommandCacheSize;
505 
506     nodememory = reinterpret_cast<u8*>(ut::RoundUp(nodememory, 32));
507     node->m_PrimitiveCommandCache = reinterpret_cast<u32*>(nodememory);
508     nodememory += primitiveCommandCacheSize;
509 
510     return node;
511 }
512 
513 int
AddVertexStreamSize(u32 formatType,int dimension,int capacity,int prevSize)514 ParticleShape::AddVertexStreamSize(
515     u32 formatType,
516     int dimension,
517     int capacity,
518     int prevSize
519 )
520 {
521     int formatSize = 1;
522     switch (formatType)
523     {
524     case GL_FLOAT:
525         formatSize = 4;
526         break;
527     default:
528         NW_FATAL_ERROR("unsupported formatType");
529     }
530 
531     int streamSize = (capacity + internal::PARTICLE_SIMD_WIDTH_MAX) * dimension * formatSize;
532 
533     prevSize = ut::RoundUp(prevSize, 32);
534     prevSize += streamSize;
535     prevSize = ut::RoundUp(prevSize, 32);
536     prevSize += streamSize;
537 
538     return prevSize + streamSize;
539 }
540 
541 ParticleShape::VertexAttribute*
AddVertexStream(s32 usage,u32 formatType,int dimension,int capacity,u8 ** memory)542 ParticleShape::AddVertexStream(
543     s32 usage,
544     u32 formatType,
545     int dimension,
546     int capacity,
547     u8** memory
548 )
549 {
550     int formatSize = 1;
551     switch (formatType)
552     {
553     case GL_FLOAT:
554         formatSize = 4;
555         break;
556     default:
557         NW_FATAL_ERROR("unsupported formatType");
558     }
559 
560     *memory = reinterpret_cast<u8*>(ut::RoundUp(*memory, 32));
561 
562     int streamSize = (capacity + internal::PARTICLE_SIMD_WIDTH_MAX) * dimension * formatSize;
563     void* stream0 = *memory;
564     *memory += streamSize;
565 
566     void* stream1 = *memory;
567     *memory += streamSize;
568 
569     std::memset(stream0, 0, streamSize);
570     std::memset(stream1, 0, streamSize);
571 
572     return this->AddVertexAttribute(
573         usage,
574         formatType,
575         dimension,
576         true,
577         reinterpret_cast<u8*>(stream0),
578         reinterpret_cast<u8*>(stream1));
579 }
580 
581 int
AddVertexParamSize(u32 formatType,int dimension,int prevSize)582 ParticleShape::AddVertexParamSize(
583     u32 formatType,
584     int dimension,
585     int prevSize
586 )
587 {
588     int formatSize = 1;
589     switch (formatType)
590     {
591     case GL_FLOAT:
592         formatSize = 4;
593         break;
594     default:
595         NW_FATAL_ERROR("unsupported formatType");
596     }
597 
598     prevSize = ut::RoundUp(prevSize, 32);
599 
600     int streamSize = dimension * formatSize;
601 
602     return prevSize + streamSize;
603 }
604 
605 ParticleShape::VertexAttribute*
AddVertexParam(s32 usage,u32 formatType,int dimension,f32 * parameters,u8 ** memory)606 ParticleShape::AddVertexParam(
607     s32 usage,
608     u32 formatType,
609     int dimension,
610     f32* parameters,
611     u8** memory
612 )
613 {
614     NW_UNUSED_VARIABLE(parameters);
615 
616     int formatSize = 1;
617     switch (formatType)
618     {
619     case GL_FLOAT:
620         formatSize = 4;
621         break;
622     default:
623         NW_FATAL_ERROR("unsupported formatType");
624     }
625 
626     int streamSize = dimension * formatSize;
627     *memory = reinterpret_cast<u8*>(ut::RoundUp(*memory, 32));
628     void* stream = *memory;
629     *memory += streamSize;
630 
631     std::memcpy(stream, parameters, streamSize);
632 
633     return this->AddVertexAttribute(
634         usage,
635         formatType,
636         dimension,
637         false,
638         reinterpret_cast<u8*>(stream),
639         NULL);
640 }
641 
642 //----------------------------------------
ParticleShape(int capacity,os::IAllocator * allocator,os::IAllocator * deviceAllocator,void * deviceMemory,ResParticleShape resObj)643 ParticleShape::ParticleShape(
644     int capacity,
645     os::IAllocator* allocator,
646     os::IAllocator* deviceAllocator,
647     void* deviceMemory,
648     ResParticleShape resObj)
649     : SceneObject(allocator, resObj),
650     m_Capacity(capacity),
651     m_BufferSide(false),
652     m_ResVertexAttributeDataCount(0),
653     m_DeviceAllocator(deviceAllocator),
654     m_DeviceMemory(deviceMemory)
655 {
656     m_PrimitiveBuffer[0] = NULL;
657     m_PrimitiveBuffer[1] = NULL;
658     m_PrimitiveBufferOffset[0] = 0;
659     m_PrimitiveBufferOffset[1] = 0;
660 
661     for (int usage = 0; usage < PARTICLEUSAGE_COUNT; ++usage)
662     {
663         for (int side = 0; side < 2; ++side)
664         {
665             m_VertexAttribute[usage].m_Stream[side] = NULL;
666             m_VertexAttribute[usage].m_CommandPtr[side] = NULL;
667         }
668     }
669 
670     for (int i = 0; i < 2; ++i)
671     {
672         m_CommandCache[i] = NULL;
673         m_CommandCacheSize[i] = 0;
674     }
675 
676     m_DeactivateVertexCommandCache = NULL;
677     m_DeactivateVertexCommandCacheSize = 0;
678     m_PrimitiveCommandCache = NULL;
679     m_PrimitiveCommandCacheSize = 0;
680 }
681 
682 //----------------------------------------
~ParticleShape()683 ParticleShape::~ParticleShape()
684 {
685     m_DeviceAllocator->Free(m_DeviceMemory);
686 
687     for (int i = 0; i < 2; ++ i)
688     {
689         if (this->m_CommandCache[i] != NULL)
690         {
691             this->m_CommandCache[i] = NULL;
692             this->m_CommandCacheSize[i] = 0;
693         }
694     }
695 
696     if (this->m_DeactivateVertexCommandCache != NULL)
697     {
698         this->m_DeactivateVertexCommandCache = NULL;
699         this->m_DeactivateVertexCommandCacheSize = 0;
700     }
701 
702     if (this->m_PrimitiveCommandCache != NULL)
703     {
704         this->m_PrimitiveCommandCache = NULL;
705         this->m_PrimitiveCommandCacheSize = 0;
706     }
707 }
708 
709 void
FlushBuffer()710 ParticleShape::FlushBuffer()
711 {
712     for (s32 i = 0; i < this->GetVertexAttributesCount(); ++i)
713     {
714         if (this->IsVertexStream(i))
715         {
716             nngxUpdateBuffer(
717                 this->GetVertexStreamPtr(i, PARTICLE_BUFFER_FRONT),
718                 this->GetVertexCapacity() * this->GetVertexAttributeDimension(i) * sizeof(f32));
719         }
720     }
721 
722     nngxUpdateBuffer(
723         this->GetPrimitiveStreamPtr(PARTICLE_BUFFER_FRONT),
724         this->GetVertexCapacity() * sizeof(u16));
725 }
726 
727 } // namespace gfx
728 } // namespace nw
729