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