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