/*---------------------------------------------------------------------------* Project: Horizon File: gx_CommandCacheSimple.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 #include "demo.h" // Save the command list and reuse it. // // This sample merely saves the command list and reuses it, and does not edit the saved command list. // #define USE_COMMAND_CACHE namespace { GLuint s_CurrentCommandListId = 0; GLuint s_SavedCommandListId = 0; GLuint s_SavedCommandBufferOffset = 0; GLsizei s_SavedCommandBufferSize = 0; GLuint s_SavedCommandRequestBeginId = 0; GLsizei s_SavedCommandRequestSize = 0; GLbitfield s_StateMask = 0; // References the 3D command buffer. // GLboolean s_CopyCommandBuffer = GL_FALSE; // Copies the 3D command buffer. GLboolean s_CopyCommandBuffer = GL_TRUE; GLuint s_ProgramId = 0; GLuint s_ShaderId = 0; nn::fnd::ExpHeap s_AppHeap; uptr s_AddrForGxHeap; const u32 s_GxHeapSize = 0x400000; demo::RenderSystem s_RenderSystem; nn::math::Vector3 s_CameraPosition(0.0f, 2.0f, 2.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}; demo::Cube s_Cube; } void InitializeGraphics(void); void InitializeShader(void); bool DrawFrame(void); void UseShader(void); void UpdateCamera(void); void DrawDisplay0(void); void DrawDisplay1(void); void UpdateBody(demo::Body& body); void DrawBody(demo::Body& body); bool DrawFrameCommandCache(void); void DrawDisplay0CommandCache(void); void MakeDisplay0CommandCache(void); void CopyCommandList(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); glClearColor(0.3f, 0.3f, 0.3f, 1.0f); glClearDepthf(1.f); 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); // Initialize cube u32 vertexAttributes = demo::VERTEX_POSITION_ATTRIBUTE | demo::VERTEX_COLOR_ATTRIBUTE | demo::VERTEX_NORMAL_ATTRIBUTE; s_Cube.InitializeCube(vertexAttributes, 0.5f, 0.5f, 0.5f); s_Cube.SetColor(1.0f, 0.0f, 0.0f); s_Cube.SetWorldPosition(0.0f, 0.0f, 0.0f); s_Cube.SetWorldAngle(0.0f, 45.0f, 0.0f); } 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 Finalize(void) { s_Cube.Finalize(); 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 UpdateCamera(void) { nn::math::MTX34LookAt(&s_ViewMatrix, &s_CameraPosition, &s_CameraUp, &s_CameraTarget); } void DrawDisplay0(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); UseShader(); glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION], 1, GL_TRUE, static_cast(s_Display0ProjectionMatrix)); UpdateBody(s_Cube); DrawBody(s_Cube); s_RenderSystem.SwapBuffers(); } void UseShader(void) { glUseProgram(s_ProgramId); // 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 DrawDisplay1(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); s_RenderSystem.Clear(); s_RenderSystem.SwapBuffers(); } void UpdateBody(demo::Body& body) { f32 worldAngle[3]; body.GetWorldAngle(worldAngle[0], worldAngle[1], worldAngle[2]); worldAngle[1] += 1.0f; if ( worldAngle[1] > 360.0f ) { worldAngle[1] = 0.0f; } body.SetWorldAngle(worldAngle[0], worldAngle[1], worldAngle[2]); } 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(); // Creates and saves the command list. MakeDisplay0CommandCache(); DrawDisplay1(); s_InitializeCommandCache = true; } else { UpdateCamera(); // Reuses the saved command list. DrawDisplay0CommandCache(); DrawDisplay1(); } s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH); return true; } void MakeDisplay0CommandCache(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); // Starts saving the command list. nngxStartCmdlistSave(); UseShader(); glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION], 1, GL_TRUE, static_cast(s_Display0ProjectionMatrix)); UpdateBody(s_Cube); DrawBody(s_Cube); // Finishes saving the command list and copies it. CopyCommandList(); s_RenderSystem.SwapBuffers(); } void DrawDisplay0CommandCache(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); // Adds the saved command list to the current command list. nngxUseSavedCmdlist(s_SavedCommandListId, s_SavedCommandBufferOffset, s_SavedCommandBufferSize, s_SavedCommandRequestBeginId, s_SavedCommandRequestSize, s_StateMask, s_CopyCommandBuffer); s_RenderSystem.SwapBuffers(); } void CopyCommandList(void) { if (! s_CopyCommandBuffer ) { nngxSplitDrawCmdlist(); } // Ends saving the command list. nngxStopCmdlistSave(&s_SavedCommandBufferOffset, &s_SavedCommandBufferSize, &s_SavedCommandRequestBeginId, &s_SavedCommandRequestSize); NN_LOG("Saved CommandList information\n"); NN_LOG(" bufferOffset = %d, bufferSize = %d\n", s_SavedCommandBufferOffset, s_SavedCommandBufferSize); NN_LOG(" requestBeginId = %d, requestSize = %d\n", s_SavedCommandRequestBeginId, s_SavedCommandRequestSize); // Allocates command list at the save destination. nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, (GLint*)&s_CurrentCommandListId); NN_LOG("CurrentCommandListId = %d\n", s_CurrentCommandListId); nngxGenCmdlists(1, &s_SavedCommandListId); NN_LOG("SavedCommandListId = %d\n", s_SavedCommandListId); nngxBindCmdlist(s_SavedCommandListId); nngxCmdlistStorage(0x10000, 32); // Unbinds the current command list. nngxBindCmdlist(0); // Copies the current command list to the command list at the save destination. nngxCopyCmdlist(s_CurrentCommandListId, s_SavedCommandListId); // Bind the command list. nngxBindCmdlist(s_CurrentCommandListId); DEMO_ASSERT_GL_ERROR(); } 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 ) { #ifdef USE_COMMAND_CACHE flag = DrawFrameCommandCache(); #else flag = DrawFrame(); #endif } Finalize(); }