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