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