1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: demo_MemoryManager.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: 47694 $ 14 *---------------------------------------------------------------------------*/ 15 16 #include "demo/Utility/demo_MemoryManager.h" 17 18 #define DEBUG_PRINT 0 19 20 namespace demo 21 { 22 namespace 23 { 24 const int ALIGNMENT_SYSTEM_BUFFER = 4; // Specify the maximum based on the rules 25 const int ALIGNMENT_VERTEX = 16; // Specify 16-byte aligned assuming the nngxAddBlockImageCopyCommand function 26 const int ALIGNMENT_TEXTURE = 128; 27 const int ALIGNMENT_RENDER_BUFFER = 64; // 24-bit format depth buffer (D24) must be aligned to 96 bytes 28 const int ALIGNMENT_DISPLAY_BUFFER = 16; 29 const int ALIGNMENT_3D_COMMAND_BUFFER = 16; 30 MathRoundup(uptr x,int base)31 inline uptr MathRoundup(uptr x, int base) 32 { 33 return ((x) + ((base)-1)) & ~((base)-1); 34 } 35 } 36 37 namespace detail 38 { MemoryManager()39 MemoryManager::MemoryManager() : 40 m_Initialized(false), 41 m_pStartAddrFcram(NULL), 42 m_CurrentAddrVramA(NULL), 43 m_CurrentAddrVramB(NULL), 44 m_HeapOnFcram(), 45 m_AllocatedBlockSize(0) 46 { 47 } 48 ~MemoryManager()49 MemoryManager::~MemoryManager() 50 { 51 Finalize(); 52 } 53 Initialize(const uptr fcramAddress,const size_t memorySize)54 void MemoryManager::Initialize(const uptr fcramAddress, const size_t memorySize) 55 { 56 if (m_Initialized) 57 { 58 return; 59 } 60 61 m_pStartAddrFcram = fcramAddress; 62 NN_TASSERT_(m_pStartAddrFcram != NULL); 63 64 m_AllocatedBlockSize = memorySize; 65 66 m_HeapOnFcram.Initialize(m_pStartAddrFcram, memorySize ); 67 68 m_CurrentAddrVramA = nn::gx::GetVramStartAddr(nn::gx::MEM_VRAMA); 69 m_CurrentAddrVramB = nn::gx::GetVramStartAddr(nn::gx::MEM_VRAMB); 70 71 #if DEBUG_PRINT 72 NN_TLOG_("[demo::MemoryManager] Start address on Main Memory (FCRAM): 0x%08X\n", m_pStartAddrFcram); 73 NN_TLOG_("[demo::MemoryManager] Start address on VRAM-A: 0x%08X\n", m_CurrentAddrVramA); 74 NN_TLOG_("[demo::MemoryManager] Start address on VRAM-B: 0x%08X\n", m_CurrentAddrVramB); 75 #endif 76 77 m_Initialized = true; 78 } 79 Finalize(void)80 void MemoryManager::Finalize(void) 81 { 82 m_HeapOnFcram.Finalize(); 83 84 m_Initialized = false; 85 } 86 PrintFreeMemorySize(void)87 void MemoryManager::PrintFreeMemorySize(void) 88 { 89 NN_TLOG_("[demo::MemoryManager] Free memory size on Main Memory (FCRAM) is 0x%06X(max 0x%06X)\n", 90 m_HeapOnFcram.GetTotalFreeSize(), m_AllocatedBlockSize); 91 NN_TLOG_("[demo::MemoryManager] Free memory size on VRAM-A is 0x%06X(max 0x%06X)\n", 92 nn::gx::GetVramEndAddr(nn::gx::MEM_VRAMA) - m_CurrentAddrVramA, nn::gx::GetVramSize(nn::gx::MEM_VRAMA)); 93 NN_TLOG_("[demo::MemoryManager] Free memory size on VRAM-B is 0x%06X(max 0x%06X)\n", 94 nn::gx::GetVramEndAddr(nn::gx::MEM_VRAMB) - m_CurrentAddrVramB, nn::gx::GetVramSize(nn::gx::MEM_VRAMB)); 95 } 96 Allocate(GLenum area,GLenum aim,GLuint id,GLsizei size)97 void* MemoryManager::Allocate(GLenum area, GLenum aim, GLuint id, GLsizei size) 98 { 99 if (!m_Initialized) 100 { 101 NN_TPANIC_("Not initialized.\n"); 102 } 103 104 if (size == 0) 105 return 0; 106 107 // When allocating to VRAM, the VRAM can be treated as a stack due to its simplicity 108 // In addition, do not respond to fragmentation 109 // To deal with fragmentation, you need to retain information on memory allocated as `area`, `aim` and `id` when allocation is successful for subsequent deallocation. 110 // 111 112 int addrAlign = 8; 113 void* resultAddr = NULL; 114 115 // Take into account the alignment restrictions on each data set's position 116 switch (aim) 117 { 118 case NN_GX_MEM_SYSTEM: 119 addrAlign = ALIGNMENT_SYSTEM_BUFFER; 120 break; 121 case NN_GX_MEM_TEXTURE: 122 addrAlign = ALIGNMENT_TEXTURE; 123 break; 124 case NN_GX_MEM_VERTEXBUFFER: 125 addrAlign = ALIGNMENT_VERTEX; 126 break; 127 case NN_GX_MEM_RENDERBUFFER: 128 addrAlign = ALIGNMENT_RENDER_BUFFER; 129 break; 130 case NN_GX_MEM_DISPLAYBUFFER: 131 addrAlign = ALIGNMENT_DISPLAY_BUFFER; 132 break; 133 case NN_GX_MEM_COMMANDBUFFER: 134 addrAlign = ALIGNMENT_3D_COMMAND_BUFFER; 135 break; 136 default: 137 NN_TPANIC_("Invalid parameter.(0x%X)\n", aim); 138 break; 139 } 140 141 switch (area) 142 { 143 case NN_GX_MEM_FCRAM: 144 // When using FCRAM, no need to manage this because it is allocated from the expanded heap that is supported by the SDK 145 if ( (resultAddr = m_HeapOnFcram.Allocate(size, addrAlign)) == NULL) 146 { 147 NN_TPANIC_("Lack of resource on Main Memory (FCRAM).\n"); 148 } 149 break; 150 case NN_GX_MEM_VRAMA: 151 { 152 if (MathRoundup(m_CurrentAddrVramA, addrAlign) + size > nn::gx::GetVramEndAddr(nn::gx::MEM_VRAMA)) 153 { 154 NN_TPANIC_("Lack of resource on VRAM-A.\n"); 155 } 156 157 m_CurrentAddrVramA = MathRoundup(m_CurrentAddrVramA, addrAlign); 158 resultAddr = reinterpret_cast<void*>(m_CurrentAddrVramA); 159 m_CurrentAddrVramA += size; 160 } 161 break; 162 case NN_GX_MEM_VRAMB: 163 { 164 if (MathRoundup(m_CurrentAddrVramB, addrAlign) + size > nn::gx::GetVramEndAddr(nn::gx::MEM_VRAMB)) 165 { 166 NN_TPANIC_("Lack of resource on VRAM-B.\n"); 167 } 168 169 m_CurrentAddrVramB = MathRoundup(m_CurrentAddrVramB, addrAlign); 170 resultAddr = reinterpret_cast<void*>(m_CurrentAddrVramB); 171 m_CurrentAddrVramB += size; 172 } 173 break; 174 default: 175 // This is not likely in normal use; PANIC 176 NN_TPANIC_("Invalid parameter. (0x%X)\n", area); 177 break; 178 } 179 180 #if DEBUG_PRINT 181 if (aim == NN_GX_MEM_SYSTEM) 182 { 183 NN_TLOG_("[demo::MemoryManager] NN_GX_MEM_SYSTEM is allocated at 0x%08X - 0x%08X on %X\n", 184 resultAddr, 185 reinterpret_cast<int>(resultAddr) + size - 1, area); 186 } 187 else if (aim == NN_GX_MEM_TEXTURE) 188 { 189 NN_TLOG_("[demo::MemoryManager] NN_GX_MEM_TEXTURE is allocated at 0x%08X - 0x%08X on %X\n", 190 resultAddr, 191 reinterpret_cast<int>(resultAddr) + size - 1, area); 192 } 193 else if (aim == NN_GX_MEM_VERTEXBUFFER) 194 { 195 NN_TLOG_("[demo::MemoryManager] NN_GX_MEM_VERTEXBUFFER is allocated at 0x%08X - 0x%08X on %X\n", 196 resultAddr, 197 reinterpret_cast<int>(resultAddr) + size - 1, area); 198 } 199 else if (aim == NN_GX_MEM_DISPLAYBUFFER) 200 { 201 NN_TLOG_("[demo::MemoryManager] NN_GX_MEM_DISPLAYBUFFER is allocated at 0x%08X - 0x%08X on %X\n", 202 resultAddr, 203 reinterpret_cast<int>(resultAddr) + size - 1, area); 204 } 205 else if (aim == NN_GX_MEM_RENDERBUFFER) 206 { 207 NN_TLOG_("[demo::MemoryManager] NN_GX_MEM_RENDERBUFFER is allocated at 0x%08X - 0x%08X on %X\n", 208 resultAddr, 209 reinterpret_cast<int>(resultAddr) + size - 1, area); 210 } 211 else if (aim == NN_GX_MEM_COMMANDBUFFER) 212 { 213 NN_TLOG_("[demo::MemoryManager] NN_GX_MEM_COMMANDBUFFER is allocated at 0x%08X - 0x%08X on %X\n", 214 resultAddr, 215 reinterpret_cast<int>(resultAddr) + size - 1, area); 216 } 217 #else 218 NN_UNUSED_VAR(id); 219 #endif // #if DEBUG_PRINT 220 221 return resultAddr; 222 } 223 224 /* Memory deallocator for DMPGL */ Deallocate(GLenum area,GLenum aim,GLuint id,void * addr)225 void MemoryManager::Deallocate(GLenum area, GLenum aim, GLuint id, void* addr) 226 { 227 NN_UNUSED_VAR(aim); 228 NN_UNUSED_VAR(id); 229 230 if (! m_Initialized) 231 { 232 NN_TPANIC_("Not initialized.\n"); 233 } 234 235 #if DEBUG_PRINT 236 NN_TLOG_("[demo::MemoryManager] (id %d) was deallocated at 0x%08X on %X\n", id, addr, area); 237 #endif 238 239 switch (area) 240 { 241 case NN_GX_MEM_FCRAM: 242 m_HeapOnFcram.Free(addr); 243 break; 244 245 case NN_GX_MEM_VRAMA: 246 case NN_GX_MEM_VRAMB: 247 // Because the buffer in VRAM is simple, do not deallocate 248 break; 249 250 default: 251 NN_TPANIC_("Invalid parameter.\n"); 252 break; 253 } 254 } 255 } 256 257 namespace 258 { 259 demo::detail::MemoryManager s_MemoryManager; 260 } 261 InitializeMemoryManager(const uptr fcramAddress,const size_t memorySize)262 NN_WEAK_SYMBOL void InitializeMemoryManager(const uptr fcramAddress, const size_t memorySize) 263 { 264 s_MemoryManager.Initialize(fcramAddress, memorySize); 265 } 266 FinalizeMemoryManager(void)267 NN_WEAK_SYMBOL void FinalizeMemoryManager(void) 268 { 269 s_MemoryManager.Finalize(); 270 } 271 PrintMemoryManagerInfo(void)272 NN_WEAK_SYMBOL void PrintMemoryManagerInfo(void) 273 { 274 s_MemoryManager.PrintFreeMemorySize(); 275 } 276 GetAllocator(GLenum area,GLenum aim,GLuint id,GLsizei size)277 NN_WEAK_SYMBOL void* GetAllocator(GLenum area, GLenum aim, GLuint id, GLsizei size) 278 { 279 return s_MemoryManager.Allocate(area, aim, id, size); 280 } 281 GetDeallocator(GLenum area,GLenum aim,GLuint id,void * addr)282 NN_WEAK_SYMBOL void GetDeallocator(GLenum area, GLenum aim, GLuint id, void* addr) 283 { 284 s_MemoryManager.Deallocate(area, aim, id, addr); 285 } 286 Alloc(size_t size)287 NN_WEAK_SYMBOL void* Alloc(size_t size) 288 { 289 return s_MemoryManager.Allocate(NN_GX_MEM_FCRAM, NN_GX_MEM_SYSTEM, 0, size); 290 } 291 Free(void * ptr)292 NN_WEAK_SYMBOL void Free(void* ptr) 293 { 294 s_MemoryManager.Deallocate(NN_GX_MEM_FCRAM, NN_GX_MEM_SYSTEM, 0, ptr); 295 } 296 297 } 298