1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     demo_GraphicsSystem.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: 28445 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nw/demo/demo_GraphicsSystem.h>
17 
18 #include <nw/demo/demo_DisplayBufferSwapper.h>
19 #include <nw/demo/demo_Memory.h>
20 #include <nw/demo/demo_Utility.h>
21 #include <nw/demo/demo_DebugUtility.h>
22 #include <nw/demo/demo_GraphicsDrawing.h>
23 #include <nw/demo/demo_CameraController.h>
24 #include <nw/demo/demo_GraphicsMemoryAllocator.h>
25 
26 #include <nw/gfx/gfx_IRenderTarget.h>
27 #include <nw/gfx/gfx_RenderContext.h>
28 #include <nw/gfx/gfx_RenderElement.h>
29 #include <nw/gfx/gfx_MeshRenderer.h>
30 #include <nw/gfx/gfx_ShaderProgram.h>
31 #include <nw/gfx/gfx_SceneNode.h>
32 #include <nw/gfx/gfx_Model.h>
33 #include <nw/gfx/gfx_FragmentLight.h>
34 #include <nw/gfx/gfx_SceneTraverser.h>
35 #include <nw/gfx/gfx_SceneContext.h>
36 #include <nw/gfx/gfx_WorldMatrixUpdater.h>
37 #include <nw/gfx/gfx_SkeletonUpdater.h>
38 #include <nw/gfx/gfx_SceneUpdater.h>
39 #include <nw/gfx/gfx_SceneInitializer.h>
40 #include <nw/gfx/gfx_Camera.h>
41 #include <nw/gfx/gfx_Fog.h>
42 #include <nw/gfx/gfx_IMaterialIdGenerator.h>
43 #include <nw/gfx/gfx_CommandUtil.h>
44 #include <nw/gfx/gfx_ParticleUtil.h>
45 
46 #include <nw/ut/ut_Color.h>
47 #include <nw/ut/ut_Foreach.h>
48 
49 #include <nw/dev.h>
50 
51 #include <nn/fs.h>
52 #include <nn/fnd.h>
53 #include <nn/gx.h>
54 
55 //! このマクロを有効にすると、ログ出力にレンダーキューのソート後の状態をレポートします。
56 //#define REPORT_RENDER_QUEUE_ENABLED
57 
58 //! このマクロを有効にすると、半透明以外の深度ソートを省略するようになります。
59 #define SORT_DEPTH_OF_TRANSLUCENT_MESH_ENABLED
60 
61 namespace nw
62 {
63 namespace demo
64 {
65 
66 const float RenderSystem::LoadMeterDescription::NANO_TO_MILLI = 1.0f / (1000.0f * 1000.0f);
67 const float RenderSystem::LoadMeterDescription::MILLI_TO_RATE = 1.0f / (1000.0f / 60.0f);
68 
69 namespace
70 {
71     GraphicsMemoryAllocator s_GraphicsMemoryAllocator;
72     nw::demo::DemoAllocator* s_DeviceAllocator;
73 }
74 
75 //----------------------------------------
AllocateGraphicsMemory(GLenum area,GLenum aim,GLuint id,GLsizei size)76 void* AllocateGraphicsMemory(GLenum area, GLenum aim, GLuint id, GLsizei size)
77 {
78 
79     void* buffer = s_GraphicsMemoryAllocator.Allocate(area, aim, id, size);
80 
81     // NOTE: GL の管理領域を nw::gfx に設定する必要がなくなり、このコードは不要となりました。
82 #if 0
83     if (s_GetGlSystemFlag)
84     {
85         if (size == nw::gfx::GlSystem::SHADER_MANAGER_BUFFER_SIZE)
86         {
87             nw::gfx::GlSystem::SetGlShManager( buffer );
88         }
89     }
90 #endif
91 
92     return buffer;
93 }
94 
95 //----------------------------------------
DeallocateGraphicsMemory(GLenum area,GLenum aim,GLuint id,void * addr)96 void DeallocateGraphicsMemory(GLenum area, GLenum aim, GLuint id, void* addr)
97 {
98     s_GraphicsMemoryAllocator.Deallocate(area, aim, id, addr);
99 }
100 
101 //----------------------------------------
102 RenderSystem*
Create(os::IAllocator * allocator,const Description & description)103 RenderSystem::Create(
104     os::IAllocator* allocator,
105     const Description& description
106 )
107 {
108     void* memory = allocator->Alloc(sizeof(RenderSystem));
109     RenderSystem* renderSystem = new(memory) RenderSystem();
110 
111     renderSystem->m_RenderContext = gfx::RenderContext::Builder()
112         .Create(allocator);
113 
114     renderSystem->m_PostRenderCallback = ut::Signal1<void, const gfx::Camera*>::CreateVariableSizeSignal(allocator);
115     renderSystem->m_PostRightRenderCallback = ut::Signal1<void, const gfx::Camera*>::CreateVariableSizeSignal(allocator);
116 
117 #ifdef SORT_DEPTH_OF_TRANSLUCENT_MESH_ENABLED
118     // 半透明以外のメッシュで深度情報の量子化を行わなくするための
119     // レンダーキー・ファクトリクラスを生成します。
120     renderSystem->m_PriorMaterialRenderKeyFactory =
121         gfx::CreatePriorMaterialAndZeroDepthRenderKeyFactory(allocator);
122 #else
123     renderSystem->m_PriorMaterialRenderKeyFactory =
124         gfx::CreatePriorMaterialRenderKeyFactory(allocator);
125 #endif
126 
127     renderSystem->m_PriorDepthRenderKeyFactory =
128         gfx::CreatePriorDepthReverseDepthRenderKeyFactory(allocator);
129 
130     renderSystem->m_RenderQueue = gfx::RenderQueue::Builder()
131         .MaxRenderElements(256)
132         .Create(allocator);
133 
134     renderSystem->m_RenderQueue->Reset(
135         renderSystem->m_PriorMaterialRenderKeyFactory,
136         renderSystem->m_PriorDepthRenderKeyFactory,
137         renderSystem->m_PriorMaterialRenderKeyFactory,
138         renderSystem->m_PriorMaterialRenderKeyFactory);
139 
140     renderSystem->m_MeshRenderer = gfx::MeshRenderer::Create(allocator);
141     renderSystem->m_MeshRenderer->SetRenderContext(renderSystem->m_RenderContext);
142 
143 
144     if (nngxInitialize(AllocateGraphicsMemory, DeallocateGraphicsMemory) == GL_FALSE)
145     {
146         NW_FATAL_ERROR("nngxInitialize failed.\n");
147     }
148 
149     // コマンドリスト
150     nw::demo::CommandListSwapper::Description swapperDescription;
151     swapperDescription.commandListCount = description.commandListCount;
152     swapperDescription.bufferSize = description.commandBufferSize;
153     swapperDescription.requestCount = description.commandRequestCount;
154     swapperDescription.reusableBufferSize = description.reusableCommandBufferSize;
155     swapperDescription.reusableRequestCount = description.reusableCommandRequestCount;
156     swapperDescription.maxGpuProfilingEntryCount = description.maxGpuProfilingEntryCount;
157     renderSystem->m_CommandListSwapper =
158         nw::demo::CommandListSwapper::Create(allocator, swapperDescription);
159 
160     NW_POINTER_ASSERT(renderSystem->m_CommandListSwapper);
161 
162     renderSystem->m_CommandListSwapper->Bind();
163     renderSystem->m_CommandListSwapper->RunAsync();
164 
165     nngxStartLcdDisplay();
166 
167 
168     renderSystem->m_UpperSwapper = DisplayBufferSwapper::Builder()
169         .BufferDescription(description.upperScreenDescription)
170         .BufferCount(description.displayBufferCount)
171         .Create(allocator);
172 
173     renderSystem->m_LowerSwapper = DisplayBufferSwapper::Builder()
174         .BufferDescription(description.lowerScreenDescription)
175         .BufferCount(description.displayBufferCount)
176         .Create(allocator);
177 
178     nngxSetDisplayMode(description.upperScreenMode);
179 
180     // ステレオモードの場合は上画面のディスプレイバッファを追加で生成する
181     if (description.upperScreenMode == UPPER_SCREEN_MODE_STEREO)
182     {
183         nw::demo::DisplayBufferSwapper::Description extensionScreenDescription;
184         extensionScreenDescription.screenKind = nw::demo::EXTENSION_SCREEN;
185         extensionScreenDescription.width  = description.upperScreenDescription.width;
186         extensionScreenDescription.height = description.upperScreenDescription.height;
187 
188         renderSystem->m_ExtensionSwapper = DisplayBufferSwapper::Builder()
189             .BufferDescription(extensionScreenDescription)
190             .BufferCount(description.displayBufferCount)
191             .Create(allocator);
192 
193         // ステレオカメラを生成する
194         void* cameraMemory = allocator->Alloc(sizeof(nn::ulcd::CTR::StereoCamera));
195         nn::ulcd::CTR::StereoCamera* stereoCamera = new(cameraMemory) nn::ulcd::CTR::StereoCamera();
196         stereoCamera->Initialize();
197         renderSystem->m_StereoCamera = stereoCamera;
198     }
199 
200     NW_GL_ASSERT();
201 
202     renderSystem->m_Allocator = allocator;
203 
204     return renderSystem;
205 }
206 
207 //----------------------------------------
208 void
LoadSkyModel(const wchar_t * fileName)209 RenderSystem::LoadSkyModel(const wchar_t* fileName)
210 {
211     ResourceSet* resourceSet = Utility::LoadResources(m_Resources, fileName, m_Allocator);
212 
213     resourceSet->resource.ForeachTexture(nw::gfx::TextureLocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
214     resourceSet->resource.ForeachIndexStream(nw::gfx::IndexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
215     resourceSet->resource.ForeachVertexStream(nw::gfx::VertexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
216 
217     nw::gfx::Result result = resourceSet->resource.Setup(m_Allocator);
218     if (result.IsFailure())
219     {
220         NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
221     }
222 
223     // モデルのインスタンスを生成します。
224     nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
225     nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
226         m_Allocator,
227         *(models.begin()),
228         false
229     );
230 
231     nw::gfx::Model* model = nw::ut::DynamicCast<nw::gfx::Model*>(node);
232     NW_NULL_ASSERT(model);
233 
234     m_SkyModel = model;
235 }
236 
237 //----------------------------------------
238 void
Destroy()239 RenderSystem::Destroy()
240 {
241     os::IAllocator* allocator = this->m_Allocator;
242 
243     nngxStopCmdlist();
244     nngxWaitCmdlistDone();
245 
246     gfx::SafeDestroy(this->m_SkyModel);
247     nw::demo::SafeCleanupResources(m_Resources);
248     m_Resources.clear();
249 
250     if (this->m_StereoCamera)
251     {
252         m_StereoCamera->Finalize();
253         allocator->Free(m_StereoCamera);
254     }
255 
256     gfx::SafeDestroy(this->m_ExtensionSwapper);
257 
258     gfx::SafeDestroy(this->m_LowerSwapper);
259     gfx::SafeDestroy(this->m_UpperSwapper);
260     gfx::SafeDestroy(this->m_MeshRenderer);
261     gfx::SafeDestroy(this->m_RenderQueue);
262     gfx::SafeDestroy(this->m_PriorMaterialRenderKeyFactory);
263     gfx::SafeDestroy(this->m_PriorDepthRenderKeyFactory);
264     gfx::SafeDestroy(this->m_PostRightRenderCallback);
265     gfx::SafeDestroy(this->m_PostRenderCallback);
266     gfx::SafeDestroy(this->m_RenderContext);
267     gfx::SafeDestroy(this->m_CommandListSwapper);
268 
269     nngxFinalize();
270     // TODO: グラフィックスメモリアロケーターのデアロケータを実装する
271     s_GraphicsMemoryAllocator.Finalize();
272     NW_GL_ASSERT();
273 
274     void* memory = static_cast<void*>(this);
275     this->~RenderSystem();
276 
277     allocator->Free(memory);
278 }
279 
280 //----------------------------------------
281 void
SetRenderTarget(gfx::IRenderTarget * renderTarget)282 RenderSystem::SetRenderTarget(gfx::IRenderTarget* renderTarget)
283 {
284     gfx::RenderContext* renderContext = this->GetRenderContext();
285     renderContext->SetRenderTarget(renderTarget);
286 }
287 
288 //----------------------------------------
289 void
SetRenderSortMode(gfx::ISceneUpdater::RenderSortMode renderSortMode)290 RenderSystem::SetRenderSortMode(gfx::ISceneUpdater::RenderSortMode renderSortMode)
291 {
292     this->m_RenderSortMode = renderSortMode;
293 
294     gfx::SafeDestroy(this->m_PriorDepthRenderKeyFactory);
295     if (this->m_RenderSortMode == gfx::ISceneUpdater::OPAQUE_MESH_BASE_AND_TRANSLUCENT_MODEL_BASE_SORT)
296     {
297         this->m_PriorDepthRenderKeyFactory =
298             gfx::CreateTopPriorDepthReverseDepthRenderKeyFactory(this->m_Allocator);
299     }
300     else
301     {
302         this->m_PriorDepthRenderKeyFactory =
303             gfx::CreatePriorDepthReverseDepthRenderKeyFactory(this->m_Allocator);
304     }
305 
306     NW_NULL_ASSERT(this->m_PriorDepthRenderKeyFactory);
307 }
308 
309 //----------------------------------------
310 struct RenderSceneInternalFunctor
311 : public std::unary_function<gfx::RenderElement&, void>
312 {
313     gfx::RenderContext* m_RenderContext;
314     gfx::MeshRenderer* m_MeshRenderer;
315 
RenderSceneInternalFunctornw::demo::RenderSceneInternalFunctor316     RenderSceneInternalFunctor(gfx::RenderContext* renderContext, gfx::MeshRenderer* meshRenderer)
317     : m_RenderContext(renderContext), m_MeshRenderer(meshRenderer)
318     {
319         NW_NULL_ASSERT(renderContext);
320         NW_NULL_ASSERT(meshRenderer);
321     }
322 
operator ()nw::demo::RenderSceneInternalFunctor323     void operator()(gfx::RenderElement& element)
324     {
325         if (element.IsCommand())
326         {
327             gfx::RenderCommand* command = element.GetCommand();
328             NW_NULL_ASSERT(command);
329             command->Invoke(this->m_RenderContext);
330         }
331         else
332         {
333             gfx::ResMesh mesh = element.GetMesh();
334             gfx::Model* model = element.GetModel();
335             model->PreRenderSignal()(model, mesh, this->m_RenderContext);
336             this->m_MeshRenderer->RenderMesh(mesh, model);
337             model->PostRenderSignal()(model, mesh, this->m_RenderContext);
338         }
339         NW_GL_ASSERT();
340     }
341 };
342 
343 //----------------------------------------
344 void
SetSceneEnvironmentSettings(SceneSystem * sceneSystem,ut::MoveArray<gfx::SceneEnvironmentSetting * > * sceneEnvironmentSettings)345 RenderSystem::SetSceneEnvironmentSettings(
346     SceneSystem* sceneSystem,
347     ut::MoveArray<gfx::SceneEnvironmentSetting*>* sceneEnvironmentSettings
348 )
349 {
350     gfx::RenderContext* renderContext = this->GetRenderContext();
351     gfx::SceneContext* sceneContext = sceneSystem->GetSceneContext();
352     gfx::SceneEnvironment& sceneEnvironment = renderContext->GetSceneEnvironment();
353 
354     ut::MoveArray<gfx::SceneEnvironmentSetting*>::iterator end = sceneEnvironmentSettings->end();
355     for (ut::MoveArray<gfx::SceneEnvironmentSetting*>::iterator sceneEnvironmentSetting = sceneEnvironmentSettings->begin();
356         sceneEnvironmentSetting != end;
357         ++sceneEnvironmentSetting)
358     {
359         (*sceneEnvironmentSetting)->ResolveReference(*sceneContext);
360         sceneEnvironment.ApplyFrom(**sceneEnvironmentSetting);
361     }
362 }
363 
364 //----------------------------------------
365 void
SetEnvironment(SceneSystem * sceneSystem)366 RenderSystem::SetEnvironment(
367     SceneSystem* sceneSystem
368 )
369 {
370     NW_PROFILE("RenderSystem::SetEnvironment");
371 
372     gfx::RenderContext* renderContext = this->GetRenderContext();
373     gfx::SceneContext* sceneContext = sceneSystem->GetSceneContext();
374     gfx::SceneEnvironment& sceneEnvironment = renderContext->GetSceneEnvironment();
375 
376     if (sceneContext->GetAmbientLightsBegin() != sceneContext->GetAmbientLightsEnd())
377     {
378         sceneEnvironment.SetAmbientLight(*sceneContext->GetAmbientLightsBegin());
379     }
380 
381     if (sceneContext->GetHemiSphereLightsBegin() != sceneContext->GetHemiSphereLightsEnd())
382     {
383         sceneEnvironment.SetHemiSphereLight(*sceneContext->GetHemiSphereLightsBegin());
384     }
385 
386     std::for_each(
387         sceneContext->GetFragmentLightsBegin(),
388         sceneContext->GetFragmentLightsEnd(),
389         std::bind1st(std::mem_fun(&gfx::SceneEnvironment::SetFragmentLight), &sceneEnvironment));
390 
391     std::for_each(
392         sceneContext->GetVertexLightsBegin(),
393         sceneContext->GetVertexLightsEnd(),
394         std::bind1st(std::mem_fun(&gfx::SceneEnvironment::SetVertexLight), &sceneEnvironment));
395 
396     if (sceneContext->GetFogBegin() != sceneContext->GetFogEnd())
397     {
398         sceneEnvironment.SetFog(0, *sceneContext->GetFogBegin());
399     }
400 }
401 
402 //----------------------------------------
403 void
SubmitView(SceneSystem * sceneSystem)404 RenderSystem::SubmitView(
405     SceneSystem* sceneSystem
406 )
407 {
408     NW_PROFILE("RenderSystem::SubmitView");
409 
410     nw::gfx::Camera* camera = this->GetRenderContext()->GetActiveCamera();
411     gfx::SceneContext* sceneContext = sceneSystem->GetSceneContext();
412 
413     //----------------------------------------
414     // フォグを更新します。
415     std::for_each(sceneContext->GetFogBegin(), sceneContext->GetFogEnd(), gfx::Fog::UpdateFunctor(camera));
416 
417     //----------------------------------------
418     // カメラに依存する処理と、描画要素をレンダーキューに積みます。
419 
420     #ifdef SORT_DEPTH_OF_TRANSLUCENT_MESH_ENABLED
421     // RenderQueue::Reset の引数に true を指定すると、ソート用キーをキャッシュする最適化機能が
422     // 有効になります。
423     // 半透明以外のソート用キーのみキャッシュされるようになります。
424     this->m_RenderQueue->Reset(true);
425 
426     // 半透明メッシュの深度のみ計算して、半透明メッシュのみ深度によるソートがされるようになります。
427     // 深度計算の処理負荷の低減を期待できます。
428     sceneSystem->GetSceneUpdater()->SetDepthSortMode(gfx::ISceneUpdater::SORT_DEPTH_OF_TRANSLUCENT_MESH);
429     #else
430     this->m_RenderQueue->Reset();
431 
432     // すべてのメッシュの深度を計算して、深度によってもソートされるようになります。
433     // 不透明物体等を手前から描画することで、GPUのフィル負荷の低減を期待できます。
434     sceneSystem->GetSceneUpdater()->SetDepthSortMode(gfx::ISceneUpdater::SORT_DEPTH_OF_ALL_MESH);
435     #endif
436 
437     sceneSystem->GetSceneUpdater()->SubmitView(
438         this->m_RenderQueue,
439         sceneContext,
440         *camera,
441         0,
442         1,
443         this->m_RenderSortMode);
444 
445     //----------------------------------------
446     // レンダーキューをソートします。
447     // RenderElementCompare() やレンダーキーファクトリーをカスタマイズすることで
448     // 描画順を変更することができます。
449     // 詳しくは最適化TIPSを参照してください。
450     std::sort(
451         this->m_RenderQueue->Begin(),
452         this->m_RenderQueue->End(),
453         gfx::RenderElementCompare());
454 
455 #ifdef REPORT_RENDER_QUEUE_ENABLED
456     // レンダーキューのソート後の状態をレポートします。
457     // リリース版ではなにも表示されなくなっています。
458     std::for_each(
459         this->m_RenderQueue->Begin(),
460         this->m_RenderQueue->End(),
461         gfx::RenderQueue::ReportFunctor());
462 #endif
463 }
464 
465 //----------------------------------------
466 void
RenderScene(gfx::Camera * camera,s32 screenKind,bool isCommandCacheDump)467 RenderSystem::RenderScene(
468     gfx::Camera* camera,
469     s32 screenKind,
470     bool isCommandCacheDump
471 )
472 {
473     NW_PROFILE("RenderSystem::RenderScene");
474 
475     gfx::RenderContext* renderContext = this->GetRenderContext();
476     gfx::SceneEnvironment& sceneEnvironment = renderContext->GetSceneEnvironment();
477 
478     NW_GL_ASSERT();
479 
480     // GPU処理時間計測開始
481     int profilingId = m_CommandListSwapper->AddGpuProfilingStartPoint(true);
482     NW_ASSERT(profilingId >= 0);
483     int cmdBufferSize = m_CommandListSwapper->GetCommandBufferSize();
484 
485     renderContext->SetCameraMatrix(camera);
486 
487     if (m_SkyModel != NULL)
488     {
489         this->ClearBySkyModel(camera);
490     }
491     else
492     {
493         this->ClearBuffer(nw::ut::FloatColor(0.5f, 0.5f, 0.5f, 1.0f));
494     }
495 
496     if (isCommandCacheDump)
497     {
498         nw::gfx::internal::CommandCacheBuilder builder;
499         builder.Begin();
500 
501         std::for_each(
502             this->m_RenderQueue->Begin(),
503             this->m_RenderQueue->End(),
504             RenderSceneInternalFunctor(renderContext, this->m_MeshRenderer));
505 
506         builder.End();
507         builder.Report();
508     }
509     else
510     {
511         std::for_each(
512             this->m_RenderQueue->Begin(),
513             this->m_RenderQueue->End(),
514             RenderSceneInternalFunctor(renderContext, this->m_MeshRenderer));
515     }
516 
517     m_LoadMeterDescription.drawCommandBufferSize =
518         m_CommandListSwapper->GetCommandBufferSize() - cmdBufferSize;
519     m_CumulativeLoadMeterDescription.drawCommandBufferSize =
520         m_CommandListSwapper->GetCommandBufferSize() - cmdBufferSize;
521 
522     (*m_PostRenderCallback)(camera);
523 
524     // GPU処理時間計測終了
525     nngxSplitDrawCmdlist();
526 
527     m_CommandListSwapper->SetGpuProfilingEndPoint(profilingId);
528 
529     TransferBuffer(screenKind);
530 }
531 
532 //----------------------------------------
533 void
RenderStereoScene(gfx::Camera * leftCamera,gfx::Camera * rightCamera,bool isCommandCacheDump)534 RenderSystem::RenderStereoScene(
535     gfx::Camera* leftCamera,
536     gfx::Camera* rightCamera,
537     bool isCommandCacheDump
538 )
539 {
540     NW_PROFILE("RenderSystem::RenderStereoScene");
541 
542     gfx::RenderContext* renderContext = this->GetRenderContext();
543     gfx::SceneEnvironment& sceneEnvironment = renderContext->GetSceneEnvironment();
544 
545     //----------------------------------------
546     // 再利用するためのコマンドを作成し、保存します。
547     //
548     // ベースカメラを元にしたシーンを描画します。
549     m_CommandListSwapper->StartCommandSave();
550     int cmdBufferSize = m_CommandListSwapper->GetCommandBufferSize();
551 
552     if (m_SkyModel != NULL)
553     {
554         this->ClearBySkyModel(renderContext->GetActiveCamera());
555     }
556     else
557     {
558         this->ClearBuffer(nw::ut::FloatColor(0.5f, 0.5f, 0.5f, 1.0f));
559     }
560 
561     if (isCommandCacheDump)
562     {
563         nw::gfx::internal::CommandCacheBuilder builder;
564         builder.Begin();
565 
566         std::for_each(
567             this->m_RenderQueue->Begin(),
568             this->m_RenderQueue->End(),
569             RenderSceneInternalFunctor(renderContext, this->m_MeshRenderer));
570 
571         builder.End();
572         builder.Report();
573     }
574     else
575     {
576         std::for_each(
577             this->m_RenderQueue->Begin(),
578             this->m_RenderQueue->End(),
579             RenderSceneInternalFunctor(renderContext, this->m_MeshRenderer));
580     }
581 
582     m_LoadMeterDescription.drawCommandBufferSize =
583         m_CommandListSwapper->GetCommandBufferSize() - cmdBufferSize;
584 
585     m_CommandListSwapper->EndCommandSave();
586 
587     //----------------------------------------
588     // 左目用と右目用に保存したコマンドを再利用します。
589 
590     // GPU処理時間計測開始
591     int profilerLeft = m_CommandListSwapper->AddGpuProfilingStartPoint(true);
592     NW_ASSERT(profilerLeft >= 0);
593 
594     // 左目用
595     renderContext->SetCameraMatrix(leftCamera);
596     m_CommandListSwapper->ReuseCommand(false);
597 
598     (*m_PostRenderCallback)(leftCamera);
599 
600     // GPU処理時間計測終了
601     m_CommandListSwapper->SetGpuProfilingEndPoint(profilerLeft);
602 
603     TransferBuffer(UPPER_SCREEN);
604     NW_GL_ASSERT();
605 
606     // GPU処理時間計測開始
607     int profilerRight = m_CommandListSwapper->AddGpuProfilingStartPoint(true);
608     NW_ASSERT(profilerRight >= 0);
609 
610     // 右目用
611     renderContext->SetCameraMatrix(rightCamera);
612     m_CommandListSwapper->ReuseCommand(false);
613 
614     (*m_PostRightRenderCallback)(rightCamera);
615 
616     // GPU処理時間計測終了
617     m_CommandListSwapper->SetGpuProfilingEndPoint(profilerRight);
618 
619     TransferBuffer(EXTENSION_SCREEN);
620     NW_GL_ASSERT();
621 }
622 
623 //----------------------------------------
624 void
ClearBuffer(nw::ut::FloatColor clearColor)625 RenderSystem::ClearBuffer( nw::ut::FloatColor clearColor )
626 {
627     if (!nw::demo::DebugUtility::IsCpuProfilingMode())
628     {
629         this->SuspendLoadMeter();
630 
631         this->m_RenderContext->ClearBuffer(
632             GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
633             clearColor,
634             1.0f);
635         NW_GL_ASSERT();
636 
637         this->ResumeLoadMeter();
638     }
639 }
640 
641 //----------------------------------------
642 void
ClearBySkyModel(const gfx::Camera * camera)643 RenderSystem::ClearBySkyModel(const gfx::Camera* camera)
644 {
645     NW_NULL_ASSERT(camera);
646 
647     if (m_SkyModel != NULL)
648     {
649         math::VEC3 translate = camera->WorldMatrix().GetColumn(3);
650         m_SkyModel->WorldMatrix()._03 = translate.x;
651         m_SkyModel->WorldMatrix()._13 = translate.y;
652         m_SkyModel->WorldMatrix()._23 = translate.z;
653 
654         // Far の半分まで SkyModel を拡大します。
655         float scale = (camera->GetFar() / 2.0f);
656         m_SkyModel->WorldMatrix()._00 = scale;
657         m_SkyModel->WorldMatrix()._11 = scale;
658         m_SkyModel->WorldMatrix()._22 = scale;
659 
660         gfx::ResMeshArray meshArray = m_SkyModel->GetResMeshes();
661         gfx::ResMeshArray::iterator endMesh = meshArray.end();
662         for (gfx::ResMeshArray::iterator iter = meshArray.begin();
663             iter != endMesh;
664             ++iter)
665         {
666             this->m_MeshRenderer->RenderMesh(*iter, m_SkyModel);
667         }
668     }
669 }
670 
671 //----------------------------------------
672 void
TransferBuffer(s32 screenKind)673 RenderSystem::TransferBuffer(
674     s32 screenKind
675 )
676 {
677     gfx::RenderContext* renderContext = this->GetRenderContext();
678 
679     // コマンドリストが多重化されている場合、
680     // ディスプレイバッファへの転送するタイミングが変わるため、
681     // 転送先のディスプレイバッファを変更する必要があります。
682     // 詳細は PresentBuffer() のコメントを参照してください。
683 
684     bool isMultiCommandList = m_CommandListSwapper->GetListCount() > 1;
685 
686     if (screenKind & UPPER_SCREEN)
687     {
688         this->m_UpperSwapper->MakeTransferBufferCommand(
689             renderContext->GetRenderTarget(),
690             isMultiCommandList);
691     }
692 
693     if (screenKind & LOWER_SCREEN)
694     {
695         this->m_LowerSwapper->MakeTransferBufferCommand(
696             renderContext->GetRenderTarget(),
697             isMultiCommandList);
698     }
699 
700     if (screenKind & EXTENSION_SCREEN)
701     {
702         this->m_ExtensionSwapper->MakeTransferBufferCommand(
703             renderContext->GetRenderTarget(),
704             isMultiCommandList);
705     }
706 }
707 
708 //----------------------------------------
709 void
WaitCommandList()710 RenderSystem::WaitCommandList()
711 {
712     this->SuspendLoadMeter();
713 
714     NW_PROFILE("RenderSystem::WaitCommandList");
715 
716     nn::os::Tick startTick = nn::os::Tick::GetSystemCurrent();
717 
718     m_CommandListSwapper->WaitDone();
719 
720     s64 span = static_cast<nn::os::Tick>(nn::os::Tick::GetSystemCurrent() - startTick).ToTimeSpan().GetNanoSeconds();
721     m_LoadMeterDescription.cumulativeWaitTime +=
722         static_cast<float>(span) * LoadMeterDescription::NANO_TO_MILLI;
723 
724     this->ResumeLoadMeter();
725 }
726 
727 //----------------------------------------
728 void
RunCommandList()729 RenderSystem::RunCommandList()
730 {
731     m_CommandListSwapper->RunAsync();
732 }
733 
734 //----------------------------------------
735 void
SwapCommandList()736 RenderSystem::SwapCommandList()
737 {
738     m_CommandListSwapper->Swap();
739     m_CommandListSwapper->Bind();
740 }
741 
742 //----------------------------------------
743 void
WaitVSync(s32 screenKind)744 RenderSystem::WaitVSync(s32 screenKind)
745 {
746     NW_MAX_ASSERT(screenKind, (int)BOTH_SCREENS);
747 
748     GLenum display;
749     if (screenKind & (UPPER_SCREEN | LOWER_SCREEN)) { display = NN_GX_DISPLAY_BOTH; }
750     else if (screenKind & UPPER_SCREEN) { display = NN_GX_DISPLAY0; }
751     else if (screenKind & LOWER_SCREEN) { display = NN_GX_DISPLAY1; }
752 
753 
754     EndLoadMeter();
755 
756     {
757         NW_PROFILE("WaitVSync");
758         nngxWaitVSync(display);
759     }
760 
761     BeginLoadMeter();
762 }
763 
764 //----------------------------------------
765 void
SwapBuffer(s32 screenKind)766 RenderSystem::SwapBuffer(
767     s32 screenKind
768 )
769 {
770     GLenum display;
771     if ((screenKind & NORMAL_SCREENS) == NORMAL_SCREENS)
772     {
773         this->m_UpperSwapper->ActivateBuffer();
774         this->m_LowerSwapper->ActivateBuffer();
775 
776         if (screenKind & EXTENSION_SCREEN)
777         {
778             this->m_ExtensionSwapper->ActivateBuffer();
779         }
780 
781         display = NN_GX_DISPLAY_BOTH;
782     }
783     else if (screenKind & UPPER_SCREEN)
784     {
785         this->m_UpperSwapper->ActivateBuffer();
786 
787         if (screenKind & EXTENSION_SCREEN)
788         {
789             this->m_ExtensionSwapper->ActivateBuffer();
790         }
791 
792         display = NN_GX_DISPLAY0;
793     }
794     else if (screenKind & LOWER_SCREEN)
795     {
796         this->m_LowerSwapper->ActivateBuffer();
797 
798         display = NN_GX_DISPLAY1;
799     }
800 
801     nngxSwapBuffers(display);
802     glBindFramebuffer(GL_FRAMEBUFFER, 0);
803 }
804 
805 //----------------------------------------
806 void
PresentBuffer(s32 screenKind)807 RenderSystem::PresentBuffer(s32 screenKind)
808 {
809     // コマンドリストが多重化されているかどうかで、
810     // 転送するディスプレイバッファを変更したり、
811     // コマンドリスト終了待ちのタイミングを変えたりする必要があります。
812     // これらを正しく行わない場合、テアリングなどが発生することがあります。
813     if (m_CommandListSwapper->GetListCount() > 1)
814     {
815         // コマンドリストが多重化されている場合、
816         // この関数が呼ばれるまでに蓄積されたコマンドが実行( RunCommandList() )されるのは
817         // VSync とディスプレイバッファのスワップが行われた後になります。
818         //
819         // レンダーバッファからディスプレイバッファへの転送もコマンドとして蓄積され、
820         // 同じくディスプレイバッファのスワップ後に実行されます。
821         // そのため、この関数内で呼ばれるSwapBuffer()により表示されるディスプレイバッファへの転送をしてしまうと、
822         // 表示中のディスプレイバッファへの転送が実行され、テアリングが発生します。
823         //
824         // これを解決するため、ディスプレイバッファへの転送コマンドを蓄積する場合、
825         // その時点を基準に2回ディスプレイバッファのスワップが行われたときに
826         // 表示されるバッファへ転送する必要があります。
827         // DisplayBufferSwapper::MakeTransferBufferCommand() の第2引数にtrueを指定することで、
828         // 内部的にこのような転送先の調整が行われます。
829         WaitCommandList();
830         SwapBuffer(screenKind);
831         WaitVSync(screenKind);
832         RunCommandList();
833         SwapCommandList();
834     }
835     else
836     {
837         RunCommandList();
838         WaitCommandList();
839         SwapBuffer(screenKind);
840         WaitVSync(screenKind);
841     }
842 }
843 
844 //----------------------------------------
845 void
CalcStereoCamera(gfx::Camera * leftCamera,gfx::Camera * rightCamera,gfx::Camera * baseCamera,f32 depthLevel,f32 depthRange)846 RenderSystem::CalcStereoCamera(
847     gfx::Camera* leftCamera,
848     gfx::Camera* rightCamera,
849     gfx::Camera* baseCamera,
850     f32 depthLevel,
851     f32 depthRange)
852 {
853     NW_NULL_ASSERT(leftCamera);
854     NW_NULL_ASSERT(rightCamera);
855     NW_NULL_ASSERT(baseCamera);
856     nn::math::MTX44& projOriginal = baseCamera->ProjectionMatrix();
857     nn::math::MTX34& viewOriginal = baseCamera->ViewMatrix();
858     nn::math::MTX44& projL = leftCamera->ProjectionMatrix();
859     nn::math::MTX34& viewL = leftCamera->ViewMatrix();
860     nn::math::MTX44& projR = rightCamera->ProjectionMatrix();
861     nn::math::MTX34& viewR = rightCamera->ViewMatrix();
862 
863     // Orthoカメラをステレオ表示する場合は自分で絵を用意しなければいけません。
864     if (baseCamera->GetResCamera().GetProjectionType() == gfx::ResCamera::PROJTYPE_ORTHO)
865     {
866         // 現在はOrthoカメラのステレオ表示には未対応です。
867         math::MTX44Copy(&projL, &projOriginal);
868         math::MTX34Copy(&viewL, &viewOriginal);
869         math::MTX44Copy(&projR, &projOriginal);
870         math::MTX34Copy(&viewR, &viewOriginal);
871 
872         // CalculateMatrices(....)で画面にあわせての回転を行っているので、
873         // Orthoの場合はpivotを設定します。
874         baseCamera->GetProjectionUpdater()->SetPivotDirection(math::PIVOT_UPSIDE_TO_TOP);
875         leftCamera->GetProjectionUpdater()->SetPivotDirection(math::PIVOT_UPSIDE_TO_TOP);
876         rightCamera->GetProjectionUpdater()->SetPivotDirection(math::PIVOT_UPSIDE_TO_TOP);
877     }
878     else
879     {
880         m_StereoCamera->CalculateMatrices(
881             &projL,
882             &viewL,
883             &projR,
884             &viewR,
885             &projOriginal,
886             &viewOriginal,
887             depthLevel,
888             depthRange,
889             false);
890     }
891 }
892 
893 //----------------------------------------
894 void
BeginLoadMeter()895 RenderSystem::BeginLoadMeter()
896 {
897     m_LoadMeterDescription.startTick = nn::os::Tick::GetSystemCurrent();
898     m_LoadMeterDescription.drawCommandBufferSize = 0;
899 }
900 
901 //----------------------------------------
902 void
EndLoadMeter()903 RenderSystem::EndLoadMeter()
904 {
905     nn::os::Tick endTick = nn::os::Tick::GetSystemCurrent();
906 
907     s64 span = static_cast<nn::os::Tick>(endTick - m_LoadMeterDescription.startTick).ToTimeSpan().GetNanoSeconds();
908 
909     float currentTime         = static_cast<float>(span) * LoadMeterDescription::NANO_TO_MILLI;
910     float currentGpuTime      = static_cast<float>(this->m_CommandListSwapper->GetGpuProfilingTotalCostTime());
911 
912     m_LoadMeterDescription.cumulativeTime += currentTime;
913     m_LoadMeterDescription.cumulativeGpuTime += currentGpuTime;
914 
915     m_CumulativeLoadMeterDescription.cumulativeTime += currentTime;
916     m_CumulativeLoadMeterDescription.cumulativeGpuTime += currentGpuTime;
917 
918     m_CumulativeLoadMeterDescription.drawCommandBufferSize = m_LoadMeterDescription.drawCommandBufferSize;
919 
920     ++m_LoadMeterDescription.callCount;
921     ++m_CumulativeLoadMeterDescription.callCount;
922 }
923 
924 //----------------------------------------
925 void
CalcLoadMeter()926 RenderSystem::CalcLoadMeter()
927 {
928     float callCount = static_cast<float>(m_LoadMeterDescription.callCount);
929     m_LoadMeterDescription.loadTime = m_LoadMeterDescription.cumulativeTime / callCount;
930     m_LoadMeterDescription.loadGpuTime = m_LoadMeterDescription.cumulativeGpuTime / callCount;
931     m_LoadMeterDescription.waitTime = m_LoadMeterDescription.cumulativeWaitTime / callCount;
932     m_LoadMeterDescription.cumulativeTime = 0.0f;
933     m_LoadMeterDescription.cumulativeGpuTime = 0.0f;
934     m_LoadMeterDescription.cumulativeWaitTime = 0.0f;
935     m_LoadMeterDescription.callCount = 0;
936 }
937 
938 //----------------------------------------
939 void
SuspendLoadMeter()940 RenderSystem::SuspendLoadMeter()
941 {
942     nn::os::Tick endTick = nn::os::Tick::GetSystemCurrent();
943 
944     s64 span = static_cast<nn::os::Tick>(endTick - m_LoadMeterDescription.startTick).ToTimeSpan().GetNanoSeconds();
945     m_LoadMeterDescription.cumulativeTime +=
946         static_cast<float>(span) * LoadMeterDescription::NANO_TO_MILLI;
947     m_CumulativeLoadMeterDescription.cumulativeTime +=
948         static_cast<float>(span) * LoadMeterDescription::NANO_TO_MILLI;
949 
950     m_LoadMeterDescription.startTick = 0;
951 }
952 
953 //----------------------------------------
954 void
ResumeLoadMeter()955 RenderSystem::ResumeLoadMeter()
956 {
957     m_LoadMeterDescription.startTick = nn::os::Tick::GetSystemCurrent();
958 }
959 
960 //----------------------------------------
961 void
ResetCumulativeLoadMeter()962 RenderSystem::ResetCumulativeLoadMeter()
963 {
964     m_CumulativeLoadMeterDescription.cumulativeTime = 0.0f;
965     m_CumulativeLoadMeterDescription.cumulativeGpuTime = 0.0f;
966     m_CumulativeLoadMeterDescription.cumulativeWaitTime = 0.0f;
967     m_CumulativeLoadMeterDescription.callCount = 0;
968 }
969 
970 
971 //----------------------------------------
972 SceneSystem*
Create(os::IAllocator * allocator,const Description & description)973 SceneSystem::Create(
974     os::IAllocator* allocator,
975     const Description& description
976 )
977 {
978     void* memory = allocator->Alloc(sizeof(SceneSystem));
979     SceneSystem* sceneSystem = new(memory) SceneSystem();
980 
981     sceneSystem->m_SceneContext = gfx::SceneContext::Builder()
982         .MaxSceneNodes(description.maxSceneNodes)
983         .MaxModels(description.maxModels)
984         .MaxSkeletalModels(description.maxSkeletalModels)
985         .MaxCameras(description.maxCameras)
986         .MaxLights(description.maxLights)
987         .MaxFragmentLights(description.maxFragmentLights)
988         .MaxVertexLights(description.maxVertexLights)
989         .MaxHemiSphereLights(description.maxHemiSphereLights)
990         .MaxAmbientLights(description.maxAmbientLights)
991         .MaxFogs(description.maxFogs)
992         .MaxParticleSets(description.maxParticleSets)
993         .MaxParticleEmitters(description.maxParticleEmitters)
994         .MaxParticleModels(description.maxParticleModels)
995         .IsFixedSizeMemory(description.isFixedSizeMemory)
996         .Create(allocator);
997 
998     sceneSystem->m_SceneTraverser = gfx::SceneTraverser::Builder()
999         .Create(allocator);
1000 
1001     gfx::WorldMatrixUpdater* worldMatrixUpdater = gfx::WorldMatrixUpdater::Builder()
1002         .Create(allocator);
1003 
1004     gfx::SkeletonUpdater* skeletonUpdater = gfx::SkeletonUpdater::Builder()
1005         .Create(allocator);
1006 
1007     sceneSystem->m_SceneUpdater = gfx::SceneUpdater::Builder()
1008         .WorldMatrixUpdaterPtr(worldMatrixUpdater)
1009         .SkeletonUpdaterPtr(skeletonUpdater)
1010         .Create(allocator);
1011 
1012     nw::gfx::IMaterialIdGenerator* materialIdGenerator =
1013         nw::gfx::SortingMaterialIdGenerator::Builder()
1014         .IsFixedSizeMemory(description.isFixedSizeMemory)
1015         .MaxMaterials(description.maxMaterials)
1016         .Create(allocator);
1017 
1018     sceneSystem->m_SceneInitializer = gfx::SceneInitializer::Builder()
1019         .MaterialIdGenerator(materialIdGenerator)
1020         .Create(allocator);
1021 
1022     sceneSystem->m_CameraController = CameraController::Builder()
1023         .Create(allocator);
1024 
1025     NW_GL_ASSERT();
1026 
1027     sceneSystem->m_Allocator = allocator;
1028 
1029     return sceneSystem;
1030 }
1031 
1032 //----------------------------------------
1033 void
Destroy()1034 SceneSystem::Destroy()
1035 {
1036     gfx::SafeDestroy(this->m_SceneInitializer);
1037     gfx::SafeDestroy(this->m_SceneTraverser);
1038     gfx::SafeDestroy(this->m_SceneUpdater);
1039     gfx::SafeDestroy(this->m_SceneContext);
1040 
1041     gfx::SafeDestroy(this->m_CameraController);
1042 
1043     os::IAllocator* allocator = this->m_Allocator;
1044 
1045     void* memory = static_cast<void*>(this);
1046     this->~SceneSystem();
1047     allocator->Free(memory);
1048 }
1049 
1050 //----------------------------------------
1051 void
InitializeScene(gfx::SceneNode * sceneRoot)1052 SceneSystem::InitializeScene(gfx::SceneNode* sceneRoot)
1053 {
1054     this->m_SceneInitializer->Begin();
1055     sceneRoot->Accept(this->m_SceneInitializer);
1056     this->m_SceneInitializer->End();
1057 
1058     TraverseScene(sceneRoot);
1059 }
1060 
1061 //----------------------------------------
1062 void
TraverseScene(gfx::SceneNode * sceneRoot)1063 SceneSystem::TraverseScene(gfx::SceneNode* sceneRoot)
1064 {
1065     this->m_SceneTraverser->Begin(this->m_SceneContext);
1066     sceneRoot->Accept(this->m_SceneTraverser);
1067     this->m_SceneTraverser->End();
1068 
1069     // パーティクルセットの依存順でソートする
1070     std::sort(
1071         this->m_SceneContext->GetParticleSetBegin(),
1072         this->m_SceneContext->GetParticleSetEnd(),
1073         gfx::ParticleSetCompare());
1074 }
1075 
1076 //----------------------------------------
1077 void
UpdateScene()1078 SceneSystem::UpdateScene()
1079 {
1080     NW_PROFILE("SceneSystem::UpdateScene");
1081 
1082     this->m_SceneUpdater->UpdateAll(this->m_SceneContext);
1083 }
1084 
1085 
1086 //----------------------------------------
1087 void
FinalizeGraphicsSystem()1088 FinalizeGraphicsSystem()
1089 {
1090     s_GraphicsMemoryAllocator.Finalize();
1091 
1092     nw::demo::FinalizeDemoAllocator(s_DeviceAllocator);
1093 }
1094 
1095 //----------------------------------------
1096 void
InitializeGraphicsSystem(nw::demo::DemoAllocator * deviceAllocator)1097 InitializeGraphicsSystem(nw::demo::DemoAllocator* deviceAllocator)
1098 {
1099     s_DeviceAllocator = deviceAllocator;
1100 
1101     nn::os::Initialize();
1102     nn::fs::Initialize();
1103 
1104     // メインメモリとデバイスメモリを初期化します。
1105     // メインメモリはユーザーが自由にアクセスできる領域となり、
1106     // デバイスメモリはGPUがアクセスするFCRAM上の領域となります。
1107     nw::demo::InitializeDemoMemory();
1108 
1109     nw::demo::InitializeDemoAllocator(s_DeviceAllocator, nw::demo::DEMO_MEMORY_SIZE, nn::os::ALLOCATE_OPTION_LINEAR);
1110 
1111     // デバイスメモリを用いるグラフィックスメモリアロケータを初期化します。
1112     s_GraphicsMemoryAllocator.Initialize(s_DeviceAllocator);
1113 
1114     const int MAX_FILE = 256;
1115     const int MAX_DIRECTORY = 16;
1116 
1117     s32 workingMemorySize = nn::fs::GetRomRequiredMemorySize(MAX_FILE, MAX_DIRECTORY);
1118     void* workingMemory = Alloc(workingMemorySize);
1119     nn::Result result = nn::fs::MountRom(MAX_FILE, MAX_DIRECTORY, workingMemory, workingMemorySize);
1120 
1121     NW_ASSERT(result.IsSuccess());
1122 }
1123 
1124 } // namespace demo
1125 } // namespace nw
1126