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