z_memman_console.cpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883
  1. /*
  2. * UNPUBLISHED -- Rights reserved under the copyright laws of the
  3. * United States. Use of a copyright notice is precautionary only and
  4. * does not imply publication or disclosure.
  5. *
  6. * THIS DOCUMENTATION CONTAINS CONFIDENTIAL AND PROPRIETARY INFORMATION
  7. * OF VICARIOUS VISIONS, INC. ANY DUPLICATION, MODIFICATION,
  8. * DISTRIBUTION, OR DISCLOSURE IS STRICTLY PROHIBITED WITHOUT THE PRIOR
  9. * EXPRESS WRITTEN PERMISSION OF VICARIOUS VISIONS, INC.
  10. */
  11. /*
  12. * ZONE MEMORY MANAGER
  13. *
  14. * Goals:
  15. * 1. Minimize overhead
  16. * 2. Minimize fragmentation
  17. *
  18. * Constraints:
  19. * 1. Maximum allocated block size is 32MB
  20. * 2. Maximum 64 different memory tags supported
  21. * 3. Maximum 256 byte alignment
  22. *
  23. * All memory required by the manager is allocated at startup in
  24. * the form of one large pool.
  25. *
  26. * Allocated blocks require a 4 byte header to store size, tag, and
  27. * alignment information. Blocks that need to support the Z_TagFree()
  28. * feature require an additional 8 byte link list structure.
  29. *
  30. * Free blocks require a 16 bytes of tracking information. If possible
  31. * this information is stored directly in the block (which is in the
  32. * pool.) If the free block is not large enough, its information is
  33. * stored in an overflow buffer.
  34. *
  35. * In an effort to reduce fragmentation, blocks allocated for a short
  36. * period of time at the end of the pool. All other blocks are allocated
  37. * at the start. Allocation is first fit.
  38. *
  39. */
  40. #include "../game/q_shared.h"
  41. #include "qcommon.h"
  42. #include "../renderer/qgl_console.h"
  43. #ifdef _GAMECUBE
  44. #include <dolphin/os.h>
  45. #endif
  46. #ifdef _WINDOWS
  47. #include <windows.h>
  48. #endif
  49. #ifdef _XBOX
  50. #include <Xtl.h>
  51. #include "../win32/xbox_texture_man.h"
  52. #endif
  53. // Used to mark the start and end of blocks in debug mode
  54. #define ZONE_MAGIC 0xfe
  55. // Size of the free block overflow buffer
  56. #define ZONE_FREE_OVERFLOW 4096
  57. // Indicates whether or not special (slow) debug code should be enabled
  58. #define ZONE_DEBUG 0
  59. // Allocate all available memory minus this amount - texture pools are
  60. // allocated before this, so just leave enough for framebuffer, etc...
  61. // Gah! I hate Bink! Stupid thing allocates physical memory (probably via
  62. // DSound) when starting. Need to leave just a little more.
  63. #ifdef FINAL_BUILD
  64. # define ZONE_HEAP_FREE (1024*1024*6 + 512*1024 + 256*1024 + 64*1024)
  65. #else
  66. # define ZONE_HEAP_FREE (1024*1024*16 + 16*1024*1024)
  67. #endif
  68. #ifdef FINAL_BUILD
  69. #define TEXTURE_POOL_SIZE 16*1024*1024
  70. #else
  71. #define TEXTURE_POOL_SIZE 20*1024*1024
  72. #endif
  73. // Two systems (Bink, and Savegames) need large, contiguous allocations once things
  74. // are running and fragmented. They get their own sandbox:
  75. #define TEMP_ALLOC_POOL_SIZE (2*1024*1024 + 512*1024)
  76. __declspec (align(32)) char s_TempAllocPool[TEMP_ALLOC_POOL_SIZE];
  77. int s_TempAllocPoint = 0;
  78. void *TempAlloc( unsigned long size )
  79. {
  80. if( s_TempAllocPoint + size > TEMP_ALLOC_POOL_SIZE )
  81. {
  82. Com_Printf( "WARNING: TempAlloc pool full!\n" );
  83. return NULL;
  84. }
  85. void *retVal = &s_TempAllocPool[s_TempAllocPoint];
  86. s_TempAllocPoint = (s_TempAllocPoint + size + 31) & ~31;
  87. return retVal;
  88. }
  89. void TempFree( void )
  90. {
  91. s_TempAllocPoint = 0;
  92. }
  93. // Should we emulate the smaller memory footprint of actual release systems?
  94. #define ZONE_EMULATE_SPACE 0
  95. // All standard header data is crammed into 4 bytes
  96. typedef unsigned int ZoneHeader;
  97. // Debug markers to check for overflow/underflow
  98. typedef unsigned int ZoneDebugHeader;
  99. typedef unsigned char ZoneDebugFooter;
  100. // Extended header information for memory freed with TagFree()
  101. struct ZoneLinkHeader
  102. {
  103. ZoneLinkHeader* m_Next;
  104. ZoneLinkHeader* m_Prev;
  105. };
  106. static ZoneLinkHeader* s_LinkBase;
  107. // Free memory block tracking information
  108. struct ZoneFreeBlock
  109. {
  110. unsigned int m_Address;
  111. unsigned int m_Size;
  112. ZoneFreeBlock* m_Next;
  113. ZoneFreeBlock* m_Prev;
  114. };
  115. // Buffer to hold free memory information that we can't
  116. // fit directly in the pool
  117. static ZoneFreeBlock s_FreeOverflow[ZONE_FREE_OVERFLOW];
  118. static int s_LastOverflowIndex;
  119. static ZoneFreeBlock s_FreeStart;
  120. static ZoneFreeBlock s_FreeEnd;
  121. // Various stats collected at runtime
  122. struct ZoneStats
  123. {
  124. int m_CountAlloc;
  125. int m_SizeAlloc;
  126. int m_OverheadAlloc;
  127. int m_PeakAlloc;
  128. int m_CountFree;
  129. int m_SizeFree;
  130. int m_SizesPerTag[TAG_COUNT];
  131. int m_CountsPerTag[TAG_COUNT];
  132. };
  133. static ZoneStats s_Stats;
  134. // Special empty block for zero size allocations
  135. struct ZoneEmptyBlock
  136. {
  137. ZoneHeader header;
  138. #ifdef _DEBUG
  139. ZoneDebugHeader start;
  140. ZoneDebugFooter end;
  141. #endif
  142. };
  143. #ifdef _DEBUG
  144. static ZoneEmptyBlock s_EmptyBlock = {TAG_STATIC << 25, ZONE_MAGIC, ZONE_MAGIC};
  145. #else
  146. static ZoneEmptyBlock s_EmptyBlock = {TAG_STATIC << 25};
  147. #endif
  148. // Free block jump table for fast memory deallocation
  149. #define Z_JUMP_TABLE_SIZE 64
  150. static ZoneFreeBlock* s_FreeJumpTable[Z_JUMP_TABLE_SIZE];
  151. static unsigned int s_FreeJumpResolution;
  152. static void* s_PoolBase;
  153. static int s_PoolSize;
  154. static bool s_Initialized = false;
  155. static memtag_t s_newDeleteTagStack[32] = { TAG_NEWDEL };
  156. static int s_newDeleteTagStackTop = 0;
  157. #ifndef _GAMECUBE
  158. static HANDLE s_Mutex = INVALID_HANDLE_VALUE;
  159. #endif
  160. static void Z_Stats_f(void);
  161. void Z_Details_f(void);
  162. void Z_DumpMemMap_f(void);
  163. void Z_CompactStats(void);
  164. void Z_PushNewDeleteTag( memtag_t eTag )
  165. {
  166. assert( s_newDeleteTagStackTop < 31 );
  167. s_newDeleteTagStack[++s_newDeleteTagStackTop] = eTag;
  168. }
  169. void Z_PopNewDeleteTag( void )
  170. {
  171. assert( s_newDeleteTagStackTop );
  172. --s_newDeleteTagStackTop;
  173. }
  174. #ifdef _XBOX
  175. void ShowOSMemory(void)
  176. {
  177. MEMORYSTATUS stat;
  178. GlobalMemoryStatus(&stat);
  179. Com_Printf(" total mem: %d, free mem: %d\n", stat.dwTotalPhys / 1024,
  180. stat.dwAvailPhys / 1024);
  181. FILE *out = fopen("d:\\osmem.txt", "a");
  182. if(out) {
  183. fprintf(out, "total mem: %d, free mem: %d\n", stat.dwTotalPhys / 1024,
  184. stat.dwAvailPhys / 1024);
  185. fclose(out);
  186. }
  187. }
  188. #endif
  189. int Z_MemFree(void)
  190. {
  191. return s_Stats.m_SizeFree;
  192. }
  193. void Com_InitZoneMemory(void)
  194. {
  195. // assert(!s_Initialized);
  196. // Zone now initializes on first use, can't reliably assume anything here
  197. if (s_Initialized)
  198. return;
  199. Com_Printf("Initialising zone memory .....\n");
  200. // Clear some globals
  201. memset(&s_Stats, 0, sizeof(s_Stats));
  202. memset(s_FreeOverflow, 0, sizeof(s_FreeOverflow));
  203. s_LastOverflowIndex = 0;
  204. s_LinkBase = NULL;
  205. // Alloc the pool
  206. MEMORYSTATUS status;
  207. GlobalMemoryStatus(&status);
  208. // BTO : VVFIXME - Extra little note to see how much memory
  209. // is being used by globals/statics
  210. Com_Printf("*** PhysRAM: %d used, %d free\n",
  211. status.dwTotalPhys-status.dwAvailPhys,
  212. status.dwAvailPhys);
  213. // Allocate the texture pool:
  214. gTextures.Initialize( TEXTURE_POOL_SIZE );
  215. GlobalMemoryStatus(&status);
  216. // BTO : VVFIXME - Extra little note to see how much memory
  217. // is being used by globals/statics
  218. Com_Printf("*** PhysRAM: %d used, %d free\n",
  219. status.dwTotalPhys-status.dwAvailPhys,
  220. status.dwAvailPhys);
  221. SIZE_T size;
  222. # if ZONE_EMULATE_SPACE
  223. #ifdef _DEBUG
  224. //Emulated space is always about 6 megs off from release build. Try
  225. //to compensate. This number may need tweaking in the future.
  226. SIZE_T exe = 6500 * 1024;
  227. #else
  228. SIZE_T exe = 0; //Exe size is already reflected in GlobalMemoryStatus().
  229. #endif
  230. size = 0x4000000 - (exe + ZONE_HEAP_FREE);
  231. # else
  232. size = status.dwAvailPhys - ZONE_HEAP_FREE;
  233. # endif
  234. s_PoolBase = GlobalAlloc(0, size);
  235. s_PoolSize = size;
  236. // Setup the initial free block
  237. ZoneFreeBlock* base = (ZoneFreeBlock*)s_PoolBase;
  238. base->m_Address = (unsigned int)s_PoolBase;
  239. base->m_Size = size;
  240. base->m_Next = &s_FreeEnd;
  241. base->m_Prev = &s_FreeStart;
  242. // Init the free block jump table
  243. memset(s_FreeJumpTable, 0, Z_JUMP_TABLE_SIZE * sizeof(ZoneFreeBlock*));
  244. s_FreeJumpResolution = (size / Z_JUMP_TABLE_SIZE) + 1;
  245. s_FreeJumpTable[0] = base;
  246. // Setup free block dummies
  247. s_FreeStart.m_Address = 0;
  248. s_FreeStart.m_Size = 0;
  249. s_FreeStart.m_Next = base;
  250. s_FreeStart.m_Prev = NULL;
  251. s_FreeEnd.m_Address = 0xFFFFFFFF;
  252. s_FreeEnd.m_Size = 0;
  253. s_FreeEnd.m_Next = NULL;
  254. s_FreeEnd.m_Prev = base;
  255. s_Stats.m_CountFree = 1;
  256. s_Stats.m_SizeFree = size;
  257. s_Initialized = true;
  258. // Add some commands
  259. Cmd_AddCommand("zone_stats", Z_Stats_f);
  260. Cmd_AddCommand("zone_details", Z_Details_f);
  261. Cmd_AddCommand("zone_memmap", Z_DumpMemMap_f);
  262. Cmd_AddCommand("zone_cstats", Z_CompactStats);
  263. #ifndef _GAMECUBE
  264. s_Mutex = CreateMutex(NULL, FALSE, NULL);
  265. #endif
  266. // Super-size my hack. With fries. We allocate enough space for g_entities at the
  267. // end of the zone now. If it turns out (somehow) that there is no persisted surface,
  268. // then we need to take g_entities from the zone, but we'd normally allocate it so late
  269. // that we'll have a big chunk in the middle. That's bad. And if we reserve space at the
  270. // front, then we might not need it, and we've got a 1.2MB chunk of empty space there.
  271. // This works perfectly, though:
  272. extern void G_ReserveZoneGentities( void );
  273. G_ReserveZoneGentities();
  274. }
  275. void Com_ShutdownZoneMemory(void)
  276. {
  277. assert(s_Initialized);
  278. // Remove commands
  279. Cmd_RemoveCommand("zone_stats");
  280. Cmd_RemoveCommand("zone_details");
  281. Cmd_RemoveCommand("zone_memmap");
  282. if (s_Stats.m_CountAlloc)
  283. {
  284. // Free all memory
  285. // CM_ReleaseVisData();
  286. Z_TagFree(TAG_ALL);
  287. }
  288. // Clear some globals
  289. memset(&s_Stats, 0, sizeof(s_Stats));
  290. memset(s_FreeOverflow, 0, sizeof(s_FreeOverflow));
  291. s_LastOverflowIndex = 0;
  292. s_LinkBase = NULL;
  293. // Free the pool
  294. #ifndef _GAMECUBE
  295. GlobalFree(s_PoolBase);
  296. CloseHandle(s_Mutex);
  297. #endif
  298. s_PoolBase = NULL;
  299. s_Initialized = false;
  300. }
  301. // Determine if a tag should only be allocated for a very
  302. // short period of time.
  303. static bool Z_IsTagTemp(memtag_t eTag)
  304. {
  305. return
  306. eTag == TAG_TEMP_WORKSPACE ||
  307. eTag == TAG_SND_RAWDATA ||
  308. eTag == TAG_ICARUS ||
  309. eTag == TAG_LISTFILES ||
  310. eTag == TAG_GP2;
  311. }
  312. // Determine if a tag needs TagFree() support.
  313. static bool Z_IsTagLinked(memtag_t eTag)
  314. {
  315. return
  316. eTag == TAG_BSP ||
  317. eTag == TAG_HUNKALLOC ||
  318. // eTag == TAG_HUNKMISCMODELS ||
  319. eTag == TAG_G_ALLOC ||
  320. eTag == TAG_UI_ALLOC;
  321. }
  322. static int Z_CalcAlignmentPad(int iAlign, unsigned int iAddress, unsigned int iOffset,
  323. unsigned int iSize, unsigned int iHeaderSize, unsigned int iFooterSize)
  324. {
  325. int align_size;
  326. if (iAlign == 0) return 0;
  327. if (iOffset == 0)
  328. {
  329. // Align data at low end of block
  330. align_size = iAlign -
  331. ((iAddress + iHeaderSize) % iAlign);
  332. }
  333. else
  334. {
  335. // Align data at high end of block
  336. unsigned int block_start = iAddress + iOffset -
  337. iSize + iHeaderSize;
  338. align_size = block_start % iAlign;
  339. }
  340. if (align_size == iAlign)
  341. {
  342. return 0;
  343. }
  344. return align_size;
  345. }
  346. static ZoneFreeBlock* Z_GetOverflowBlock(void)
  347. {
  348. for (int i = s_LastOverflowIndex; i < ZONE_FREE_OVERFLOW; ++i)
  349. {
  350. if (s_FreeOverflow[i].m_Address == 0)
  351. {
  352. s_LastOverflowIndex = i;
  353. return &s_FreeOverflow[i];
  354. }
  355. }
  356. for (int j = 0; j < s_LastOverflowIndex; ++j)
  357. {
  358. if (s_FreeOverflow[j].m_Address == 0)
  359. {
  360. s_LastOverflowIndex = j;
  361. return &s_FreeOverflow[j];
  362. }
  363. }
  364. return NULL;
  365. }
  366. static inline bool Z_IsFreeBlockLargeEnough(ZoneFreeBlock* pBlock, int iSize,
  367. int iHeaderSize, int iFooterSize, int iAlign, bool bLow, int& iAlignPad)
  368. {
  369. // Is the block large enough?
  370. if (pBlock->m_Size >= iSize)
  371. {
  372. if (iAlign > 0)
  373. {
  374. // If we need some aligment, we need to check size
  375. // against that as well.
  376. iAlignPad = Z_CalcAlignmentPad(iAlign,
  377. pBlock->m_Address, !bLow ? pBlock->m_Size : 0,
  378. iSize, iHeaderSize, iFooterSize);
  379. if (pBlock->m_Size < iAlignPad + iSize)
  380. {
  381. return false;
  382. }
  383. }
  384. return true;
  385. }
  386. return false;
  387. }
  388. static ZoneFreeBlock* Z_FindFirstFree(int iSize, int iHeaderSize,
  389. int iFooterSize, int iAlign, int& iAlignPad)
  390. {
  391. for (ZoneFreeBlock* block = s_FreeStart.m_Next; block; block = block->m_Next)
  392. {
  393. if (Z_IsFreeBlockLargeEnough(block, iSize, iHeaderSize, iFooterSize,
  394. iAlign, true, iAlignPad))
  395. {
  396. return block;
  397. }
  398. }
  399. return NULL;
  400. }
  401. static ZoneFreeBlock* Z_FindLastFree(int iSize, int iHeaderSize,
  402. int iFooterSize, int iAlign, int& iAlignPad)
  403. {
  404. for (ZoneFreeBlock* block = s_FreeEnd.m_Prev; block; block = block->m_Prev)
  405. {
  406. if (Z_IsFreeBlockLargeEnough(block, iSize, iHeaderSize, iFooterSize,
  407. iAlign, false, iAlignPad))
  408. {
  409. return block;
  410. }
  411. }
  412. return NULL;
  413. }
  414. static bool Z_ValidateFree(void)
  415. {
  416. #if ZONE_DEBUG
  417. // Make sure no free blocks are overlapping
  418. for (ZoneFreeBlock* a = &s_FreeStart; a; a = a->m_Next)
  419. {
  420. if (a->m_Address == 0 && a->m_Size != 0)
  421. {
  422. return false;
  423. }
  424. for (ZoneFreeBlock* b = &s_FreeStart; b; b = b->m_Next)
  425. {
  426. if (a != b &&
  427. a->m_Address >= b->m_Address &&
  428. a->m_Address < b->m_Address + b->m_Size)
  429. {
  430. return false;
  431. }
  432. }
  433. }
  434. #endif
  435. return true;
  436. }
  437. static bool Z_ValidateLinks(void)
  438. {
  439. #if ZONE_DEBUG
  440. // Make sure links are sane
  441. for (ZoneLinkHeader* a = s_LinkBase; a; a = a->m_Next)
  442. {
  443. if ((a->m_Next && a != a->m_Next->m_Prev) ||
  444. (a->m_Prev && a != a->m_Prev->m_Next))
  445. {
  446. return false;
  447. }
  448. }
  449. #endif
  450. return true;
  451. }
  452. static int Z_GetJumpTableIndex(unsigned int iAddress)
  453. {
  454. int index = (iAddress - (unsigned int)s_PoolBase) / s_FreeJumpResolution;
  455. if (index < 0) return 0;
  456. if (index >= Z_JUMP_TABLE_SIZE) return Z_JUMP_TABLE_SIZE - 1;
  457. return index;
  458. }
  459. static ZoneFreeBlock* Z_GetFreeBlockBefore(unsigned int iAddress)
  460. {
  461. // Find this block's position in the jump table
  462. int index = Z_GetJumpTableIndex(iAddress) - 1;
  463. // Find a valid jump table entry
  464. while (index >= 0 && !s_FreeJumpTable[index]) --index;
  465. if (index < 0) return &s_FreeStart;
  466. return s_FreeJumpTable[index];
  467. }
  468. static void Z_RemoveFromJumpTable(ZoneFreeBlock* pBlock)
  469. {
  470. // Is this block in the jump table?
  471. int index = Z_GetJumpTableIndex(pBlock->m_Address);
  472. if (s_FreeJumpTable[index] == pBlock)
  473. {
  474. // See if the next block will fit in our slot
  475. if (pBlock->m_Next != &s_FreeEnd)
  476. {
  477. int nindex = Z_GetJumpTableIndex(pBlock->m_Next->m_Address);
  478. if (nindex == index)
  479. {
  480. s_FreeJumpTable[index] = pBlock->m_Next;
  481. return;
  482. }
  483. }
  484. // See if the previous block will fit in our slot
  485. if (pBlock->m_Prev != &s_FreeStart)
  486. {
  487. int pindex = Z_GetJumpTableIndex(pBlock->m_Prev->m_Address);
  488. if (pindex == index)
  489. {
  490. s_FreeJumpTable[index] = pBlock->m_Prev;
  491. return;
  492. }
  493. }
  494. // No other free blocks fit here, give up
  495. s_FreeJumpTable[index] = NULL;
  496. }
  497. }
  498. static void Z_LinkFreeBlock(ZoneFreeBlock* pBlock)
  499. {
  500. ZoneFreeBlock* cur = Z_GetFreeBlockBefore(pBlock->m_Address);
  501. for (; cur; cur = cur->m_Next)
  502. {
  503. // Find the correct position, ordered by address
  504. if (cur->m_Address > pBlock->m_Address)
  505. {
  506. // Link up the block
  507. pBlock->m_Next = cur;
  508. pBlock->m_Prev = cur->m_Prev;
  509. cur->m_Prev->m_Next = pBlock;
  510. cur->m_Prev = pBlock;
  511. // Update the jump table if necessary
  512. int index = Z_GetJumpTableIndex(pBlock->m_Address);
  513. if (!s_FreeJumpTable[index])
  514. {
  515. s_FreeJumpTable[index] = pBlock;
  516. }
  517. s_Stats.m_CountFree++;
  518. s_Stats.m_SizeFree += pBlock->m_Size;
  519. assert(Z_ValidateFree());
  520. break;
  521. }
  522. }
  523. }
  524. static void* Z_SplitFree(ZoneFreeBlock* pBlock, int iSize, bool bLow)
  525. {
  526. assert(pBlock->m_Size >= iSize);
  527. Z_RemoveFromJumpTable(pBlock);
  528. // Delink the free block
  529. ZoneFreeBlock fblock = *pBlock;
  530. pBlock->m_Prev->m_Next = pBlock->m_Next;
  531. pBlock->m_Next->m_Prev = pBlock->m_Prev;
  532. pBlock->m_Address = 0;
  533. s_Stats.m_CountFree--;
  534. s_Stats.m_SizeFree -= pBlock->m_Size;
  535. assert(Z_ValidateFree());
  536. if (fblock.m_Size > iSize)
  537. {
  538. // Split the block into an allocated and free portion
  539. int remainder = fblock.m_Size - iSize;
  540. if (remainder < sizeof(ZoneFreeBlock))
  541. {
  542. // Free portion is not large to hold free info --
  543. // we're going to have to use the overflow buffer.
  544. ZoneFreeBlock* nblock = Z_GetOverflowBlock();
  545. if (nblock == NULL)
  546. {
  547. Z_Details_f();
  548. Com_Error(ERR_FATAL, "Zone free overflow buffer overflowed!");
  549. }
  550. // Split the block
  551. void* ret;
  552. if (bLow)
  553. {
  554. ret = (void*)fblock.m_Address;
  555. nblock->m_Address = fblock.m_Address + iSize;
  556. }
  557. else
  558. {
  559. ret = (void*)(fblock.m_Address + remainder);
  560. nblock->m_Address = fblock.m_Address;
  561. }
  562. nblock->m_Size = remainder;
  563. Z_LinkFreeBlock(nblock);
  564. return ret;
  565. }
  566. else
  567. {
  568. // Free portion is large enough -- split it
  569. void* ret;
  570. ZoneFreeBlock* nblock;
  571. if (bLow)
  572. {
  573. ret = (void*)fblock.m_Address;
  574. nblock = (ZoneFreeBlock*)(fblock.m_Address + iSize);
  575. }
  576. else
  577. {
  578. ret = (void*)(fblock.m_Address + remainder);
  579. nblock = (ZoneFreeBlock*)fblock.m_Address;
  580. }
  581. nblock->m_Address = (unsigned int)nblock;
  582. nblock->m_Size = remainder;
  583. Z_LinkFreeBlock(nblock);
  584. return ret;
  585. }
  586. }
  587. else
  588. {
  589. // No need to split, just return block.
  590. return (void*)fblock.m_Address;
  591. }
  592. }
  593. static void Z_SetupAlignmentPad(void* pBlock, int iAlignPad, bool bLow)
  594. {
  595. // Clear alignment bytes
  596. memset(pBlock, 0, iAlignPad);
  597. // If we have more than 1 alignment byte, the first align byte
  598. // tells us how many additional bytes we have.
  599. if (iAlignPad > 1)
  600. {
  601. assert(iAlignPad < 256);
  602. unsigned char* ptr;
  603. if (bLow)
  604. {
  605. ptr = (unsigned char*)pBlock + (iAlignPad - 1);
  606. }
  607. else
  608. {
  609. ptr = (unsigned char*)pBlock;
  610. }
  611. *ptr = iAlignPad - 1;
  612. }
  613. }
  614. void Z_MallocFail(const char* pMessage, int iSize, memtag_t eTag)
  615. {
  616. // Report the error
  617. // Com_Printf("Z_Malloc(): %s : %d bytes and tag %d !!!!\n", pMessage, iSize, eTag);
  618. Com_Printf("Z_Malloc(): %s : %d bytes and tag %d !!!!\n", pMessage, iSize, eTag);
  619. Z_Details_f();
  620. Z_DumpMemMap_f();
  621. // Com_Printf("(Repeat): Z_Malloc(): %s : %d bytes and tag %d !!!!\n", pMessage, iSize, eTag);
  622. Com_Printf("(Repeat): Z_Malloc(): %s : %d bytes and tag %d !!!!\n", pMessage, iSize, eTag);
  623. // Clear the screen blue to indicate out of memory
  624. for (;;)
  625. {
  626. qglBeginFrame();
  627. qglClearColor(0, 0, 1, 1);
  628. qglClear(GL_COLOR_BUFFER_BIT);
  629. qglEndFrame();
  630. }
  631. }
  632. void *Z_Malloc(int iSize, memtag_t eTag, qboolean bZeroit, int iAlign)
  633. {
  634. // assert(s_Initialized);
  635. // Zone now initializes on first use. (During static constructors)
  636. if (!s_Initialized)
  637. Com_InitZoneMemory();
  638. if (iSize == 0)
  639. {
  640. #ifdef _DEBUG
  641. return (void*)(&s_EmptyBlock.start + 1);
  642. #else
  643. return (void*)(&s_EmptyBlock.header + 1);
  644. #endif
  645. }
  646. if (iSize < 0)
  647. {
  648. Z_MallocFail("Negative size", iSize, eTag);
  649. return NULL;
  650. }
  651. #ifndef _GAMECUBE
  652. WaitForSingleObject(s_Mutex, INFINITE);
  653. #endif
  654. // Make new/delete memory temporary if requested
  655. if (eTag == TAG_NEWDEL )
  656. {
  657. eTag = s_newDeleteTagStack[s_newDeleteTagStackTop];
  658. }
  659. // Determine how much space we need with headers and footers
  660. int header_size = sizeof(ZoneHeader);
  661. int footer_size = 0;
  662. if (Z_IsTagLinked(eTag))
  663. {
  664. header_size += sizeof(ZoneLinkHeader);
  665. }
  666. #ifdef _DEBUG
  667. header_size += sizeof(ZoneDebugHeader);
  668. footer_size += sizeof(ZoneDebugFooter);
  669. #endif
  670. int real_size = iSize + header_size + footer_size;
  671. int align_pad = 0;
  672. // Get a bit of free memory. Temporary memory is allocated
  673. // from the end. More permanent allocations are done at the
  674. // begining of the pool.
  675. ZoneFreeBlock* fblock;
  676. if (Z_IsTagTemp(eTag))
  677. {
  678. fblock = Z_FindLastFree(real_size, header_size, footer_size,
  679. iAlign, align_pad);
  680. }
  681. else
  682. {
  683. fblock = Z_FindFirstFree(real_size, header_size, footer_size,
  684. iAlign, align_pad);
  685. }
  686. // Did we actually find some memory?
  687. if (!fblock)
  688. {
  689. #ifndef _GAMECUBE
  690. ReleaseMutex(s_Mutex);
  691. #endif
  692. // if(eTag == TAG_TEMP_SND_RAWDATA) {
  693. if(eTag == TAG_SND_RAWDATA) {
  694. return NULL;
  695. }
  696. Z_MallocFail("Out of memory", iSize, eTag);
  697. return NULL;
  698. }
  699. // Add any alignment bytes
  700. real_size += align_pad;
  701. // Split the free block and get a pointer to the start
  702. // allocated space.
  703. void* ablock;
  704. if (Z_IsTagTemp(eTag))
  705. {
  706. ablock = Z_SplitFree(fblock, real_size, false);
  707. // Append align pad to end of block
  708. Z_SetupAlignmentPad(
  709. (void*)((char*)ablock + real_size - align_pad),
  710. align_pad, false);
  711. }
  712. else
  713. {
  714. ablock = Z_SplitFree(fblock, real_size, true);
  715. // Insert align pad at block start
  716. Z_SetupAlignmentPad(ablock, align_pad, true);
  717. ablock = (void*)((char*)ablock + align_pad);
  718. }
  719. if (!ablock)
  720. {
  721. Z_MallocFail("Failed to split", iSize, eTag);
  722. }
  723. // Add linking header if necessary
  724. if (Z_IsTagLinked(eTag))
  725. {
  726. ZoneLinkHeader* linked = (ZoneLinkHeader*)ablock;
  727. linked->m_Next = s_LinkBase;
  728. linked->m_Prev = NULL;
  729. if (s_LinkBase)
  730. {
  731. s_LinkBase->m_Prev = linked;
  732. }
  733. s_LinkBase = linked;
  734. assert(Z_ValidateLinks());
  735. // Next...
  736. ablock = (void*)((char*)ablock + sizeof(ZoneLinkHeader));
  737. }
  738. // Setup the header:
  739. // 31 - alignment flag
  740. // 25-30 - tag
  741. // 0-24 - size without headers/footers
  742. assert(iSize >= 0 && iSize < (1 << 25));
  743. assert(eTag >= 0 && eTag < 64);
  744. ZoneHeader* header = (ZoneHeader*)ablock;
  745. *header =
  746. (((unsigned int)eTag) << 25) |
  747. ((unsigned int)iSize);
  748. if (align_pad)
  749. {
  750. *header |= (1 << 31);
  751. }
  752. // Next...
  753. ablock = (void*)((char*)ablock + sizeof(ZoneHeader));
  754. #ifdef _DEBUG
  755. {
  756. // Setup the debug markers
  757. ZoneDebugHeader* debug_header = (ZoneDebugHeader*)ablock;
  758. ZoneDebugFooter* debug_footer = (ZoneDebugFooter*)((char*)debug_header +
  759. (sizeof(ZoneDebugHeader) + iSize));
  760. *debug_header = ZONE_MAGIC;
  761. *debug_footer = ZONE_MAGIC;
  762. // Next...
  763. ablock = (void*)((char*)ablock + sizeof(ZoneDebugHeader));
  764. }
  765. #endif
  766. // Update the stats
  767. s_Stats.m_SizeAlloc += iSize;
  768. s_Stats.m_OverheadAlloc += header_size + footer_size + align_pad;
  769. s_Stats.m_SizesPerTag[eTag] += iSize;
  770. s_Stats.m_CountAlloc++;
  771. s_Stats.m_CountsPerTag[eTag]++;
  772. if (s_Stats.m_SizeAlloc + s_Stats.m_OverheadAlloc > s_Stats.m_PeakAlloc)
  773. {
  774. s_Stats.m_PeakAlloc = s_Stats.m_SizeAlloc + s_Stats.m_OverheadAlloc;
  775. }
  776. // Return a pointer to data memory
  777. if (bZeroit)
  778. {
  779. memset(ablock, 0, iSize);
  780. }
  781. assert(iAlign == 0 || (unsigned int)ablock % iAlign == 0);
  782. /*
  783. This is useful for figuring out who's allocating a certain block of
  784. memory. Please don't remove it.
  785. if(eTag == TAG_NEWDEL && (unsigned int)ablock >= 0x806c0000 &&
  786. (unsigned int)ablock <= 0x806c1000 && iSize == 24) {
  787. int suck = 0;
  788. }
  789. if(eTag == TAG_SMALL && (iSize == 7 || iSize == 96)) {
  790. int suck = 0;
  791. }
  792. if(eTag == TAG_CLIENTS) {
  793. int suck = 0;
  794. }
  795. if ((unsigned)ablock >= 0x169b000 && (unsigned)ablock <= 0x169c000 && iSize == 20)
  796. {
  797. int suck = 0;
  798. }
  799. */
  800. #ifndef _GAMECUBE
  801. ReleaseMutex(s_Mutex);
  802. #endif
  803. return ablock;
  804. }
  805. static memtag_t Z_GetTag(const ZoneHeader* header)
  806. {
  807. return (*header & 0x7E000000) >> 25;
  808. }
  809. static unsigned int Z_GetSize(const ZoneHeader* header)
  810. {
  811. return *header & 0x1FFFFFF;
  812. }
  813. static int Z_GetAlign(const ZoneHeader* header)
  814. {
  815. if (*header & (1 << 31))
  816. {
  817. unsigned char* ptr = (unsigned char*)header;
  818. memtag_t tag = Z_GetTag(header);
  819. // point to the first alignment block
  820. if (Z_IsTagTemp(tag))
  821. {
  822. ptr += sizeof(ZoneHeader) + Z_GetSize(header);
  823. #ifdef _DEBUG
  824. ptr += sizeof(ZoneDebugHeader) + sizeof(ZoneDebugFooter);
  825. #endif
  826. }
  827. else
  828. {
  829. if (Z_IsTagLinked(tag))
  830. {
  831. // skip the link header
  832. ptr -= sizeof(ZoneLinkHeader);
  833. }
  834. ptr -= 1;
  835. }
  836. return *ptr + 1;
  837. }
  838. return 0;
  839. }
  840. int Z_Size(void *pvAddress)
  841. {
  842. assert(s_Initialized);
  843. #ifdef _DEBUG
  844. ZoneDebugHeader* debug = (ZoneDebugHeader*)pvAddress - 1;
  845. if (*debug != ZONE_MAGIC)
  846. {
  847. Com_Error(ERR_FATAL, "Z_Size(): Not a valid zone header!");
  848. return 0; // won't get here
  849. }
  850. pvAddress = (void*)debug;
  851. #endif
  852. ZoneHeader* header = (ZoneHeader*)pvAddress - 1;
  853. if (Z_GetTag(header) == TAG_STATIC)
  854. {
  855. return 0; // kind of
  856. }
  857. return Z_GetSize(header);
  858. }
  859. static void Z_Coalasce(ZoneFreeBlock* pBlock)
  860. {
  861. unsigned int size = 0;
  862. // Find later free blocks adjacent to us
  863. ZoneFreeBlock* end;
  864. for (end = pBlock->m_Next;
  865. end->m_Next;
  866. end = end->m_Next)
  867. {
  868. if (end->m_Address !=
  869. end->m_Prev->m_Address + end->m_Prev->m_Size)
  870. {
  871. break;
  872. }
  873. size += end->m_Size;
  874. Z_RemoveFromJumpTable(end);
  875. end->m_Address = 0; // invalidate block
  876. s_Stats.m_CountFree--;
  877. }
  878. // Find previous free blocks adjacent to us
  879. ZoneFreeBlock* start;
  880. for (start = pBlock;
  881. start->m_Prev;
  882. start = start->m_Prev)
  883. {
  884. if (start->m_Prev->m_Address + start->m_Prev->m_Size !=
  885. start->m_Address)
  886. {
  887. break;
  888. }
  889. size += start->m_Size;
  890. Z_RemoveFromJumpTable(start);
  891. start->m_Address = 0; // invalidate block
  892. s_Stats.m_CountFree--;
  893. }
  894. // Do we need to coalesce some blocks?
  895. if (start->m_Next != end)
  896. {
  897. start->m_Next = end;
  898. end->m_Prev = start;
  899. start->m_Size += size;
  900. }
  901. }
  902. // Return type of Z_Free differs in SP/MP. Macro hack to wrap it up
  903. #ifdef _JK2MP
  904. void Z_Free(void *pvAddress)
  905. #define Z_FREE_RETURN(x) return
  906. #else
  907. int Z_Free(void *pvAddress)
  908. #define Z_FREE_RETURN(x) return (x)
  909. #endif
  910. {
  911. #ifdef _WINDOWS
  912. if (!s_Initialized) return;
  913. #endif
  914. assert(s_Initialized);
  915. #ifdef _DEBUG
  916. // check the header magic
  917. ZoneDebugHeader* debug_header = (ZoneDebugHeader*)pvAddress - 1;
  918. if (*debug_header != ZONE_MAGIC)
  919. {
  920. Com_Error(ERR_FATAL, "Z_Free(): Corrupt zone header!");
  921. Z_FREE_RETURN( 0 );
  922. }
  923. ZoneHeader* header = (ZoneHeader*)debug_header - 1;
  924. // check the footer magic
  925. ZoneDebugFooter* debug_footer = (ZoneDebugFooter*)((char*)pvAddress +
  926. Z_GetSize(header));
  927. if (*debug_footer != ZONE_MAGIC)
  928. {
  929. Com_Error(ERR_FATAL, "Z_Free(): Corrupt zone footer!");
  930. Z_FREE_RETURN( 0 );
  931. }
  932. #else
  933. ZoneHeader* header = (ZoneHeader*)pvAddress - 1;
  934. #endif
  935. memtag_t tag = Z_GetTag(header);
  936. if (tag != TAG_STATIC)
  937. {
  938. #ifndef _GAMECUBE
  939. WaitForSingleObject(s_Mutex, INFINITE);
  940. #endif
  941. // Determine size of header and footer
  942. int header_size = sizeof(ZoneHeader);
  943. int align_size = Z_GetAlign(header);
  944. int footer_size = 0;
  945. int data_size = Z_GetSize(header);
  946. if (Z_IsTagLinked(tag))
  947. {
  948. header_size += sizeof(ZoneLinkHeader);
  949. }
  950. if (Z_IsTagTemp(tag))
  951. {
  952. footer_size += align_size;
  953. }
  954. else
  955. {
  956. header_size += align_size;
  957. }
  958. #ifdef _DEBUG
  959. header_size += sizeof(ZoneDebugHeader);
  960. footer_size += sizeof(ZoneDebugFooter);
  961. #endif
  962. int real_size = data_size + header_size + footer_size;
  963. // Update the stats
  964. s_Stats.m_SizeAlloc -= data_size;
  965. s_Stats.m_OverheadAlloc -= header_size + footer_size;
  966. s_Stats.m_SizesPerTag[tag] -= data_size;
  967. s_Stats.m_CountAlloc--;
  968. s_Stats.m_CountsPerTag[tag]--;
  969. // Delink block
  970. if (Z_IsTagLinked(tag))
  971. {
  972. ZoneLinkHeader* linked = (ZoneLinkHeader*)header - 1;
  973. if (linked == s_LinkBase)
  974. {
  975. s_LinkBase = linked->m_Next;
  976. if (s_LinkBase)
  977. {
  978. s_LinkBase->m_Prev = NULL;
  979. }
  980. }
  981. else
  982. {
  983. if (linked->m_Next)
  984. {
  985. linked->m_Next->m_Prev = linked->m_Prev;
  986. }
  987. linked->m_Prev->m_Next = linked->m_Next;
  988. }
  989. assert(Z_ValidateLinks());
  990. }
  991. // Clear the block header for safety
  992. *header = 0;
  993. // Add block to free list
  994. ZoneFreeBlock* nblock = NULL;
  995. if (real_size < sizeof(ZoneFreeBlock))
  996. {
  997. // Not enough space in block to put free information --
  998. // use overflow buffer.
  999. nblock = Z_GetOverflowBlock();
  1000. if (nblock == NULL)
  1001. {
  1002. Z_Details_f();
  1003. Com_Error(ERR_FATAL, "Zone free overflow buffer overflowed!");
  1004. }
  1005. }
  1006. else
  1007. {
  1008. // Place free information in block
  1009. nblock = (ZoneFreeBlock*)((char*)pvAddress - header_size);
  1010. }
  1011. nblock->m_Address = (unsigned int)pvAddress - header_size;
  1012. nblock->m_Size = real_size;
  1013. Z_LinkFreeBlock(nblock);
  1014. // Coalesce any adjacent free blocks
  1015. Z_Coalasce(nblock);
  1016. #ifndef _GAMECUBE
  1017. ReleaseMutex(s_Mutex);
  1018. #endif
  1019. }
  1020. Z_FREE_RETURN( 0 );
  1021. }
  1022. int Z_MemSize(memtag_t eTag)
  1023. {
  1024. return s_Stats.m_SizesPerTag[eTag];
  1025. }
  1026. #if ZONE_DEBUG
  1027. void Z_FindLeak(void)
  1028. {
  1029. assert(s_Initialized);
  1030. static int cycle_count = 0;
  1031. const memtag_t tag = TAG_NEWDEL;
  1032. struct PointerInfo
  1033. {
  1034. void* data;
  1035. int counter;
  1036. bool mark;
  1037. };
  1038. const int max_pointers = 32768;
  1039. static PointerInfo pointers[max_pointers];
  1040. static int num_pointers = 0;
  1041. // Clear pointer existance
  1042. for (int i = 0; i < num_pointers; ++i)
  1043. {
  1044. pointers[i].mark = false;
  1045. }
  1046. // Add all known pointers
  1047. int start_num = num_pointers;
  1048. for (ZoneLinkHeader* link = s_LinkBase; link;)
  1049. {
  1050. ZoneHeader* header = (ZoneHeader*)(link + 1);
  1051. link = link->m_Next;
  1052. if (Z_GetTag(header) == tag)
  1053. {
  1054. // See if the pointer already is in the array
  1055. bool found = false;
  1056. for (int k = start_num; k < num_pointers; ++k)
  1057. {
  1058. if (pointers[k].data == header)
  1059. {
  1060. ++pointers[k].counter;
  1061. pointers[k].mark = true;
  1062. found = true;
  1063. break;
  1064. }
  1065. }
  1066. // If the pointer is not in the array, add it
  1067. if (!found)
  1068. {
  1069. assert(num_pointers < max_pointers);
  1070. pointers[num_pointers].data = header;
  1071. pointers[num_pointers].counter = 0;
  1072. pointers[num_pointers].mark = true;
  1073. ++num_pointers;
  1074. }
  1075. }
  1076. }
  1077. // Remove pointers that are no longer used
  1078. for (int j = 0; j < num_pointers; ++j)
  1079. {
  1080. if (pointers[j].mark)
  1081. {
  1082. if (pointers[j].counter != cycle_count &&
  1083. pointers[j].counter != cycle_count - 1 &&
  1084. pointers[j].counter != 0)
  1085. {
  1086. Com_Printf("Memory leak: %p\n", pointers[j].data);
  1087. }
  1088. }
  1089. else
  1090. {
  1091. int k;
  1092. for (k = j; k < num_pointers; ++k)
  1093. {
  1094. if (pointers[k].mark) break;
  1095. }
  1096. if (k == num_pointers) break;
  1097. memmove(pointers + j, pointers + k, (num_pointers - k) * sizeof(PointerInfo));
  1098. num_pointers -= k - j;
  1099. }
  1100. }
  1101. ++cycle_count;
  1102. }
  1103. #endif
  1104. void Z_TagPointers(memtag_t eTag)
  1105. {
  1106. assert(s_Initialized);
  1107. #ifndef _GAMECUBE
  1108. WaitForSingleObject(s_Mutex, INFINITE);
  1109. #endif
  1110. Sys_Log( "pointers.txt", va("Pointers for tag %d:\n", eTag) );
  1111. for (ZoneLinkHeader* link = s_LinkBase; link;)
  1112. {
  1113. ZoneHeader* header = (ZoneHeader*)(link + 1);
  1114. link = link->m_Next;
  1115. if (eTag == TAG_ALL || Z_GetTag(header) == eTag)
  1116. {
  1117. #ifdef _DEBUG
  1118. Sys_Log( "pointers.txt",
  1119. va("%x - %d\n", ((void*)((char*)header +
  1120. sizeof(ZoneHeader) + sizeof(ZoneDebugHeader))),
  1121. Z_Size(((void*)((char*)header +
  1122. sizeof(ZoneHeader) + sizeof(ZoneDebugHeader))))));
  1123. #else
  1124. Sys_Log( "pointers.txt",
  1125. va("%x - %d\n", (void*)(header + 1),
  1126. Z_Size((void*)(header + 1))));
  1127. #endif
  1128. }
  1129. }
  1130. #ifndef _GAMECUBE
  1131. ReleaseMutex(s_Mutex);
  1132. #endif
  1133. }
  1134. void Z_TagFree(memtag_t eTag)
  1135. {
  1136. assert(s_Initialized);
  1137. for (ZoneLinkHeader* link = s_LinkBase; link;)
  1138. {
  1139. ZoneHeader* header = (ZoneHeader*)(link + 1);
  1140. link = link->m_Next;
  1141. if (eTag == TAG_ALL || Z_GetTag(header) == eTag)
  1142. {
  1143. #ifdef _DEBUG
  1144. Z_Free((void*)((char*)header + sizeof(ZoneHeader) +
  1145. sizeof(ZoneDebugHeader)));
  1146. #else
  1147. Z_Free((void*)(header + 1));
  1148. #endif
  1149. }
  1150. }
  1151. }
  1152. void Z_SetNewDeleteTemporary(bool bTemp)
  1153. {
  1154. if( bTemp )
  1155. Z_PushNewDeleteTag( TAG_TEMP_WORKSPACE );
  1156. else
  1157. Z_PopNewDeleteTag();
  1158. }
  1159. void *S_Malloc( int iSize )
  1160. {
  1161. return Z_Malloc(iSize, TAG_SMALL, qfalse, 0);
  1162. }
  1163. int Z_GetLevelMemory(void)
  1164. {
  1165. #ifdef _JK2MP
  1166. return s_Stats.m_SizesPerTag[TAG_BSP];
  1167. #else
  1168. return s_Stats.m_SizesPerTag[TAG_HUNKALLOC] +
  1169. // s_Stats.m_SizesPerTag[TAG_HUNKMISCMODELS] +
  1170. s_Stats.m_SizesPerTag[TAG_BSP];
  1171. #endif
  1172. }
  1173. #ifdef _JK2MP
  1174. int Z_GetHunkMemory(void)
  1175. {
  1176. return s_Stats.m_SizesPerTag[TAG_HUNKALLOC] +
  1177. s_Stats.m_SizesPerTag[TAG_TEMP_HUNKALLOC];
  1178. }
  1179. #endif
  1180. int Z_GetMiscMemory(void)
  1181. {
  1182. return s_Stats.m_SizeAlloc -
  1183. (Z_GetLevelMemory() +
  1184. #ifdef _JK2MP
  1185. Z_GetHunkMemory() +
  1186. #endif
  1187. s_Stats.m_SizesPerTag[TAG_MODEL_GLM] +
  1188. s_Stats.m_SizesPerTag[TAG_MODEL_GLA] +
  1189. s_Stats.m_SizesPerTag[TAG_MODEL_MD3] +
  1190. s_Stats.m_SizesPerTag[TAG_BINK] +
  1191. s_Stats.m_SizesPerTag[TAG_SND_RAWDATA]);
  1192. }
  1193. #ifdef _GAMECUBE
  1194. static int texMemSize = 0;
  1195. #else
  1196. extern int texMemSize;
  1197. //extern unsigned long texturePoint;
  1198. #endif
  1199. void Z_CompactStats(void)
  1200. {
  1201. // New and improved, super version of CompactStats:
  1202. assert(s_Initialized);
  1203. static int printHeader = 1;
  1204. if( printHeader )
  1205. {
  1206. printHeader = 0;
  1207. Sys_Log("memory-map.txt", "Level:\tTextures:\tFreeZone:\tOverhead:\tTags...\n");
  1208. }
  1209. // No more being conservative and doing strange math. I want real numbers:
  1210. Sys_Log("memory-map.txt", va("%s\t%d\t%d\t%d",
  1211. Cvar_VariableString( "mapname" ),
  1212. gTextures.Size(),
  1213. s_Stats.m_SizeFree,
  1214. s_Stats.m_OverheadAlloc));
  1215. for( int t = 0; t < TAG_COUNT; ++t )
  1216. Sys_Log("memory-map.txt", va("\t%d", s_Stats.m_SizesPerTag[t]));
  1217. Sys_Log("memory-map.txt", "\n");
  1218. }
  1219. static void Z_Stats_f(void)
  1220. {
  1221. assert(s_Initialized);
  1222. // Display some memory usage summary information...
  1223. Com_Printf("\nThe zone is using %d bytes (%.2fMB) in %d memory blocks\n",
  1224. s_Stats.m_SizeAlloc,
  1225. (float)s_Stats.m_SizeAlloc / 1024.0f / 1024.0f,
  1226. s_Stats.m_CountAlloc);
  1227. Com_Printf("Free memory is %d bytes (%.2fMB) in %d memory blocks\n",
  1228. s_Stats.m_SizeFree,
  1229. (float)s_Stats.m_SizeFree / 1024.0f / 1024.0f,
  1230. s_Stats.m_CountFree);
  1231. Com_Printf("The zone peaked at %d bytes (%.2fMB)\n",
  1232. s_Stats.m_PeakAlloc,
  1233. (float)s_Stats.m_PeakAlloc / 1024.0f / 1024.0f);
  1234. Com_Printf("The zone overhead is %d bytes (%.2fMB)\n",
  1235. s_Stats.m_OverheadAlloc,
  1236. (float)s_Stats.m_OverheadAlloc / 1024.0f / 1024.0f);
  1237. }
  1238. void Z_Details_f(void)
  1239. {
  1240. assert(s_Initialized);
  1241. // Display some tag specific information...
  1242. Com_Printf("---------------------------------------------------------------------------\n");
  1243. Com_Printf("%20s %9s\n","Zone Tag","Bytes");
  1244. Com_Printf("%20s %9s\n","--------","-----");
  1245. for (int i=0; i<TAG_COUNT; i++)
  1246. {
  1247. int iThisCount = s_Stats.m_CountsPerTag[i];
  1248. int iThisSize = s_Stats.m_SizesPerTag[i];
  1249. if (iThisCount)
  1250. {
  1251. float fSize = (float)(iThisSize) / 1024.0f / 1024.0f;
  1252. int iSize = fSize;
  1253. int iRemainder = 100.0f * (fSize - floor(fSize));
  1254. Com_Printf("%d %9d (%2d.%02dMB) in %6d blocks (%9d average)\n",
  1255. i, iThisSize, iSize, iRemainder, iThisCount, iThisSize / iThisCount);
  1256. }
  1257. }
  1258. Com_Printf("---------------------------------------------------------------------------\n");
  1259. Z_Stats_f();
  1260. }
  1261. void Z_DumpMemMap_f(void)
  1262. {
  1263. # define WRITECHAR(C) \
  1264. Sys_Log("memmap.txt", C, 1, false); \
  1265. cur += 1024; \
  1266. if ((++counter) % 81 == 0) Sys_Log("memmap.txt", "\n", 1, false);
  1267. unsigned int cur = (unsigned int)s_PoolBase;
  1268. unsigned int counter = 0;
  1269. for (ZoneFreeBlock* fblock = &s_FreeStart; fblock != &s_FreeEnd; fblock = fblock->m_Next)
  1270. {
  1271. while (fblock->m_Address > cur + 1024)
  1272. {
  1273. WRITECHAR("*");
  1274. }
  1275. if (fblock->m_Address > cur && fblock->m_Address < cur + 1024)
  1276. {
  1277. WRITECHAR("+");
  1278. }
  1279. while (fblock->m_Address + fblock->m_Size > cur + 1024)
  1280. {
  1281. WRITECHAR("-");
  1282. }
  1283. if (fblock->m_Address + fblock->m_Size > cur &&
  1284. fblock->m_Address + fblock->m_Size < cur + 1024)
  1285. {
  1286. WRITECHAR("+");
  1287. }
  1288. }
  1289. Sys_Log("memmap.txt", "\n");
  1290. }
  1291. void Z_DisplayLevelMemory(int size, int surf, int block)
  1292. {
  1293. Z_DumpMemMap_f();
  1294. //Yes, it should be divided by 1024, but I'm going for a safety margin
  1295. //by rounding down.
  1296. //Com_Printf("level memory used: %d KB\n", size / 1000);
  1297. //Z_CompactStats(size, surf, block);
  1298. Z_CompactStats();
  1299. }
  1300. void Z_DisplayLevelMemory(void)
  1301. {
  1302. #ifdef _GAMECUBE
  1303. extern void R_SurfMramUsed(int &surface, int &block);
  1304. int surface, block;
  1305. R_SurfMramUsed(surface, block);
  1306. Z_DisplayLevelMemory(Z_GetLevelMemory(), surface, block);
  1307. #else
  1308. Z_DisplayLevelMemory(Z_GetLevelMemory(), 0, 0);
  1309. #endif
  1310. }
  1311. /*
  1312. ========================
  1313. CopyString
  1314. NOTE: never write over the memory CopyString returns because
  1315. memory from a memstatic_t might be returned
  1316. ========================
  1317. */
  1318. char *CopyString( const char *in )
  1319. {
  1320. struct ZoneSingleChar
  1321. {
  1322. ZoneHeader header;
  1323. #ifdef _DEBUG
  1324. ZoneDebugHeader start;
  1325. #endif
  1326. char data[2];
  1327. #ifdef _DEBUG
  1328. ZoneDebugFooter end;
  1329. #endif
  1330. };
  1331. #ifdef _DEBUG
  1332. static ZoneSingleChar empty = {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "\0", ZONE_MAGIC};
  1333. static ZoneSingleChar numbers[10] =
  1334. {
  1335. {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "0", ZONE_MAGIC},
  1336. {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "1", ZONE_MAGIC},
  1337. {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "2", ZONE_MAGIC},
  1338. {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "3", ZONE_MAGIC},
  1339. {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "4", ZONE_MAGIC},
  1340. {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "5", ZONE_MAGIC},
  1341. {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "6", ZONE_MAGIC},
  1342. {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "7", ZONE_MAGIC},
  1343. {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "8", ZONE_MAGIC},
  1344. {(TAG_STATIC << 25) | 2, ZONE_MAGIC, "9", ZONE_MAGIC},
  1345. };
  1346. #else
  1347. static ZoneSingleChar empty = {(TAG_STATIC << 25) | 2, "\0"};
  1348. static ZoneSingleChar numbers[10] =
  1349. {
  1350. {(TAG_STATIC << 25) | 2, "0"},
  1351. {(TAG_STATIC << 25) | 2, "1"},
  1352. {(TAG_STATIC << 25) | 2, "2"},
  1353. {(TAG_STATIC << 25) | 2, "3"},
  1354. {(TAG_STATIC << 25) | 2, "4"},
  1355. {(TAG_STATIC << 25) | 2, "5"},
  1356. {(TAG_STATIC << 25) | 2, "6"},
  1357. {(TAG_STATIC << 25) | 2, "7"},
  1358. {(TAG_STATIC << 25) | 2, "8"},
  1359. {(TAG_STATIC << 25) | 2, "9"},
  1360. };
  1361. #endif
  1362. char *out;
  1363. if (!in[0])
  1364. {
  1365. return empty.data;
  1366. }
  1367. else if (!in[1])
  1368. {
  1369. if (in[0] >= '0' && in[0] <= '9')
  1370. {
  1371. return numbers[in[0]-'0'].data;
  1372. }
  1373. }
  1374. out = (char *) S_Malloc (strlen(in)+1);
  1375. strcpy (out, in);
  1376. // Z_Label(out,in);
  1377. return out;
  1378. }
  1379. void Com_TouchMemory(void)
  1380. {
  1381. // Stub function. Do nothing.
  1382. return;
  1383. }
  1384. qboolean Z_IsFromZone(void *pvAddress, memtag_t eTag)
  1385. {
  1386. if(pvAddress >= s_PoolBase && pvAddress < (char*)s_PoolBase + s_PoolSize) {
  1387. return qtrue;
  1388. }
  1389. return qfalse;
  1390. }
  1391. qboolean Z_IsFromTempPool(void *pvAddress)
  1392. {
  1393. if(pvAddress >= s_TempAllocPool && pvAddress < s_TempAllocPool +
  1394. s_TempAllocPoint) {
  1395. return qtrue;
  1396. }
  1397. return qfalse;
  1398. }
  1399. /*
  1400. Hunk emulation
  1401. The emulation is pretty bad right now, we just use two tags:
  1402. TAG_HUNKALLOC and TAG_TEMP_HUNKALLOC, to represent the permanent and
  1403. temporary sides of the hunk respectively. We should make the
  1404. Hunk allocations tagged so we can do this better.
  1405. */
  1406. #ifdef _JK2MP
  1407. void Hunk_Clear(void)
  1408. {
  1409. Z_TagFree(TAG_TEMP_HUNKALLOC);
  1410. Z_TagFree(TAG_HUNKALLOC);
  1411. /*
  1412. Z_TagFree(TAG_HUNKALLOC);
  1413. Z_TagFree(TAG_BSP_HUNK);
  1414. Z_TagFree(TAG_BOT_HUNK);
  1415. Z_TagFree(TAG_RENDERER_HUNK);
  1416. Z_TagFree(TAG_SKELETON);
  1417. Z_TagFree(TAG_MODEL_OTHER);
  1418. Z_TagFree(TAG_MODEL_CHAR);
  1419. VM_Clear();
  1420. */
  1421. }
  1422. //void *Hunk_Alloc( int size, ha_pref preference, memtag_t eTag )
  1423. void *Hunk_Alloc(int size, ha_pref preference)
  1424. {
  1425. return Z_Malloc(size, TAG_HUNKALLOC, qtrue);
  1426. /*
  1427. assert(eTag == TAG_HUNKALLOC ||
  1428. eTag == TAG_BSP_HUNK ||
  1429. eTag == TAG_BOT_HUNK ||
  1430. eTag == TAG_RENDERER_HUNK ||
  1431. eTag == TAG_SKELETON ||
  1432. eTag == TAG_MODEL_OTHER ||
  1433. eTag == TAG_MODEL_CHAR);
  1434. return Z_Malloc(size, eTag, qtrue);
  1435. */
  1436. }
  1437. void *Hunk_AllocateTempMemory(int size)
  1438. {
  1439. return Z_Malloc(size, TAG_TEMP_HUNKALLOC, qtrue);
  1440. /*
  1441. return Z_Malloc(size, TAG_TEMP_HUNK, qtrue);
  1442. */
  1443. }
  1444. void Hunk_FreeTempMemory(void *buf)
  1445. {
  1446. Z_Free(buf);
  1447. }
  1448. void Hunk_ClearTempMemory(void)
  1449. {
  1450. Z_TagFree(TAG_TEMP_HUNKALLOC);
  1451. // Z_TagFree(TAG_TEMP_HUNK);
  1452. }
  1453. void Com_InitHunkMemory(void)
  1454. {
  1455. }
  1456. int Hunk_MemoryRemaining(void)
  1457. {
  1458. return 0;
  1459. }
  1460. void Hunk_ClearToMark(void)
  1461. {
  1462. }
  1463. qboolean Hunk_CheckMark(void)
  1464. {
  1465. return qfalse;
  1466. }
  1467. void Hunk_SetMark(void)
  1468. {
  1469. }
  1470. #endif // _JK2MP
  1471. /*
  1472. XBOXAPI
  1473. LPVOID
  1474. WINAPI
  1475. XMemAlloc(SIZE_T dwSize, DWORD dwAllocAttributes)
  1476. {
  1477. return XMemAllocDefault(dwSize, dwAllocAttributes);
  1478. }
  1479. */
  1480. /*
  1481. XTL Replacement functions
  1482. XMemAlloc
  1483. XMemFree
  1484. XMemSize
  1485. Replacing these lets us intercept ALL memory allocation done by the XTL, and lets the
  1486. Zone take pretty much all available memory at startup
  1487. */
  1488. /* This still doesn't work. Numrous allocations still use internal functions, so there's
  1489. little benefit right now.
  1490. XBOXAPI
  1491. LPVOID
  1492. WINAPI
  1493. XMemAlloc(SIZE_T dwSize, DWORD dwAllocAttributes)
  1494. {
  1495. PXALLOC_ATTRIBUTES pAllocAttributes = (PXALLOC_ATTRIBUTES)&dwAllocAttributes;
  1496. LPVOID ptr = NULL;
  1497. if (pAllocAttributes->dwMemoryType == XALLOC_MEMTYPE_HEAP)
  1498. { // Heap allocation
  1499. ptr = HeapAlloc(GetProcessHeap(),
  1500. pAllocAttributes->dwZeroInitialize ? HEAP_ZERO_MEMORY : 0,
  1501. dwSize);
  1502. if (pAllocAttributes->dwHeapTracksAttributes)
  1503. XSetAttributesOnHeapAlloc(ptr, dwAllocAttributes);
  1504. }
  1505. else
  1506. { // Physical allocation
  1507. // Map requested alignment to real alignment
  1508. ULONG_PTR ulAlign = 0;
  1509. DWORD dwProtect = 0;
  1510. switch(pAllocAttributes->dwAlignment)
  1511. {
  1512. case XALLOC_PHYSICAL_ALIGNMENT_8K:
  1513. ulAlign = 8*1024;
  1514. break;
  1515. case XALLOC_PHYSICAL_ALIGNMENT_16K:
  1516. ulAlign = 16*1024;
  1517. break;
  1518. case XALLOC_PHYSICAL_ALIGNMENT_32K:
  1519. ulAlign = 32*1024;
  1520. break;
  1521. default:
  1522. ulAlign = 4*1024;
  1523. break;
  1524. }
  1525. if (pAllocAttributes->dwMemoryProtect & XALLOC_MEMPROTECT_READONLY)
  1526. dwProtect = PAGE_READONLY;
  1527. else
  1528. dwProtect = PAGE_READWRITE;
  1529. if (pAllocAttributes->dwMemoryProtect & XALLOC_MEMPROTECT_NOCACHE)
  1530. dwProtect |= PAGE_NOCACHE;
  1531. if (pAllocAttributes->dwMemoryProtect & XALLOC_MEMPROTECT_WRITECOMBINE)
  1532. dwProtect |= PAGE_WRITECOMBINE;
  1533. ptr = XPhysicalAlloc(dwSize, MAXULONG_PTR, ulAlign, dwProtect);
  1534. }
  1535. return ptr;
  1536. }
  1537. */
  1538. /*
  1539. XBOXAPI
  1540. VOID
  1541. WINAPI
  1542. XMemFree(PVOID pAddress, DWORD dwAllocAttributes)
  1543. {
  1544. XMemFreeDefault(pAddress, dwAllocAttributes);
  1545. }
  1546. */
  1547. /*
  1548. XBOXAPI
  1549. VOID
  1550. WINAPI
  1551. XMemFree(PVOID pAddress, DWORD dwAllocAttributes)
  1552. {
  1553. PXALLOC_ATTRIBUTES pAllocAttributes = (PXALLOC_ATTRIBUTES)&dwAllocAttributes;
  1554. if (pAllocAttributes->dwMemoryType == XALLOC_MEMTYPE_HEAP)
  1555. { // Heap pointer
  1556. HeapFree(GetProcessHeap(), 0, pAddress);
  1557. }
  1558. else
  1559. { // Physical pointer
  1560. XPhysicalFree(pAddress);
  1561. }
  1562. }
  1563. */
  1564. /*
  1565. XBOXAPI
  1566. SIZE_T
  1567. WINAPI
  1568. XMemSize(PVOID pAddress, DWORD dwAllocAttributes)
  1569. {
  1570. return XMemSizeDefault(pAddress, dwAllocAttributes);
  1571. }
  1572. */
  1573. /*
  1574. XBOXAPI
  1575. SIZE_T
  1576. WINAPI
  1577. XMemSize(PVOID pAddress, DWORD dwAllocAttributes)
  1578. {
  1579. PXALLOC_ATTRIBUTES pAllocAttributes = (PXALLOC_ATTRIBUTES)&dwAllocAttributes;
  1580. if (pAllocAttributes->dwMemoryType == XALLOC_MEMTYPE_HEAP)
  1581. { // Heap pointer
  1582. return HeapSize(GetProcessHeap(), 0, pAddress);
  1583. }
  1584. else
  1585. { // Physical pointer
  1586. return XPhysicalSize(pAddress);
  1587. }
  1588. }
  1589. */