summaryrefslogtreecommitdiff
path: root/materialsystem/shaderapidx9/gpubufferallocator.h
blob: cffd96d3189185d604d3a26acbb14cf9d742dcac (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: CGPUBufferAllocator manages allocation of VBs/IBs from shared memory pools.
//          Avoids 4KB physical alloc alignment overhead per VB/IB.
//
// $NoKeywords: $
//
//===========================================================================//


#ifndef GPUBUFFERALLOCATOR_H
#define GPUBUFFERALLOCATOR_H

#ifdef _WIN32
#pragma once
#endif

#ifdef _X360

#include "tier1/utlvector.h"
#include "tier1/convar.h"

class CVertexBuffer;
class CIndexBuffer;


// Only active on X360 atm
#define USE_GPU_BUFFER_ALLOCATOR ( IsX360() )


//-----------------------------------------------------------------------------
// A handle to a buffer pool allocation, held by the allocated VB/IB
//-----------------------------------------------------------------------------
struct GPUBufferHandle_t
{
	GPUBufferHandle_t( void ) : nPoolNum( -1 ), pMemory( NULL ), nPoolEntry( -1 ) {}
	bool IsValid( void ) { return ( pMemory != NULL ); }
	byte *	pMemory;		// Physical address of the allocation
	int		nPoolNum;		// Identifies the pool
	int		nPoolEntry;		// Identifies this allocation within the pool
};

//-----------------------------------------------------------------------------
// Describes an entry in a CGPUBufferPool
//-----------------------------------------------------------------------------
struct GPUBufferPoolEntry_t
{
	int  nOffset;
	int  nSize;
	bool bIsVertexBuffer;
	union
	{
		// These are set to NULL by CGPUBufferPool::Free() (called when the VB/IB is destroyed)
		CVertexBuffer *pVertexBuffer;
		CIndexBuffer  *pIndexBuffer;
	};
};

//-----------------------------------------------------------------------------
// A single memory block out of which individual VBs/IBs are allocated
//-----------------------------------------------------------------------------
class CGPUBufferPool
{
public:
	CGPUBufferPool( int nSize );
	virtual ~CGPUBufferPool( void );

	// Returns the index (-1 on failure) of a new allocation in the pool, for a buffer of the given size.
	int Allocate( int nSize, bool bIsVertexBuffer, void *pObject );
	// Frees a given entry (just marks it as freed, the memory will not be reused by Allocate() until CGPUBufferAllocator::Defrag() is called )
	void Deallocate( const GPUBufferHandle_t *pHandle );

private:
	// NOTE: these values are specialized for X360 and should be #ifdef'd for other target platforms
	static const int POOL_ENTRIES_INIT_SIZE = 256;
	static const int POOL_ENTRIES_GROW_SIZE = 256;
	static const int POOL_ENTRY_ALIGNMENT	= 4;	// 4-byte alignment required for VB/IB data on XBox360

	byte *							m_pMemory;		// Pointer to the (physical) address of the pool's memory
	int								m_nSize;		// Total size of the pool
	int								m_nBytesUsed;	// High watermark of used memory in the pool
	CUtlVector<GPUBufferPoolEntry_t>m_PoolEntries;	// Memory-order array of items allocated in the pool

	// CGPUBufferAllocator is a friend so that CGPUBufferAllocator::Defrag() can shuffle allocations around
	friend class CGPUBufferAllocator;
};

//-----------------------------------------------------------------------------
// Manages a set of memory blocks out of which individual VBs/IBs are allocated
//-----------------------------------------------------------------------------
class CGPUBufferAllocator
{
public:
	CGPUBufferAllocator( void );
	virtual ~CGPUBufferAllocator( void );

	// (De)Allocates memory for a vertex/index buffer:
	bool AllocateVertexBuffer(   CVertexBuffer *pVertexBuffer, int nBufferSize );
	bool AllocateIndexBuffer(    CIndexBuffer  *pIndexBuffer,  int nBufferSize  );
	void DeallocateVertexBuffer( CVertexBuffer *pVertexBuffer );
	void DeallocateIndexBuffer(  CIndexBuffer  *pIndexBuffer  );

	// Compact memory to account for freed buffers
	// NOTE: this must only be called during map transitions, no rendering must be in flight and everything must be single-threaded!
	void Compact();

	// Spew statistics about pooled buffer allocations
	void SpewStats( bool bBrief = false );


private:
	// NOTE: these values are specialized for X360 and should be #ifdef'd for other target platforms
	static const int INITIAL_POOL_SIZE		= 57*1024*1024 + 256*1024;
	static const int ADDITIONAL_POOL_SIZE	= 2*1024*1024;
	static const int MAX_POOLS				= 8;
	static const int MAX_BUFFER_SIZE		= ADDITIONAL_POOL_SIZE; // 256*1024;


	// Allocate a new CGPUBufferPool
	bool AllocatePool( int nPoolSize );
	// Allocate/deallocate a buffer (type-agnostic)
	bool AllocateBuffer(   GPUBufferHandle_t *pHandle, int nBufferSize, void *pObject, bool bIsVertexBuffer );
	void DeallocateBuffer( const GPUBufferHandle_t *pHandle );
	// Make a handle for a given allocation
	GPUBufferHandle_t MakeGPUBufferHandle( int nPoolNum, int nPoolEntry );
	// Helper for Compact
	void MoveBufferMemory( int nDstPool, int *pnDstEntry, int *pnDstOffset, CGPUBufferPool &srcPool, GPUBufferPoolEntry_t &srcEntry );


	CGPUBufferPool *m_BufferPools[ MAX_POOLS ];
	int				m_nBufferPools;
	bool			m_bEnabled;

	CThreadFastMutex m_mutex;
};


// Track non-pooled physallocs, to help tune CGPUBufferAllocator usage:
extern CInterlockedInt g_NumIndividualIBPhysAllocs;
extern CInterlockedInt g_SizeIndividualIBPhysAllocs;
extern CInterlockedInt g_NumIndividualVBPhysAllocs;
extern CInterlockedInt g_SizeIndividualVBPhysAllocs;

#endif // _X360

#endif // GPUBUFFERALLOCATOR_H