147 lines
5.3 KiB
C++
147 lines
5.3 KiB
C++
//========= 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
|