summaryrefslogtreecommitdiff
path: root/materialsystem/shaderapidx9/gpubufferallocator.h
diff options
context:
space:
mode:
Diffstat (limited to 'materialsystem/shaderapidx9/gpubufferallocator.h')
-rw-r--r--materialsystem/shaderapidx9/gpubufferallocator.h146
1 files changed, 146 insertions, 0 deletions
diff --git a/materialsystem/shaderapidx9/gpubufferallocator.h b/materialsystem/shaderapidx9/gpubufferallocator.h
new file mode 100644
index 0000000..cffd96d
--- /dev/null
+++ b/materialsystem/shaderapidx9/gpubufferallocator.h
@@ -0,0 +1,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