You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
5.3 KiB
146 lines
5.3 KiB
//========= 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
|
|
|