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