1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_ResShape.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: $
16 *---------------------------------------------------------------------------*/
17
18 #include "../precompiled.h"
19
20 #include <nw/ut/ut_ResUtil.h>
21 #include <nw/ut/ut_ResDictionary.h>
22 #include <nw/gfx/gfx_SceneObject.h>
23 #include <nw/gfx/res/gfx_ResShape.h>
24 #include <nw/gfx/res/gfx_ResParticleShape.h>
25 #include <nw/gfx/res/gfx_ResTexture.h>
26 #include <nw/gfx/gfx_Common.h>
27 #include <GLES2/gl2.h>
28 #include <GLES2/gl2ext.h>
29 #include <nw/gfx/gfx_CommandUtil.h>
30
31 #include <nn/gx.h>
32
33 namespace nw {
34 namespace gfx {
35 namespace res {
36
37 typedef void (*SetupFunc)(nw::os::IAllocator* allocator, ResShape resShape);
38 typedef void (*CleanupFunc)(ResShape resShape);
39
40 static void ResShape_Setup(nw::os::IAllocator* allocator, ResShape resShape);
41 static void ResSeparateDataShape_Setup(nw::os::IAllocator* allocator, ResShape resShape);
42 static void ResParticleShape_Setup(nw::os::IAllocator* allocator, ResShape resShape);
43
44 static void ResShape_Cleanup(ResShape resShape);
45 static void ResSeparateDataShape_Cleanup(ResShape resShape);
46 static void ResParticleShape_Cleanup(ResShape resShape);
47
48 static SetupFunc sShape_SetupTable[] =
49 {
50 ResSeparateDataShape_Setup,
51 ResParticleShape_Setup
52 };
53
54 static CleanupFunc sShape_CleanupTable[] =
55 {
56 ResSeparateDataShape_Cleanup,
57 ResParticleShape_Cleanup
58 };
59
60
61
62 //---------------------------------------------------------------------------
63 //! @brief 必要であれば頂点バッファのコピー用のメモリを確保し、転送をおこないます。
64 //!
65 //! @param[in] bufferID メモリ確保用の頂点バッファIDです。
66 //! @param[in] resStream 頂点ストリームリソースです。
67 //! @param[in] loadFlag 頂点バッファの配置メモリフラグです。
68 //---------------------------------------------------------------------------
69 static void
BufferData(u32 bufferID,ResIndexStream resStream,u32 loadFlag)70 BufferData( u32 bufferID, ResIndexStream resStream, u32 loadFlag )
71 {
72 u32 size = resStream.GetStreamCount();
73 GLenum transtype = loadFlag & 0xFFFF0000;
74 void* address = NULL;
75 const u32 NN_GX_MEM_MASK = 0x00030000;
76
77 switch (transtype)
78 {
79 case (NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP):
80 nngxUpdateBuffer( resStream.GetStream(), size );
81 break;
82
83 case (NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP):
84 case (NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP):
85 {
86 GLuint area = (transtype & NN_GX_MEM_MASK);
87 address = __dmpgl_allocator(area, NN_GX_MEM_VERTEXBUFFER, bufferID, size);
88 nngxAddVramDmaCommand( resStream.GetStream(), address, size );
89
90 resStream.SetLocationAddress( address );
91 resStream.ref().m_MemoryArea = area;
92 }
93 break;
94
95 case (NN_GX_MEM_FCRAM | GL_COPY_FCRAM_DMP):
96 {
97 address = __dmpgl_allocator(NN_GX_MEM_FCRAM, NN_GX_MEM_VERTEXBUFFER, bufferID, size);
98 nw::os::MemCpy( address, resStream.GetStream(), size );
99 nngxUpdateBuffer( address, size );
100
101 resStream.SetLocationAddress( address );
102 resStream.ref().m_MemoryArea = NN_GX_MEM_FCRAM;
103 }
104 break;
105
106 case (NN_GX_MEM_VRAMA | GL_COPY_FCRAM_DMP):
107 case (NN_GX_MEM_VRAMB | GL_COPY_FCRAM_DMP):
108 NW_FATAL_ERROR("GL_COPY_DMA is not supported!");
109 break;
110
111 default:
112 break;
113 }
114 }
115
116 //---------------------------------------------------------------------------
117 //! @brief コピーした頂点情報を開放します。
118 //!
119 //! @param[in] bufferID バッファオブジェクトIDです。
120 //! @param[in] resStream
121 //---------------------------------------------------------------------------
122 static void
DeleteBuffer(u32 bufferID,ResIndexStream resStream)123 DeleteBuffer( u32 bufferID, ResIndexStream resStream )
124 {
125 GLuint area = resStream.ref().m_MemoryArea;
126
127 if (area != ResIndexStreamData::AREA_NO_MALLOC)
128 {
129 void* address = reinterpret_cast<void*>( resStream.GetLocationAddress() );
130 __dmpgl_deallocator( area, NN_GX_MEM_VERTEXBUFFER, bufferID, address );
131 resStream.SetLocationAddress( static_cast<u32>(NULL) );
132 }
133 }
134
135
136 //----------------------------------------
137 Result
Setup(nw::os::IAllocator * allocator)138 ResShape::Setup(nw::os::IAllocator* allocator)
139 {
140 Result result = RESOURCE_RESULT_OK;
141 switch ( this->ref().typeInfo )
142 {
143 case ResSeparateDataShape::TYPE_INFO:
144 {
145 sShape_SetupTable[0]( allocator, *this );
146 this->SetFlags(ut::EnableFlag(this->GetFlags(), ResShape::FLAG_HAS_BEEN_SETUP));
147 }
148 break;
149 case ResParticleShape::TYPE_INFO:
150 {
151 sShape_SetupTable[1]( allocator, *this );
152 this->SetFlags(ut::EnableFlag(this->GetFlags(), ResShape::FLAG_HAS_BEEN_SETUP));
153 }
154 break;
155 default:
156 {
157 }
158 }
159 return result;
160 }
161
162
163 /*!--------------------------------------------------------------------------*
164 Name: ResShape_Setup
165
166 @brief シェイプのリソース初期化をおこないます。
167
168 @param[in] resShape シェイプリソースです。
169
170 @return なし。
171 *---------------------------------------------------------------------------*/
172 static void
ResShape_Setup(nw::os::IAllocator * allocator,ResShape resShape)173 ResShape_Setup(nw::os::IAllocator* allocator, ResShape resShape)
174 {
175 s32 primSetNum = resShape.GetPrimitiveSetsCount();
176
177 for ( s32 i = 0; i < primSetNum; ++i )
178 {
179 resShape.GetPrimitiveSets( i ).Setup(allocator);
180 }
181 }
182
183
184 /*!--------------------------------------------------------------------------*
185 Name: ResSeparateDataShape_Setup
186
187 @brief 複数属性シェイプのリソース初期化をおこないます。
188
189 @param[in] resShape シェイプリソースです。
190
191 @return なし。
192 *---------------------------------------------------------------------------*/
193 static void
ResSeparateDataShape_Setup(nw::os::IAllocator * allocator,ResShape resShape)194 ResSeparateDataShape_Setup(nw::os::IAllocator* allocator, ResShape resShape)
195 {
196 ResShape_Setup( allocator, resShape );
197
198 ResSeparateDataShape resSeparateShape = ResStaticCast<ResSeparateDataShape>( resShape );
199
200 s32 vtxAttrNum = resSeparateShape.GetVertexAttributesCount();
201 for ( s32 i = 0; i < vtxAttrNum; ++ i )
202 {
203 resSeparateShape.GetVertexAttributes( i ).Setup();
204 }
205 }
206
207
208 /*!--------------------------------------------------------------------------*
209 Name: ResParticleShape_Setup
210
211 @brief パーティクルシェイプのリソース初期化をおこないます。
212
213 @param[in] resShape シェイプリソースです。
214
215 @return なし。
216 *---------------------------------------------------------------------------*/
217 static void
ResParticleShape_Setup(nw::os::IAllocator * allocator,ResShape resShape)218 ResParticleShape_Setup(nw::os::IAllocator* allocator, ResShape resShape)
219 {
220 NW_UNUSED_VARIABLE(resShape);
221 NW_UNUSED_VARIABLE(allocator);
222 }
223
224
225 /*!--------------------------------------------------------------------------*
226 Name: ResPrimitiveSet::Setup
227
228 @brief リソースの初期化をおこないます。
229
230 @return なし。
231 *---------------------------------------------------------------------------*/
232 void
Setup(nw::os::IAllocator * allocator)233 ResPrimitiveSet::Setup(nw::os::IAllocator* allocator)
234 {
235 NW_ASSERT( this->IsValid() );
236
237 ResPrimitiveArray primitiveArray = this->GetPrimitives();
238
239 for (ResPrimitiveArray::iterator it = primitiveArray.begin(); it != primitiveArray.end(); ++it)
240 {
241 (*it).Setup(allocator);
242 }
243 }
244
245
246 /*!--------------------------------------------------------------------------*
247 Name: ResPrimitive::Setup
248
249 @brief リソースの初期化をおこないます。
250
251 @return なし。
252 *---------------------------------------------------------------------------*/
253 void
Setup(nw::os::IAllocator * allocator)254 ResPrimitive::Setup(nw::os::IAllocator* allocator)
255 {
256 NW_ASSERT( this->IsValid() );
257
258 if (allocator == NULL) { allocator = CommandCacheManager::GetAllocator(); }
259
260 this->ref().m_CommandAllocator = allocator;
261 u32 streamNum = this->GetIndexStreamsCount();
262
263 GLuint* bufferObjects = reinterpret_cast<GLuint*>( this->GetBufferObjects() );
264
265 for ( uint i = 0; i < streamNum; ++i )
266 {
267 ResIndexStream resStream = this->GetIndexStreams( u32(i) );
268 bufferObjects[ i ] = reinterpret_cast<u32>(resStream.ptr());
269
270 s32 commandSize = internal::CalcSetupDrawIndexStreamCommand( resStream );
271 resStream.ref().m_CommandCache = allocator->Alloc(commandSize, 4);
272 resStream.ref().m_CommandCacheSize = commandSize;
273
274 if (resStream.GetLocationAddress() != NULL)
275 {
276 resStream.ref().m_MemoryArea = ResIndexStreamData::AREA_NO_MALLOC;
277 continue;
278 }
279
280 u32 size = resStream.GetStreamCount();
281 void* buf = resStream.GetStream();
282
283 // 頂点インデックスバッファのメモリへの読み込み指定
284 int loadFlag = resStream.GetLocationFlag();
285
286 // デフォルトは、FCRAM から NO_COPY。
287 if (loadFlag == 0)
288 {
289 loadFlag = NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP;
290 }
291
292 BufferData( bufferObjects[ i ], resStream, loadFlag );
293 }
294 }
295
296 //----------------------------------------
297 void
SetupDrawCommand(bool hasGeometryShader)298 ResPrimitive::SetupDrawCommand(bool hasGeometryShader)
299 {
300 ResIndexStreamArray indexStreams = this->GetIndexStreams();
301
302 ResIndexStreamArray::iterator end = indexStreams.end();
303 for (ResIndexStreamArray::iterator stream = indexStreams.begin(); stream != end; ++stream)
304 {
305 ResIndexStream indexStream = *stream;
306 NW_NULL_ASSERT( indexStream.ref().m_CommandCache );
307
308 internal::CommandBufferInfo bufferInfo(
309 indexStream.ref().m_CommandCache,
310 indexStream.ref().m_CommandCacheSize );
311
312 s32 resultSize = internal::SetupDrawIndexStreamCommand(bufferInfo, indexStream, hasGeometryShader);
313 NW_ASSERT( resultSize == indexStream.ref().m_CommandCacheSize );
314 }
315
316 ref().m_Flags |= ResPrimitive::FLAG_COMMAND_HAS_BEEN_SETUP;
317 }
318
319 //----------------------------------------
320 void
Cleanup()321 ResShape::Cleanup()
322 {
323 switch ( this->ref().typeInfo )
324 {
325 case ResSeparateDataShape::TYPE_INFO:
326 {
327 sShape_CleanupTable[0]( *this );
328 this->SetFlags(ut::DisableFlag(this->GetFlags(), ResShape::FLAG_HAS_BEEN_SETUP));
329 }
330 break;
331 case ResParticleShape::TYPE_INFO:
332 {
333 sShape_CleanupTable[1]( *this );
334 this->SetFlags(ut::DisableFlag(this->GetFlags(), ResShape::FLAG_HAS_BEEN_SETUP));
335 }
336 break;
337 default:
338 {
339 }
340 }
341 }
342
343 //----------------------------------------
344 static void
ResShape_Cleanup(ResShape resShape)345 ResShape_Cleanup(ResShape resShape)
346 {
347 s32 primSetNum = resShape.GetPrimitiveSetsCount();
348
349 for ( s32 i = 0; i < primSetNum; ++i )
350 {
351 resShape.GetPrimitiveSets( i ).Cleanup();
352 }
353 }
354
355 //----------------------------------------
356 static void
ResSeparateDataShape_Cleanup(ResShape resShape)357 ResSeparateDataShape_Cleanup(ResShape resShape)
358 {
359 ResSeparateDataShape resSeparateShape = ResStaticCast<ResSeparateDataShape>( resShape );
360
361 s32 vtxAttrNum = resSeparateShape.GetVertexAttributesCount();
362
363 for ( s32 i = 0; i < vtxAttrNum; ++ i )
364 {
365 resSeparateShape.GetVertexAttributes( i ).Cleanup();
366 }
367
368 ResShape_Cleanup( resShape );
369 }
370
371 //----------------------------------------
372 static void
ResParticleShape_Cleanup(ResShape resShape)373 ResParticleShape_Cleanup(ResShape resShape)
374 {
375 ResParticleShape resParticleShape = ResStaticCast<ResParticleShape>( resShape );
376 }
377
378
379 //------------------------------------------------------------------------------
380 void
Cleanup()381 ResPrimitiveSet::Cleanup()
382 {
383 NW_ASSERT( this->IsValid() );
384
385 ResPrimitiveArray primitiveArray = this->GetPrimitives();
386
387 for (ResPrimitiveArray::iterator it = primitiveArray.begin(); it != primitiveArray.end(); ++it)
388 {
389 (*it).Cleanup();
390 }
391 }
392
393
394 //------------------------------------------------------------------------------
395 void
Cleanup()396 ResPrimitive::Cleanup()
397 {
398 NW_ASSERT( this->IsValid() );
399
400 u32 streamNum = this->GetIndexStreamsCount();
401
402 GLuint* bufferObjects = reinterpret_cast<GLuint*>( this->GetBufferObjects() );
403
404 for ( uint i = 0; i < streamNum; ++i )
405 {
406 ResIndexStream resStream = this->GetIndexStreams( u32(i) );
407 if (resStream.IsValid() && resStream.ref().m_CommandCache)
408 {
409 this->ref().m_CommandAllocator->Free(resStream.ref().m_CommandCache);
410 resStream.ref().m_CommandCache = NULL;
411 resStream.ref().m_CommandCacheSize = 0;
412 }
413
414 DeleteBuffer( bufferObjects[ i ], resStream );
415 }
416
417 std::memset( bufferObjects, 0, sizeof(GLuint) * streamNum );
418
419 ref().m_CommandAllocator = NULL;
420 ref().m_Flags &= ~FLAG_COMMAND_HAS_BEEN_SETUP;
421 }
422
423
424 //----------------------------------------------------------
425 u32
GetVertexCount()426 ResSeparateDataShape::GetVertexCount()
427 {
428 int attributesCount = this->GetVertexAttributesCount();
429 for (int i = 0 ; i < attributesCount ; ++i)
430 {
431 u32 vertexCount = this->GetVertexAttributes(i).GetVertexCount();
432
433 // 最初に見つかった頂点数を返します。
434 if (vertexCount)
435 {
436 return vertexCount;
437 }
438 }
439
440 NW_FATAL_ERROR("Vertex stream not found\n");
441
442 return 0;
443 }
444
445 } /* namespace res */
446 } /* namespace gfx */
447 } /* namespace nw */
448
449