1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     gx_CommandCacheVSUniformModel.cpp
4 
5   Copyright (C)2009-2012 Nintendo Co., Ltd.  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   $Rev: 47228 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/os.h>
17 #include <nn/fnd.h>
18 #include <nn/gx.h>
19 #include <nn/math.h>
20 #include <nn/fs.h>
21 #include <nn/init.h>
22 #include <nn/applet.h>
23 
24 #include "demo.h"
25 
26 // Save the command list and reuse it.
27 #define USE_COMMAND_CACHE
28 
29 namespace
30 {
31     const u32 s_CommandListSize = 0x800;
32     const u32 s_CommandListRequestNum = 1;
33 
34     // Arguments to pass to the nngxUseSavedCmdlist function.
35     // This sample saves a command list for each object.
36     // When using combinations of command caches, consistent internal states are not always maintained. Consistency will depend on the contents of the caches.
37     // For this reason, after calling the ngxUseSavedCmdlist function, complete commands should be generated for each state.
38     // [TODO] Generating complete commands for all states is redundant.
39     //        Ideally, complete commands should be generated only for states that generate updates for each command cache.
40     //        Currently, there is no easy way to obtain the states that were updated in response to caches generated at runtime. For this reason, the demo generates complete commands for all states.
41     //
42     GLbitfield s_StateMask = NN_GX_STATE_ALL;
43 
44     // Number of models to render
45     const u32 MAX_MODEL_NUM = 50;
46 
47     // Copies the 3D command buffer.
48     // GLboolean s_CopyCommandBuffer = GL_TRUE;
49     // References the 3D command buffer.
50     GLboolean s_CopyCommandBuffer = GL_FALSE;
51 
52     // Index of the array that stores the model view matrix.
53     const u32 s_ModelViewArrayIndex = 0;
54     // Start index of the floating point register of the model view matrix (ModelView c4-c7) in the vertex shader
55     const u32 s_ModelViewRegIndex = 4;
56 
57     // Prepares one command cache for each model to render, links them and uses them.
58     demo::CommandCache s_CommandCacheArray[MAX_MODEL_NUM];
59 
60     GLuint s_ProgramId = 0;
61     GLuint s_ShaderId = 0;
62 
63     nn::fnd::ExpHeap s_AppHeap;
64     uptr s_AddrForGxHeap;
65     const u32 s_GxHeapSize = 0x800000;
66 
67     demo::RenderSystem s_RenderSystem;
68 
69     nn::math::Vector3 s_CameraPosition(0.0f, 4.0f, 6.0f);
70     nn::math::Vector3 s_CameraUp(0.0f, 1.0f, 0.0f);
71     nn::math::Vector3 s_CameraTarget(0.0f, 0.0f, 0.0f);
72 
73     nn::math::Matrix34 s_ViewMatrix;
74     nn::math::Matrix44 s_Display0ProjectionMatrix;
75     nn::math::Matrix44 s_Display1ProjectionMatrix;
76 
77     f32 s_GlobalAmbientLight[] = { 0.3f,  0.3f,  0.3f, 1.0f};
78     f32 s_Light0Ambient[]      = { 0.3f,  0.3f,  0.3f, 1.0f};
79     f32 s_Light0Diffuse[]      = { 0.7f,  0.7f,  0.7f, 1.0f};
80     f32 s_Light0Position[]     = {15.0f, 15.0f, 15.0f, 1.0f};
81 
82     f32 s_MaterialAmbient[] = {0.3f, 0.3f, 0.3f, 1.0f};
83     f32 s_MaterialDiffuse[] = {0.7f, 0.7f, 0.7f, 1.0f};
84 
85     const nn::math::Vector3 s_InitialPosition(0.0f, -3.0f, 0.0f);
86     const nn::math::Vector3 s_InitialVelocity(0.0f, 1.0f, 0.0f);
87     const nn::math::Vector3 s_Gravity(0.0f, -0.1f, 0.0f);
88 
89     const f32 s_DeltaTime = 0.1f;
90     demo::Particle s_ParticleArray[MAX_MODEL_NUM];
91 
92     const f32 s_ParticleRadius = 0.4f;
93     const u32 s_ParticleDivision = 4;
94 }
95 
96 void Initialize(void);
97 void InitializeGraphics(void);
98 void InitializeCommandCache(void);
99 void InitializeShader(void);
100 
101 void Finalize(void);
102 
103 // If using normal rendering
104 bool DrawFrame(void);
105 void SetDisplay0ProjectionMatrix(void);
106 void UseProgram(void);
107 void SetFragmentUniforms(void);
108 void UpdateCamera(void);
109 void DrawDisplay0(void);
110 void DrawDisplay1(void);
111 void UpdateBody(demo::Body& body);
112 void DrawBody(demo::Body& body);
113 
114 // If using the command cache to render
115 bool DrawFrameCommandCache(void);
116 void MakeDisplay0CommandCache(void);
117 void DrawDisplay0CommandCache(void);
118 void UpdateDisplay0CommandCache(void);
119 
Initialize(void)120 void Initialize(void)
121 {
122     // fs initialization
123     nn::fs::Initialize();
124 
125     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
126     static char buffer[ROMFS_BUFFER_SIZE];
127     NN_UTIL_PANIC_IF_FAILED(
128         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
129 
130     InitializeGraphics();
131 }
132 
InitializeGraphics(void)133 void InitializeGraphics(void)
134 {
135     s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(),
136         nn::os::GetDeviceMemorySize() );
137     s_AddrForGxHeap = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
138 
139     s_RenderSystem.Initialize(s_AddrForGxHeap, s_GxHeapSize);
140 
141     // Stops executing the command list.
142     nngxStopCmdlist();
143 
144     glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
145     glClearDepthf(1.0f);
146 
147     glEnable(GL_DEPTH_TEST);
148     glDepthFunc(GL_LESS);
149 
150     glEnable(GL_CULL_FACE);
151     glFrontFace(GL_CCW);
152     glCullFace(GL_BACK);
153 
154     InitializeShader();
155 
156     // Initialize projection matrix
157     nn::math::MTX44PerspectivePivotDeg(&s_Display0ProjectionMatrix, 45.0f,
158         demo::DISPLAY0_ASPECT, 0.2f, 100.0f,
159         nn::math::PIVOT_UPSIDE_TO_TOP);
160 
161     nn::math::MTX44PerspectivePivotDeg(&s_Display1ProjectionMatrix, 45.0f,
162         demo::DISPLAY1_ASPECT, 0.2f, 100.0f,
163         nn::math::PIVOT_UPSIDE_TO_TOP);
164 
165     u32 vertexAttributes = demo::VERTEX_POSITION_ATTRIBUTE |
166         demo::VERTEX_COLOR_ATTRIBUTE |
167         demo::VERTEX_NORMAL_ATTRIBUTE;
168 
169     demo::Particle::s_InitialPosition = ::s_InitialPosition;
170     demo::Particle::s_InitialVelocity = ::s_InitialVelocity;
171     demo::Particle::s_Gravity = ::s_Gravity;
172 
173     NN_LOG("  ParticleRadius = %f\n", s_ParticleRadius);
174 
175     for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++)
176     {
177         s_ParticleArray[modelIndex].InitializeParticle(vertexAttributes, s_ParticleRadius, s_ParticleDivision);
178     }
179     NN_LOG("  ParticleVerticesNum = %d\n", s_ParticleArray[0].m_Sphere.GetPackedVerticesNum());
180     NN_LOG("  ParticleTrianglesNum = %d\n", s_ParticleArray[0].m_Sphere.GetPackedTrianglesNum());
181 
182 #ifdef USE_COMMAND_CACHE
183     InitializeCommandCache();
184 #else
185     NN_LOG("Normal mode (No command cache)\n");
186 #endif
187 }
188 
InitializeShader(void)189 void InitializeShader(void)
190 {
191     s_ProgramId = glCreateProgram();
192 
193     // Load vertex shader
194     s_ShaderId = glCreateShader(GL_VERTEX_SHADER);
195     nn::fs::FileReader file(L"rom:/shader.shbin");
196     size_t fileSize = file.GetSize();
197     void* buf = s_AppHeap.Allocate(fileSize);
198     s32 read = file.Read(buf, fileSize);
199     glShaderBinary(1, &s_ShaderId, GL_PLATFORM_BINARY_DMP, buf, read);
200     file.Finalize();
201     s_AppHeap.Free(buf);
202 
203     glAttachShader(s_ProgramId, s_ShaderId);
204     glAttachShader(s_ProgramId, GL_DMP_FRAGMENT_SHADER_DMP);
205 
206     glBindAttribLocation(s_ProgramId, 0, "aPosition");
207     glBindAttribLocation(s_ProgramId, 1, "aColor");
208     glBindAttribLocation(s_ProgramId, 2, "aNormal");
209 
210     glLinkProgram(s_ProgramId);
211     glValidateProgram(s_ProgramId);
212 
213     demo::InitializeUniforms(s_ProgramId);
214 }
215 
InitializeCommandCache(void)216 void InitializeCommandCache(void)
217 {
218     if ( s_CopyCommandBuffer )
219     {
220         NN_LOG("Command cache mode (COPY 3D command buffer)\n");
221     }
222     else
223     {
224         NN_LOG("Command cache mode (REFERENCE 3D command buffer)\n");
225     }
226 
227     // Initializes the command cache.
228     for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++)
229     {
230         s_CommandCacheArray[modelIndex].Initialize(s_CommandListSize, s_CommandListRequestNum,
231             s_CopyCommandBuffer, s_StateMask, 1);
232 
233         s_CommandCacheArray[modelIndex].SetVSUniformMatrixRegisterIndex(0, s_ModelViewArrayIndex, s_ModelViewRegIndex);
234     }
235 }
236 
Finalize(void)237 void Finalize(void)
238 {
239     for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++)
240     {
241         s_ParticleArray[modelIndex].Finalize();
242     }
243 
244 #ifdef USE_COMMAND_CACHE
245     for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++)
246     {
247         s_CommandCacheArray[modelIndex].Finalize();
248     }
249 #endif
250 
251     s_RenderSystem.Finalize();
252 
253     s_AppHeap.Free(reinterpret_cast<void*>(s_AddrForGxHeap));
254     s_AppHeap.Finalize();
255 }
256 
257 
DrawFrame(void)258 bool DrawFrame(void)
259 {
260     UpdateCamera();
261     DrawDisplay0();
262     DrawDisplay1();
263 
264     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
265 
266     return true;
267 }
268 
DrawDisplay0(void)269 void DrawDisplay0(void)
270 {
271     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
272     s_RenderSystem.Clear();
273 
274     for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++)
275     {
276         s_ParticleArray[modelIndex].Update(s_DeltaTime);
277 
278         UseProgram();
279         SetFragmentUniforms();
280         SetDisplay0ProjectionMatrix();
281 
282         DrawBody(s_ParticleArray[modelIndex]);
283     }
284 
285     s_RenderSystem.SwapBuffers();
286 }
287 
DrawDisplay1(void)288 void DrawDisplay1(void)
289 {
290     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
291     s_RenderSystem.Clear();
292 
293     s_RenderSystem.SwapBuffers();
294 }
295 
UseProgram(void)296 void UseProgram(void)
297 {
298     glUseProgram(s_ProgramId);
299 }
300 
SetFragmentUniforms(void)301 void SetFragmentUniforms(void)
302 {
303     // Fragment uniform
304     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_ALPHA_TEST], GL_FALSE);
305 
306     // Fragment uniform : Texture samplerType
307     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE0_SAMPLER_TYPE], GL_FALSE);
308     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE1_SAMPLER_TYPE], GL_FALSE);
309     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE2_SAMPLER_TYPE], GL_FALSE);
310     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE3_SAMPLER_TYPE], GL_FALSE);
311 
312     // Fragment uniform : Fragment lighting
313     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_ENABLED], GL_TRUE);
314     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_AMBIENT], 1, s_GlobalAmbientLight);
315     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_ENABLED], GL_TRUE);
316     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_AMBIENT], 1, s_Light0Ambient);
317     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_DIFFUSE], 1, s_Light0Diffuse);
318     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_POSITION], 1, s_Light0Position);
319 
320     // Fragment uniform : Material
321     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_AMBIENT], 1, s_MaterialAmbient);
322     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_DIFFUSE], 1, s_MaterialDiffuse);
323 
324     // Fragment uniform : Texture combiner
325     //   Modulate fragment primary color and vertex color.
326     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_RGB],
327         GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_PRIMARY_COLOR, GL_PREVIOUS);
328     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_ALPHA],
329         GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PREVIOUS);
330     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_RGB],
331         GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
332     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_ALPHA],
333         GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
334     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_RGB],
335         GL_MODULATE);
336     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_ALPHA],
337         GL_MODULATE);
338 }
339 
UpdateCamera(void)340 void UpdateCamera(void)
341 {
342     nn::math::MTX34LookAt(&s_ViewMatrix, &s_CameraPosition, &s_CameraUp, &s_CameraTarget);
343 }
344 
SetDisplay0ProjectionMatrix(void)345 void SetDisplay0ProjectionMatrix(void)
346 {
347     glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION],
348         1, GL_TRUE, static_cast<f32*>(s_Display0ProjectionMatrix));
349 }
350 
DrawBody(demo::Body & body)351 void DrawBody(demo::Body& body)
352 {
353     nn::math::MTX44 modelViewMatrix(s_ViewMatrix);
354     nn::math::Matrix44 worldMatrix = body.GetWorldMatrix();
355     nn::math::MTX44Mult(&modelViewMatrix, &modelViewMatrix, &worldMatrix);
356     glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_MODELVIEW],
357         1, GL_TRUE, static_cast<f32*>(modelViewMatrix));
358 
359     body.Draw();
360 }
361 
DrawFrameCommandCache(void)362 bool DrawFrameCommandCache(void)
363 {
364     static bool s_InitializeCommandCache = false;
365     if (! s_InitializeCommandCache )
366     {
367         UpdateCamera();
368         MakeDisplay0CommandCache();
369 
370         DrawDisplay1();
371         s_InitializeCommandCache = true;
372     }
373     else
374     {
375         UpdateCamera();
376         DrawDisplay0CommandCache();
377         DrawDisplay1();
378     }
379 
380     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
381 
382     return true;
383 }
384 
MakeDisplay0CommandCache(void)385 void MakeDisplay0CommandCache(void)
386 {
387     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
388     s_RenderSystem.Clear();
389 
390     UpdateCamera();
391 
392     for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++)
393     {
394         s_ParticleArray[modelIndex].Update(s_DeltaTime);
395 
396         s_CommandCacheArray[modelIndex].BeginSave();
397 
398         // Saves the offset to the start of the 3D command buffer when rendering one model
399         s_CommandCacheArray[modelIndex].SaveCommandBufferStartOffset(0);
400 
401         UseProgram();
402         SetFragmentUniforms();
403         SetDisplay0ProjectionMatrix();
404 
405         DrawBody(s_ParticleArray[modelIndex]);
406 
407         s_CommandCacheArray[modelIndex].EndSave();
408     }
409 
410     s_RenderSystem.SwapBuffers();
411 }
412 
DrawDisplay0CommandCache(void)413 void DrawDisplay0CommandCache(void)
414 {
415     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
416     s_RenderSystem.Clear(NN_GX_DISPLAY_BOTH);
417 
418     UpdateCamera();
419 
420     for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++)
421     {
422         demo::Particle& particle = s_ParticleArray[modelIndex];
423         particle.Update(s_DeltaTime);
424 
425         // Calculates model view matrices of the particles.
426         nn::math::MTX44 modelViewMatrix(s_ViewMatrix);
427         nn::math::Matrix44 worldMatrix = particle.GetWorldMatrix();
428         nn::math::MTX44Mult(&modelViewMatrix, &modelViewMatrix, &worldMatrix);
429 
430         // Updates model view matrices of the particles.
431         s_CommandCacheArray[modelIndex].UpdateVSUniformMatrix(0, s_ModelViewArrayIndex, modelViewMatrix);
432 
433         // Adds the saved command list to the current command list.
434         s_CommandCacheArray[modelIndex].Append();
435     }
436 
437     s_RenderSystem.SwapBuffers();
438 }
439 
nnMain(void)440 void nnMain(void)
441 {
442     // Call only nn::applet::Enable to also allow execution from the HOME Menu
443     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
444     nn::applet::Enable();
445 
446     Initialize();
447 
448     bool flag = true;
449     while ( flag )
450     {
451         flag = DrawFrame();
452     }
453 
454     Finalize();
455 }
456