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