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