1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     gx_CommandCacheSimple.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/types.h>
17 
18 #include <nn/os.h>
19 #include <nn/fnd.h>
20 #include <nn/gx.h>
21 #include <nn/math.h>
22 #include <nn/fs.h>
23 #include <nn/init.h>
24 #include <nn/applet.h>
25 
26 #include "demo.h"
27 
28 // Save the command list and reuse it.
29 //
30 // This sample merely saves the command list and reuses it, and does not edit the saved command list.
31 //
32 #define USE_COMMAND_CACHE
33 
34 namespace
35 {
36     GLuint s_CurrentCommandListId = 0;
37     GLuint s_SavedCommandListId = 0;
38     GLuint s_SavedCommandBufferOffset = 0;
39     GLsizei s_SavedCommandBufferSize = 0;
40     GLuint s_SavedCommandRequestBeginId = 0;
41     GLsizei s_SavedCommandRequestSize = 0;
42 
43     GLbitfield s_StateMask = 0;
44 
45     // References the 3D command buffer.
46     // GLboolean s_CopyCommandBuffer = GL_FALSE;
47     // Copies the 3D command buffer.
48     GLboolean s_CopyCommandBuffer = GL_TRUE;
49 
50     GLuint s_ProgramId = 0;
51     GLuint s_ShaderId = 0;
52 
53     nn::fnd::ExpHeap s_AppHeap;
54     uptr s_AddrForGxHeap;
55     const u32 s_GxHeapSize = 0x400000;
56 
57     demo::RenderSystem s_RenderSystem;
58 
59     nn::math::Vector3 s_CameraPosition(0.0f, 2.0f, 2.0f);
60     nn::math::Vector3 s_CameraUp(0.0f, 1.0f, 0.0f);
61     nn::math::Vector3 s_CameraTarget(0.0f, 0.0f, 0.0f);
62 
63     nn::math::Matrix34 s_ViewMatrix;
64     nn::math::Matrix44 s_Display0ProjectionMatrix;
65     nn::math::Matrix44 s_Display1ProjectionMatrix;
66 
67     f32 s_GlobalAmbientLight[] = { 0.3f,  0.3f,  0.3f, 1.0f};
68     f32 s_Light0Ambient[]      = { 0.3f,  0.3f,  0.3f, 1.0f};
69     f32 s_Light0Diffuse[]      = { 0.7f,  0.7f,  0.7f, 1.0f};
70     f32 s_Light0Position[]     = {15.0f, 15.0f, 15.0f, 1.0f};
71 
72     f32 s_MaterialAmbient[] = {0.3f, 0.3f, 0.3f, 1.0f};
73     f32 s_MaterialDiffuse[] = {0.7f, 0.7f, 0.7f, 1.0f};
74 
75     demo::Cube s_Cube;
76 }
77 
78 void InitializeGraphics(void);
79 void InitializeShader(void);
80 
81 bool DrawFrame(void);
82 void UseShader(void);
83 void UpdateCamera(void);
84 void DrawDisplay0(void);
85 void DrawDisplay1(void);
86 
87 void UpdateBody(demo::Body& body);
88 void DrawBody(demo::Body& body);
89 
90 bool DrawFrameCommandCache(void);
91 void DrawDisplay0CommandCache(void);
92 void MakeDisplay0CommandCache(void);
93 void CopyCommandList(void);
94 
Initialize(void)95 void Initialize(void)
96 {
97     // fs initialization
98     nn::fs::Initialize();
99 
100     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
101     static char buffer[ROMFS_BUFFER_SIZE];
102     NN_UTIL_PANIC_IF_FAILED(
103         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
104 
105     InitializeGraphics();
106 }
107 
InitializeGraphics(void)108 void InitializeGraphics(void)
109 {
110     s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(),
111         nn::os::GetDeviceMemorySize() );
112     s_AddrForGxHeap = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
113 
114     s_RenderSystem.Initialize(s_AddrForGxHeap, s_GxHeapSize);
115 
116     glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
117     glClearDepthf(1.f);
118 
119     glEnable(GL_DEPTH_TEST);
120     glDepthFunc(GL_LESS);
121 
122     glEnable(GL_CULL_FACE);
123     glFrontFace(GL_CCW);
124     glCullFace(GL_BACK);
125 
126     InitializeShader();
127 
128     // Initialize projection matrix
129     nn::math::MTX44PerspectivePivotDeg(&s_Display0ProjectionMatrix, 45.0f,
130         demo::DISPLAY0_ASPECT, 0.2f, 100.0f,
131         nn::math::PIVOT_UPSIDE_TO_TOP);
132 
133     nn::math::MTX44PerspectivePivotDeg(&s_Display1ProjectionMatrix, 45.0f,
134         demo::DISPLAY1_ASPECT, 0.2f, 100.0f,
135         nn::math::PIVOT_UPSIDE_TO_TOP);
136 
137     // Initialize cube
138     u32 vertexAttributes = demo::VERTEX_POSITION_ATTRIBUTE |
139         demo::VERTEX_COLOR_ATTRIBUTE |
140         demo::VERTEX_NORMAL_ATTRIBUTE;
141     s_Cube.InitializeCube(vertexAttributes, 0.5f, 0.5f, 0.5f);
142     s_Cube.SetColor(1.0f, 0.0f, 0.0f);
143     s_Cube.SetWorldPosition(0.0f, 0.0f, 0.0f);
144     s_Cube.SetWorldAngle(0.0f, 45.0f, 0.0f);
145 }
146 
InitializeShader(void)147 void InitializeShader(void)
148 {
149     s_ProgramId = glCreateProgram();
150 
151     // Load vertex shader
152     s_ShaderId = glCreateShader(GL_VERTEX_SHADER);
153     nn::fs::FileReader file(L"rom:/shader.shbin");
154     size_t fileSize = file.GetSize();
155     void* buf = s_AppHeap.Allocate(fileSize);
156     s32 read = file.Read(buf, fileSize);
157     glShaderBinary(1, &s_ShaderId, GL_PLATFORM_BINARY_DMP, buf, read);
158     file.Finalize();
159     s_AppHeap.Free(buf);
160 
161     glAttachShader(s_ProgramId, s_ShaderId);
162     glAttachShader(s_ProgramId, GL_DMP_FRAGMENT_SHADER_DMP);
163 
164     glBindAttribLocation(s_ProgramId, 0, "aPosition");
165     glBindAttribLocation(s_ProgramId, 1, "aColor");
166     glBindAttribLocation(s_ProgramId, 2, "aNormal");
167 
168     glLinkProgram(s_ProgramId);
169     glValidateProgram(s_ProgramId);
170 
171     demo::InitializeUniforms(s_ProgramId);
172 }
173 
Finalize(void)174 void Finalize(void)
175 {
176     s_Cube.Finalize();
177 
178     s_RenderSystem.Finalize();
179 
180     s_AppHeap.Free(reinterpret_cast<void*>(s_AddrForGxHeap));
181     s_AppHeap.Finalize();
182 }
183 
DrawFrame(void)184 bool DrawFrame(void)
185 {
186     UpdateCamera();
187     DrawDisplay0();
188     DrawDisplay1();
189 
190     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
191 
192     return true;
193 }
194 
UpdateCamera(void)195 void UpdateCamera(void)
196 {
197     nn::math::MTX34LookAt(&s_ViewMatrix, &s_CameraPosition, &s_CameraUp, &s_CameraTarget);
198 }
199 
DrawDisplay0(void)200 void DrawDisplay0(void)
201 {
202     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
203     s_RenderSystem.Clear();
204 
205     UseShader();
206     glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION],
207         1, GL_TRUE, static_cast<f32*>(s_Display0ProjectionMatrix));
208 
209     UpdateBody(s_Cube);
210     DrawBody(s_Cube);
211 
212     s_RenderSystem.SwapBuffers();
213 }
214 
UseShader(void)215 void UseShader(void)
216 {
217     glUseProgram(s_ProgramId);
218 
219     // Fragment uniform
220     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_ALPHA_TEST], GL_FALSE);
221 
222     // Fragment uniform : Texture samplerType
223     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE0_SAMPLER_TYPE], GL_FALSE);
224     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE1_SAMPLER_TYPE], GL_FALSE);
225     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE2_SAMPLER_TYPE], GL_FALSE);
226     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE3_SAMPLER_TYPE], GL_FALSE);
227 
228     // Fragment uniform : Fragment lighting
229     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_ENABLED], GL_TRUE);
230     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_AMBIENT], 1, s_GlobalAmbientLight);
231     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_ENABLED], GL_TRUE);
232     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_AMBIENT], 1, s_Light0Ambient);
233     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_DIFFUSE], 1, s_Light0Diffuse);
234     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_POSITION], 1, s_Light0Position);
235 
236     // Fragment uniform : Material
237     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_AMBIENT], 1, s_MaterialAmbient);
238     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_DIFFUSE], 1, s_MaterialDiffuse);
239 
240     // Fragment uniform : Texture combiner
241     //   Modulate fragment primary color and vertex color.
242     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_RGB],
243         GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_PRIMARY_COLOR, GL_PREVIOUS);
244     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_ALPHA],
245         GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PREVIOUS);
246     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_RGB],
247         GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
248     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_ALPHA],
249         GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
250     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_RGB],
251         GL_MODULATE);
252     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_ALPHA],
253         GL_MODULATE);
254 }
255 
DrawDisplay1(void)256 void DrawDisplay1(void)
257 {
258     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
259     s_RenderSystem.Clear();
260 
261     s_RenderSystem.SwapBuffers();
262 }
263 
UpdateBody(demo::Body & body)264 void UpdateBody(demo::Body& body)
265 {
266     f32 worldAngle[3];
267     body.GetWorldAngle(worldAngle[0], worldAngle[1], worldAngle[2]);
268     worldAngle[1] += 1.0f;
269     if ( worldAngle[1] > 360.0f )
270     {
271         worldAngle[1] = 0.0f;
272     }
273     body.SetWorldAngle(worldAngle[0], worldAngle[1], worldAngle[2]);
274 }
275 
DrawBody(demo::Body & body)276 void DrawBody(demo::Body& body)
277 {
278     nn::math::MTX44 modelViewMatrix(s_ViewMatrix);
279     nn::math::Matrix44 worldMatrix = body.GetWorldMatrix();
280     nn::math::MTX44Mult(&modelViewMatrix, &modelViewMatrix, &worldMatrix);
281     glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_MODELVIEW],
282         1, GL_TRUE, static_cast<f32*>(modelViewMatrix));
283 
284     body.Draw();
285 }
286 
DrawFrameCommandCache(void)287 bool DrawFrameCommandCache(void)
288 {
289     static bool s_InitializeCommandCache = false;
290     if (! s_InitializeCommandCache )
291     {
292         UpdateCamera();
293         // Creates and saves the command list.
294         MakeDisplay0CommandCache();
295         DrawDisplay1();
296         s_InitializeCommandCache = true;
297     }
298     else
299     {
300         UpdateCamera();
301         // Reuses the saved command list.
302         DrawDisplay0CommandCache();
303         DrawDisplay1();
304     }
305 
306     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
307 
308     return true;
309 }
310 
MakeDisplay0CommandCache(void)311 void MakeDisplay0CommandCache(void)
312 {
313     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
314     s_RenderSystem.Clear();
315 
316     // Starts saving the command list.
317     nngxStartCmdlistSave();
318 
319     UseShader();
320     glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION],
321         1, GL_TRUE, static_cast<f32*>(s_Display0ProjectionMatrix));
322 
323     UpdateBody(s_Cube);
324     DrawBody(s_Cube);
325 
326     // Finishes saving the command list and copies it.
327     CopyCommandList();
328 
329     s_RenderSystem.SwapBuffers();
330 }
331 
DrawDisplay0CommandCache(void)332 void DrawDisplay0CommandCache(void)
333 {
334     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
335     s_RenderSystem.Clear();
336 
337     // Adds the saved command list to the current command list.
338     nngxUseSavedCmdlist(s_SavedCommandListId,
339         s_SavedCommandBufferOffset, s_SavedCommandBufferSize,
340         s_SavedCommandRequestBeginId, s_SavedCommandRequestSize,
341         s_StateMask,
342         s_CopyCommandBuffer);
343 
344     s_RenderSystem.SwapBuffers();
345 }
346 
CopyCommandList(void)347 void CopyCommandList(void)
348 {
349     if (! s_CopyCommandBuffer )
350     {
351         nngxSplitDrawCmdlist();
352     }
353 
354     // Ends saving the command list.
355     nngxStopCmdlistSave(&s_SavedCommandBufferOffset, &s_SavedCommandBufferSize,
356         &s_SavedCommandRequestBeginId, &s_SavedCommandRequestSize);
357     NN_LOG("Saved CommandList information\n");
358     NN_LOG("  bufferOffset   = %d, bufferSize  = %d\n", s_SavedCommandBufferOffset, s_SavedCommandBufferSize);
359     NN_LOG("  requestBeginId = %d, requestSize = %d\n", s_SavedCommandRequestBeginId, s_SavedCommandRequestSize);
360 
361     // Allocates command list at the save destination.
362     nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, (GLint*)&s_CurrentCommandListId);
363     NN_LOG("CurrentCommandListId = %d\n", s_CurrentCommandListId);
364 
365     nngxGenCmdlists(1, &s_SavedCommandListId);
366     NN_LOG("SavedCommandListId = %d\n", s_SavedCommandListId);
367     nngxBindCmdlist(s_SavedCommandListId);
368     nngxCmdlistStorage(0x10000, 32);
369 
370     // Unbinds the current command list.
371     nngxBindCmdlist(0);
372 
373     // Copies the current command list to the command list at the save destination.
374     nngxCopyCmdlist(s_CurrentCommandListId, s_SavedCommandListId);
375 
376     // Bind the command list.
377     nngxBindCmdlist(s_CurrentCommandListId);
378 
379     DEMO_ASSERT_GL_ERROR();
380 }
381 
nnMain(void)382 void nnMain(void)
383 {
384     // Call only nn::applet::Enable to also allow execution from the HOME Menu
385     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
386     nn::applet::Enable();
387 
388     Initialize();
389 
390     bool flag = true;
391     while ( flag )
392     {
393 #ifdef USE_COMMAND_CACHE
394         flag = DrawFrameCommandCache();
395 #else
396         flag = DrawFrame();
397 #endif
398     }
399 
400     Finalize();
401 }
402