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