#pragma once
//===========================================================================//
// File:	 MemoryManager.cpp												 //
// Project:  GameOS					                                         //
// Contents: MemoryManager subsyystem										 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 12/12/97  JTR    Created													 //
// 12/27/97  JTR	Documented												 //
// 01/07/98  JTR	Cleaned up reporting. Added timestamp.					 //
//---------------------------------------------------------------------------//
// Copyright (C) 1999 Microsoft Corp.						                 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

struct _MEMORYPOOL;
struct _HEAPHEADER;
struct _LARGEBLOCKHEADER;

//
// Single byte before allocations
//
// 0	 = Invalid (duplicate free detection)
// 1-252 = Heap number for a 'pool' allocated block
// 253   = Large block (not in pools)
// 254   = Block allocated before init.
// 255   = Unused
//
//
const int Magic_LargeBlock=253;					// Larger than 4k memory block (no in pools)
const int Magic_BeforeInit=254;					// Allocated before inited  (was 0xabadcafe)

//
// This is the largest 'pool' size - blocks larger than this use the system allocator
//
const int LargestMemoryBlock=1024;				// Largest memory block managed
//
// This is the total number of pools being managed
//
const int MemoryPools=18;						// Number of memory pools (defined in PoolSizes[])

//
// Magic number placed after allocations in DEBUG/ARMOR
//
const int MemoryEndMarker=0x7fb1deaf;			// Placed at the end of allocations in _ARMOR builds





#pragma pack(push,1)
//
// Information block for all blocks in pools with < 256 bytes
//
typedef struct
{
#ifdef LAB_ONLY
	BYTE			Size;						// Size of block (note pools are always <64K)
#endif
#ifdef _DEBUG
	DOUBLE			dTimeStamp;					// at what time was the block alloc'd
	DWORD			pContext[0];				// we'll allocate the right size based on gMemoryStackWalkLevel
#endif
} SMALLPOOLBLOCK;

//
// Information block for all blocks in pools with >= 256 bytes
//
typedef struct
{
#ifdef LAB_ONLY
	WORD			Size;						// Size of block (note pools are always <64K)
#endif
#ifdef _DEBUG
	DOUBLE			dTimeStamp;					// at what time was the block alloc'd
	DWORD			pContext[0];				// we'll allocate the right size based on gMemoryStackWalkLevel
#endif
} POOLBLOCK;

//
// Header for large blocks or blocks before memory manager inited.
//
typedef struct _LARGEBLOCK
{
	DWORD				Size;					// Size of block (note can be any size)
	_LARGEBLOCKHEADER*	pLast;					// Pointer to previous large memory block
	_LARGEBLOCKHEADER*	pNext;					// Pointer to next large memory block
	BYTE				Heap;
#ifdef _DEBUG
	DOUBLE				dTimeStamp;				// at what time was the block alloc'd
	DWORD				pContext[0];			// we'll allocate the right size based on gMemoryStackWalkLevel
#endif
} LARGEBLOCK;

//
// Structure placed directly BEFORE each memory block
//
typedef struct _LARGEBLOCKHEADER
{
	LARGEBLOCK*		pLargeBlockInfo;
	BYTE			LargeMagicNumber;			// Magic_LargeBlock or Magic_BeforeInit
} LARGEBLOCKHEADER;

//
// Structure used to hold information about 'pools' of memory blocks
//
typedef struct _MEMORYPOOL
{
	DWORD				HeapTag;				// Tag so that memory is easily spotted in VM viewers
	_MEMORYPOOL*		pLast;					// Points to the last heap of the SAME block size
	_MEMORYPOOL*		pNext;					// Points to the next heap of the SAME block size
	POOLBLOCK*			pInfoBlocks;			// an array of blocks which describe particular memory blocks (may point to a SMALLPOOLBLOCK header for >256 bytes)
	BYTE*				pMemoryPool;			// Pointer to the base of the memory blocks (pointer to header byte before allocation)
	WORD				wBlockSize;				// what is the size of the individual blocks?
	WORD				wTotalBlocks;			// Total blocks available
	#ifdef LAB_ONLY
	WORD				wUserBytes;				// the amount of memory in the pool that is actual user data
	#endif
	WORD				AllocCount[16];			// Number of blocks allocated in each 4K page (when 0, block can be decommitted)
	WORD				FreeBlockPtr;			// Next available block in FreeBlockStack
	WORD				FreeBlockStack[0];		// Free block offsets (from base of pool - pointer to header byte before allocation)
} MEMORYPOOL;

//
// Used to hold GameOS level heap information
//
struct gos_Heap
{
	gos_Heap*	pParent;
	gos_Heap*	pNext;
	gos_Heap*	pChild;
	DWORD		Magic;
	int			Instances;
	char		Name[128];
#ifdef LAB_ONLY
	DWORD		MaximumSize;
	int			BytesAllocated;
	int			TotalAllocatedLastLoop;
	int			BytesAllocatedThisLoop;
	int			BytesFreedThisLoop;
	int			AllocationsThisLoop;
	int			AllocationsLastLoop;
	int			TotalAllocations;
	int			PeakSize;
	bool		bExpanded;							// this is used for collapsing tree in debugger
	bool		bExamined;							// this is used for collapsing tree in debugger
	int			LargeAllocations;
	int			LargeAllocated;
	int			DXAllocations;
	int			DXAllocated;
#endif
	BYTE		HeapNumber;							// Heap number in HeapList[]  (<<24)
};
#pragma pack(pop)





extern gos_Heap* AllHeaps;
extern WORD PoolSizes[MemoryPools];
extern HGOSHEAP HeapList[256];
extern DWORD LargeMemorySize;
extern DWORD LargeMemoryAllocations;
extern DWORD gMemoryBlockOverhead;
extern HGOSHEAP Heap_Texture;
extern HGOSHEAP Heap_Texture32;
extern HGOSHEAP Heap_Texture16;
extern HGOSHEAP Heap_TextureOther;
extern HGOSHEAP Heap_Network;
extern HGOSHEAP ParentGameOSHeap;
extern HGOSHEAP DefaultHeap;
extern MEMORYPOOL* gMemoryPool[MemoryPools];


void gos_ChangeHeapSize( HGOSHEAP Heap, int Change, bool SystemAllocation=0 );
void MM_CheckRegistered();
void MM_Shutdown();
void MM_UpdateStatistics( HGOSHEAP Heap );
void MM_Startup();
void SetupVirtualMemory();
void AnalyzeWS( char* Title );


extern PSAPI_WS_WATCH_INFORMATION* pMemBlockInfo;
extern HANDLE HWSProcess;
