/*---------------------------------------------------------------------------* Project: Horizon File: gx_CommandCacheVSUniformModel.cpp Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 47228 $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include "demo.h" // Save the command list and reuse it. #define USE_COMMAND_CACHE namespace { const u32 s_CommandListSize = 0x800; const u32 s_CommandListRequestNum = 1; // Arguments to pass to the nngxUseSavedCmdlist function. // This sample saves a command list for each object. // When using combinations of command caches, consistent internal states are not always maintained. Consistency will depend on the contents of the caches. // For this reason, after calling the ngxUseSavedCmdlist function, complete commands should be generated for each state. // [TODO] Generating complete commands for all states is redundant. // Ideally, complete commands should be generated only for states that generate updates for each command cache. // 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. // GLbitfield s_StateMask = NN_GX_STATE_ALL; // Number of models to render const u32 MAX_MODEL_NUM = 50; // Copies the 3D command buffer. // GLboolean s_CopyCommandBuffer = GL_TRUE; // References the 3D command buffer. GLboolean s_CopyCommandBuffer = GL_FALSE; // Index of the array that stores the model view matrix. const u32 s_ModelViewArrayIndex = 0; // Start index of the floating point register of the model view matrix (ModelView c4-c7) in the vertex shader const u32 s_ModelViewRegIndex = 4; // Prepares one command cache for each model to render, links them and uses them. demo::CommandCache s_CommandCacheArray[MAX_MODEL_NUM]; GLuint s_ProgramId = 0; GLuint s_ShaderId = 0; nn::fnd::ExpHeap s_AppHeap; uptr s_AddrForGxHeap; const u32 s_GxHeapSize = 0x800000; demo::RenderSystem s_RenderSystem; nn::math::Vector3 s_CameraPosition(0.0f, 4.0f, 6.0f); nn::math::Vector3 s_CameraUp(0.0f, 1.0f, 0.0f); nn::math::Vector3 s_CameraTarget(0.0f, 0.0f, 0.0f); nn::math::Matrix34 s_ViewMatrix; nn::math::Matrix44 s_Display0ProjectionMatrix; nn::math::Matrix44 s_Display1ProjectionMatrix; f32 s_GlobalAmbientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f}; f32 s_Light0Ambient[] = { 0.3f, 0.3f, 0.3f, 1.0f}; f32 s_Light0Diffuse[] = { 0.7f, 0.7f, 0.7f, 1.0f}; f32 s_Light0Position[] = {15.0f, 15.0f, 15.0f, 1.0f}; f32 s_MaterialAmbient[] = {0.3f, 0.3f, 0.3f, 1.0f}; f32 s_MaterialDiffuse[] = {0.7f, 0.7f, 0.7f, 1.0f}; const nn::math::Vector3 s_InitialPosition(0.0f, -3.0f, 0.0f); const nn::math::Vector3 s_InitialVelocity(0.0f, 1.0f, 0.0f); const nn::math::Vector3 s_Gravity(0.0f, -0.1f, 0.0f); const f32 s_DeltaTime = 0.1f; demo::Particle s_ParticleArray[MAX_MODEL_NUM]; const f32 s_ParticleRadius = 0.4f; const u32 s_ParticleDivision = 4; } void Initialize(void); void InitializeGraphics(void); void InitializeCommandCache(void); void InitializeShader(void); void Finalize(void); // If using normal rendering bool DrawFrame(void); void SetDisplay0ProjectionMatrix(void); void UseProgram(void); void SetFragmentUniforms(void); void UpdateCamera(void); void DrawDisplay0(void); void DrawDisplay1(void); void UpdateBody(demo::Body& body); void DrawBody(demo::Body& body); // If using the command cache to render bool DrawFrameCommandCache(void); void MakeDisplay0CommandCache(void); void DrawDisplay0CommandCache(void); void UpdateDisplay0CommandCache(void); void Initialize(void) { // fs initialization nn::fs::Initialize(); const size_t ROMFS_BUFFER_SIZE = 1024 * 64; static char buffer[ROMFS_BUFFER_SIZE]; NN_UTIL_PANIC_IF_FAILED( nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE)); InitializeGraphics(); } void InitializeGraphics(void) { s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() ); s_AddrForGxHeap = reinterpret_cast(s_AppHeap.Allocate(s_GxHeapSize)); s_RenderSystem.Initialize(s_AddrForGxHeap, s_GxHeapSize); // Stops executing the command list. nngxStopCmdlist(); glClearColor(0.3f, 0.3f, 0.3f, 1.0f); glClearDepthf(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glCullFace(GL_BACK); InitializeShader(); // Initialize projection matrix nn::math::MTX44PerspectivePivotDeg(&s_Display0ProjectionMatrix, 45.0f, demo::DISPLAY0_ASPECT, 0.2f, 100.0f, nn::math::PIVOT_UPSIDE_TO_TOP); nn::math::MTX44PerspectivePivotDeg(&s_Display1ProjectionMatrix, 45.0f, demo::DISPLAY1_ASPECT, 0.2f, 100.0f, nn::math::PIVOT_UPSIDE_TO_TOP); u32 vertexAttributes = demo::VERTEX_POSITION_ATTRIBUTE | demo::VERTEX_COLOR_ATTRIBUTE | demo::VERTEX_NORMAL_ATTRIBUTE; demo::Particle::s_InitialPosition = ::s_InitialPosition; demo::Particle::s_InitialVelocity = ::s_InitialVelocity; demo::Particle::s_Gravity = ::s_Gravity; NN_LOG(" ParticleRadius = %f\n", s_ParticleRadius); for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++) { s_ParticleArray[modelIndex].InitializeParticle(vertexAttributes, s_ParticleRadius, s_ParticleDivision); } NN_LOG(" ParticleVerticesNum = %d\n", s_ParticleArray[0].m_Sphere.GetPackedVerticesNum()); NN_LOG(" ParticleTrianglesNum = %d\n", s_ParticleArray[0].m_Sphere.GetPackedTrianglesNum()); #ifdef USE_COMMAND_CACHE InitializeCommandCache(); #else NN_LOG("Normal mode (No command cache)\n"); #endif } void InitializeShader(void) { s_ProgramId = glCreateProgram(); // Load vertex shader s_ShaderId = glCreateShader(GL_VERTEX_SHADER); nn::fs::FileReader file(L"rom:/shader.shbin"); size_t fileSize = file.GetSize(); void* buf = s_AppHeap.Allocate(fileSize); s32 read = file.Read(buf, fileSize); glShaderBinary(1, &s_ShaderId, GL_PLATFORM_BINARY_DMP, buf, read); file.Finalize(); s_AppHeap.Free(buf); glAttachShader(s_ProgramId, s_ShaderId); glAttachShader(s_ProgramId, GL_DMP_FRAGMENT_SHADER_DMP); glBindAttribLocation(s_ProgramId, 0, "aPosition"); glBindAttribLocation(s_ProgramId, 1, "aColor"); glBindAttribLocation(s_ProgramId, 2, "aNormal"); glLinkProgram(s_ProgramId); glValidateProgram(s_ProgramId); demo::InitializeUniforms(s_ProgramId); } void InitializeCommandCache(void) { if ( s_CopyCommandBuffer ) { NN_LOG("Command cache mode (COPY 3D command buffer)\n"); } else { NN_LOG("Command cache mode (REFERENCE 3D command buffer)\n"); } // Initializes the command cache. for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++) { s_CommandCacheArray[modelIndex].Initialize(s_CommandListSize, s_CommandListRequestNum, s_CopyCommandBuffer, s_StateMask, 1); s_CommandCacheArray[modelIndex].SetVSUniformMatrixRegisterIndex(0, s_ModelViewArrayIndex, s_ModelViewRegIndex); } } void Finalize(void) { for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++) { s_ParticleArray[modelIndex].Finalize(); } #ifdef USE_COMMAND_CACHE for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++) { s_CommandCacheArray[modelIndex].Finalize(); } #endif s_RenderSystem.Finalize(); s_AppHeap.Free(reinterpret_cast(s_AddrForGxHeap)); s_AppHeap.Finalize(); } bool DrawFrame(void) { UpdateCamera(); DrawDisplay0(); DrawDisplay1(); s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH); return true; } void DrawDisplay0(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++) { s_ParticleArray[modelIndex].Update(s_DeltaTime); UseProgram(); SetFragmentUniforms(); SetDisplay0ProjectionMatrix(); DrawBody(s_ParticleArray[modelIndex]); } s_RenderSystem.SwapBuffers(); } void DrawDisplay1(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); s_RenderSystem.Clear(); s_RenderSystem.SwapBuffers(); } void UseProgram(void) { glUseProgram(s_ProgramId); } void SetFragmentUniforms(void) { // Fragment uniform glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_ALPHA_TEST], GL_FALSE); // Fragment uniform : Texture samplerType glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE0_SAMPLER_TYPE], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE1_SAMPLER_TYPE], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE2_SAMPLER_TYPE], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE3_SAMPLER_TYPE], GL_FALSE); // Fragment uniform : Fragment lighting glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_ENABLED], GL_TRUE); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_AMBIENT], 1, s_GlobalAmbientLight); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_ENABLED], GL_TRUE); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_AMBIENT], 1, s_Light0Ambient); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_DIFFUSE], 1, s_Light0Diffuse); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_POSITION], 1, s_Light0Position); // Fragment uniform : Material glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_AMBIENT], 1, s_MaterialAmbient); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_DIFFUSE], 1, s_MaterialDiffuse); // Fragment uniform : Texture combiner // Modulate fragment primary color and vertex color. glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_RGB], GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_PRIMARY_COLOR, GL_PREVIOUS); glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_ALPHA], GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PREVIOUS); glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_RGB], GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR); glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_ALPHA], GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_RGB], GL_MODULATE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_ALPHA], GL_MODULATE); } void UpdateCamera(void) { nn::math::MTX34LookAt(&s_ViewMatrix, &s_CameraPosition, &s_CameraUp, &s_CameraTarget); } void SetDisplay0ProjectionMatrix(void) { glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION], 1, GL_TRUE, static_cast(s_Display0ProjectionMatrix)); } void DrawBody(demo::Body& body) { nn::math::MTX44 modelViewMatrix(s_ViewMatrix); nn::math::Matrix44 worldMatrix = body.GetWorldMatrix(); nn::math::MTX44Mult(&modelViewMatrix, &modelViewMatrix, &worldMatrix); glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_MODELVIEW], 1, GL_TRUE, static_cast(modelViewMatrix)); body.Draw(); } bool DrawFrameCommandCache(void) { static bool s_InitializeCommandCache = false; if (! s_InitializeCommandCache ) { UpdateCamera(); MakeDisplay0CommandCache(); DrawDisplay1(); s_InitializeCommandCache = true; } else { UpdateCamera(); DrawDisplay0CommandCache(); DrawDisplay1(); } s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH); return true; } void MakeDisplay0CommandCache(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); UpdateCamera(); for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++) { s_ParticleArray[modelIndex].Update(s_DeltaTime); s_CommandCacheArray[modelIndex].BeginSave(); // Saves the offset to the start of the 3D command buffer when rendering one model s_CommandCacheArray[modelIndex].SaveCommandBufferStartOffset(0); UseProgram(); SetFragmentUniforms(); SetDisplay0ProjectionMatrix(); DrawBody(s_ParticleArray[modelIndex]); s_CommandCacheArray[modelIndex].EndSave(); } s_RenderSystem.SwapBuffers(); } void DrawDisplay0CommandCache(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(NN_GX_DISPLAY_BOTH); UpdateCamera(); for (u32 modelIndex = 0; modelIndex < MAX_MODEL_NUM; modelIndex++) { demo::Particle& particle = s_ParticleArray[modelIndex]; particle.Update(s_DeltaTime); // Calculates model view matrices of the particles. nn::math::MTX44 modelViewMatrix(s_ViewMatrix); nn::math::Matrix44 worldMatrix = particle.GetWorldMatrix(); nn::math::MTX44Mult(&modelViewMatrix, &modelViewMatrix, &worldMatrix); // Updates model view matrices of the particles. s_CommandCacheArray[modelIndex].UpdateVSUniformMatrix(0, s_ModelViewArrayIndex, modelViewMatrix); // Adds the saved command list to the current command list. s_CommandCacheArray[modelIndex].Append(); } s_RenderSystem.SwapBuffers(); } void nnMain(void) { // Call only nn::applet::Enable to also allow execution from the HOME Menu // HOME Menu transitions, POWER Button presses, and sleep are all unsupported nn::applet::Enable(); Initialize(); bool flag = true; while ( flag ) { flag = DrawFrame(); } Finalize(); }