mirror of
https://github.com/celisej567/cool-source-archive.git
synced 2026-09-15 20:09:19 +03:00
430 lines
11 KiB
C++
430 lines
11 KiB
C++
// HUH???
|
|
#define RAD_TELEMETRY_DISABLED
|
|
|
|
#include "VertexBufferDx11.h"
|
|
#include "shaderapidx9/locald3dtypes.h"
|
|
#include "shaderapidx11_global.h"
|
|
#include "shaderdevicedx11.h"
|
|
#include "shaderapi/ishaderutil.h"
|
|
#include "tier0/vprof.h"
|
|
#include "tier0/dbg.h"
|
|
#include "materialsystem/ivballoctracker.h"
|
|
#include "tier2/tier2.h"
|
|
|
|
// NOTE: This has to be the last file included!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Dx11 implementation of a vertex buffer
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// globals
|
|
//-----------------------------------------------------------------------------
|
|
#ifdef _DEBUG
|
|
int CVertexBufferDx11::s_nBufferCount = 0;
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// constructor, destructor
|
|
//-----------------------------------------------------------------------------
|
|
CVertexBufferDx11::CVertexBufferDx11( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char* pBudgetGroupName ) :
|
|
BaseClass( pBudgetGroupName )
|
|
{
|
|
Assert( nVertexCount != 0 );
|
|
|
|
m_pVertexMemory = NULL;
|
|
m_nVerticesLocked = 0;
|
|
m_pVertexBuffer = NULL;
|
|
m_VertexFormat = fmt;
|
|
m_nVertexCount = ( fmt == VERTEX_FORMAT_UNKNOWN ) ? 0 : nVertexCount;
|
|
m_VertexSize = VertexFormatSize( m_VertexFormat );
|
|
m_nBufferSize = ( fmt == VERTEX_FORMAT_UNKNOWN ) ? nVertexCount : nVertexCount * VertexSize();
|
|
m_Position = 0;
|
|
m_bIsLocked = false;
|
|
m_bIsDynamic = ( type == SHADER_BUFFER_TYPE_DYNAMIC ) || ( type == SHADER_BUFFER_TYPE_DYNAMIC_TEMP );
|
|
m_bFlush = false;
|
|
}
|
|
|
|
CVertexBufferDx11::~CVertexBufferDx11()
|
|
{
|
|
Free();
|
|
}
|
|
|
|
bool CVertexBufferDx11::HasEnoughRoom( int nVertCount ) const
|
|
{
|
|
return ( NextLockOffset() + ( nVertCount * m_VertexSize ) ) <= m_nBufferSize;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates, destroys the vertex buffer
|
|
//-----------------------------------------------------------------------------
|
|
bool CVertexBufferDx11::Allocate()
|
|
{
|
|
Assert( !m_pVertexBuffer );
|
|
|
|
if ( !m_bIsDynamic )
|
|
{
|
|
m_pVertexMemory = (unsigned char *)malloc( m_nBufferSize );
|
|
memset( m_pVertexMemory, 0, m_nBufferSize );
|
|
}
|
|
else
|
|
{
|
|
m_pVertexMemory = NULL;
|
|
}
|
|
|
|
m_Position = 0;
|
|
|
|
D3D11_BUFFER_DESC bd;
|
|
if ( m_bIsDynamic )
|
|
{
|
|
bd.Usage = D3D11_USAGE_DYNAMIC;
|
|
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
}
|
|
else
|
|
{
|
|
bd.Usage = D3D11_USAGE_DEFAULT;
|
|
bd.CPUAccessFlags = 0;
|
|
}
|
|
|
|
bd.ByteWidth = m_nBufferSize;
|
|
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
|
bd.MiscFlags = 0;
|
|
|
|
//Log( "Creating D3D vertex buffer: size: %i\n", m_nBufferSize );
|
|
|
|
//if ( m_nBufferSize <= 0 )
|
|
//{
|
|
// int *p = 0;
|
|
// *p = 1;
|
|
//}
|
|
|
|
|
|
HRESULT hr = D3D11Device()->CreateBuffer( &bd, NULL, &m_pVertexBuffer );
|
|
bool bOk = !FAILED( hr ) && ( m_pVertexBuffer != 0 );
|
|
|
|
if ( bOk )
|
|
{
|
|
// Track VB allocations
|
|
g_VBAllocTracker->CountVB( m_pVertexBuffer, m_bIsDynamic, m_nBufferSize, VertexSize(), GetVertexFormat() );
|
|
|
|
if ( !m_bIsDynamic )
|
|
{
|
|
VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
|
|
COUNTER_GROUP_TEXTURE_GLOBAL, m_nBufferSize );
|
|
}
|
|
else
|
|
{
|
|
VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
|
|
COUNTER_GROUP_TEXTURE_GLOBAL, m_nBufferSize );
|
|
// Dynamic meshes should never be compressed (slows down writing to them)
|
|
Assert( CompressionType( GetVertexFormat() ) == VERTEX_COMPRESSION_NONE );
|
|
}
|
|
#ifdef _DEBUG
|
|
++s_nBufferCount;
|
|
#endif
|
|
}
|
|
|
|
return bOk;
|
|
}
|
|
|
|
void CVertexBufferDx11::Free()
|
|
{
|
|
if ( m_pVertexBuffer )
|
|
{
|
|
#ifdef _DEBUG
|
|
--s_nBufferCount;
|
|
#endif
|
|
|
|
// Track VB allocations
|
|
g_VBAllocTracker->UnCountVB( m_pVertexBuffer );
|
|
|
|
m_pVertexBuffer->Release();
|
|
m_pVertexBuffer = NULL;
|
|
|
|
if ( !m_bIsDynamic )
|
|
{
|
|
VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
|
|
COUNTER_GROUP_TEXTURE_GLOBAL, -m_nBufferSize );
|
|
}
|
|
else
|
|
{
|
|
VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
|
|
COUNTER_GROUP_TEXTURE_GLOBAL, -m_nBufferSize );
|
|
}
|
|
}
|
|
|
|
if ( m_pVertexMemory )
|
|
{
|
|
free( m_pVertexMemory );
|
|
m_pVertexMemory = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Vertex Buffer info
|
|
//-----------------------------------------------------------------------------
|
|
int CVertexBufferDx11::VertexCount() const
|
|
{
|
|
//Assert( !m_bIsDynamic );
|
|
return m_nVertexCount;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the buffer format (only valid for static index buffers)
|
|
//-----------------------------------------------------------------------------
|
|
VertexFormat_t CVertexBufferDx11::GetVertexFormat() const
|
|
{
|
|
//Assert( !m_bIsDynamic );
|
|
return m_VertexFormat;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns true if the buffer is dynamic
|
|
//-----------------------------------------------------------------------------
|
|
bool CVertexBufferDx11::IsDynamic() const
|
|
{
|
|
return m_bIsDynamic;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Only used by dynamic buffers, indicates the next lock should perform a discard.
|
|
//-----------------------------------------------------------------------------
|
|
void CVertexBufferDx11::Flush()
|
|
{
|
|
// This strange-looking line makes a flush only occur if the buffer is dynamic.
|
|
m_bFlush = m_bIsDynamic;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Casts a dynamic buffer to be a particular vertex type
|
|
//-----------------------------------------------------------------------------
|
|
void CVertexBufferDx11::BeginCastBuffer( VertexFormat_t format )
|
|
{
|
|
Assert( format != VERTEX_FORMAT_UNKNOWN );
|
|
Assert( m_bIsDynamic && ( m_VertexFormat == VERTEX_FORMAT_UNKNOWN || m_VertexFormat == format ) );
|
|
if ( !m_bIsDynamic )
|
|
return;
|
|
|
|
m_VertexFormat = format;
|
|
m_VertexSize = VertexFormatSize( m_VertexFormat );
|
|
m_nVertexCount = m_nBufferSize / VertexSize();
|
|
}
|
|
|
|
void CVertexBufferDx11::EndCastBuffer()
|
|
{
|
|
Assert( m_bIsDynamic && m_VertexFormat != 0 );
|
|
if ( !m_bIsDynamic )
|
|
return;
|
|
m_VertexFormat = 0;
|
|
m_nVertexCount = 0;
|
|
m_VertexSize = 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the number of indices that can be written into the buffer
|
|
//-----------------------------------------------------------------------------
|
|
int CVertexBufferDx11::GetRoomRemaining() const
|
|
{
|
|
return ( m_nBufferSize - NextLockOffset() ) / VertexSize();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Lock, unlock
|
|
//-----------------------------------------------------------------------------
|
|
bool CVertexBufferDx11::Lock( int nMaxVertexCount, bool bAppend, VertexDesc_t& desc )
|
|
{
|
|
return LockEx( 0, nMaxVertexCount, desc );
|
|
}
|
|
|
|
bool CVertexBufferDx11::LockEx( int nFirstVertex, int nMaxVertexCount, VertexDesc_t &desc )
|
|
{
|
|
Assert( !m_bIsLocked && ( nMaxVertexCount <= m_nVertexCount ) );
|
|
Assert( m_VertexFormat != 0 );
|
|
|
|
// FIXME: Why do we need to sync matrices now?
|
|
ShaderUtil()->SyncMatrices();
|
|
//g_ShaderMutex.Lock();
|
|
|
|
// This can happen if the buffer was locked but a type wasn't bound
|
|
if ( m_VertexFormat == 0 )
|
|
{
|
|
//Log( "No vertex format!\n" );
|
|
goto vertexBufferLockFailed;
|
|
}
|
|
|
|
|
|
// Just give the app crap buffers to fill up while we're suppressed...
|
|
if ( g_pShaderDevice->IsDeactivated() || ( nMaxVertexCount == 0 ) )
|
|
goto vertexBufferLockFailed;
|
|
|
|
// Did we ask for something too large?
|
|
if ( nMaxVertexCount > m_nVertexCount )
|
|
{
|
|
Warning( "Too many vertices for vertex buffer. . tell a programmer (%d>%d)\n", nMaxVertexCount, m_nVertexCount );
|
|
goto vertexBufferLockFailed;
|
|
}
|
|
|
|
// We might not have a buffer owing to alt-tab type stuff
|
|
if ( !m_pVertexBuffer )
|
|
{
|
|
if ( !Allocate() )
|
|
{
|
|
//Log( "Couldn't allocate vertex buffer\n" );
|
|
goto vertexBufferLockFailed;
|
|
}
|
|
|
|
}
|
|
|
|
//Log( "Locking vertex buffer %p\n", m_pVertexBuffer );
|
|
|
|
// Check to see if we have enough memory
|
|
//int nMemoryRequired = nMaxVertexCount * VertexSize();
|
|
|
|
if ( m_bIsDynamic )
|
|
{
|
|
D3D11_MAPPED_SUBRESOURCE lockedData;
|
|
HRESULT hr;
|
|
|
|
D3D11_MAP map;
|
|
|
|
bool bHasEnoughMemory = HasEnoughRoom( nMaxVertexCount );
|
|
|
|
// If we're not appending, no overwrite unless we don't have enough room
|
|
// If we're a static buffer, always discard if we're not appending
|
|
if ( !m_bFlush && bHasEnoughMemory )
|
|
{
|
|
map = ( m_Position == 0 ) ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE;
|
|
}
|
|
else
|
|
{
|
|
map = D3D11_MAP_WRITE_DISCARD;
|
|
m_Position = 0;
|
|
m_bFlush = false;
|
|
}
|
|
|
|
int nLockOffset = NextLockOffset();
|
|
|
|
//goto vertexBufferLockFailed;
|
|
hr = D3D11DeviceContext()->Map( m_pVertexBuffer, 0, map, 0, &lockedData );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
Warning( "Failed to lock vertex buffer in CVertexBufferDx11::Lock\n" );
|
|
goto vertexBufferLockFailed;
|
|
}
|
|
|
|
ComputeVertexDescription( (unsigned char *)lockedData.pData + nLockOffset, m_VertexFormat, desc );
|
|
desc.m_nFirstVertex = nLockOffset / VertexSize();
|
|
desc.m_nOffset = nLockOffset;
|
|
m_bIsLocked = true;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Static vertex buffers
|
|
|
|
bool bHasEnoughMemory = ( nFirstVertex + nMaxVertexCount ) <= m_nVertexCount;
|
|
if ( !bHasEnoughMemory )
|
|
{
|
|
goto vertexBufferLockFailed;
|
|
}
|
|
int nLockOffset;
|
|
if ( nFirstVertex >= 0 )
|
|
nLockOffset = nFirstVertex * VertexSize();
|
|
else
|
|
nLockOffset = m_Position;
|
|
m_Position = nLockOffset;
|
|
// Static vertex buffer case
|
|
ComputeVertexDescription( m_pVertexMemory + nLockOffset, m_VertexFormat, desc );
|
|
desc.m_nFirstVertex = nFirstVertex;
|
|
desc.m_nOffset = nLockOffset;
|
|
m_nVerticesLocked = nMaxVertexCount;
|
|
m_bIsLocked = true;
|
|
return true;
|
|
}
|
|
|
|
|
|
vertexBufferLockFailed:
|
|
g_ShaderMutex.Unlock();
|
|
|
|
// Set up a bogus index descriptor
|
|
ComputeVertexDescription( 0, 0, desc );
|
|
desc.m_nFirstVertex = 0;
|
|
desc.m_nOffset = 0;
|
|
return false;
|
|
}
|
|
|
|
void CVertexBufferDx11::Unlock( int nWrittenVertexCount, VertexDesc_t& desc )
|
|
{
|
|
//Log( "Unlocking vertex buffer %p\n", m_pVertexBuffer );
|
|
Assert( nWrittenVertexCount <= m_nVertexCount );
|
|
|
|
// NOTE: This can happen if the lock occurs during alt-tab
|
|
// or if another application is initializing
|
|
if ( !m_bIsLocked )
|
|
return;
|
|
|
|
if ( m_pVertexBuffer )
|
|
{
|
|
if ( m_bIsDynamic )
|
|
{
|
|
D3D11DeviceContext()->Unmap( m_pVertexBuffer, 0 );
|
|
|
|
int nLockOffset = NextLockOffset();
|
|
int nBufferSize = nWrittenVertexCount * m_VertexSize;
|
|
|
|
m_Position = nLockOffset + nBufferSize;
|
|
}
|
|
else
|
|
{
|
|
D3D11_BOX box;
|
|
box.back = 1;
|
|
box.front = 0;
|
|
box.bottom = 1;
|
|
box.top = 0;
|
|
box.left = m_Position;
|
|
box.right = box.left + ( m_nVerticesLocked * VertexSize() );
|
|
D3D11DeviceContext()->UpdateSubresource( m_pVertexBuffer, 0, &box, m_pVertexMemory + m_Position, 0, 0 );
|
|
|
|
m_Position += m_nVerticesLocked * VertexSize();
|
|
}
|
|
|
|
}
|
|
|
|
//Spew( nWrittenVertexCount, desc );
|
|
|
|
m_bIsLocked = false;
|
|
//g_ShaderMutex.Unlock();
|
|
}
|
|
|
|
unsigned char *CVertexBufferDx11::Modify( bool bReadOnly, int nFirstVertex, int nVertexCount )
|
|
{
|
|
if ( nVertexCount == 0 )
|
|
return NULL;
|
|
|
|
Assert( m_pVertexBuffer && !m_bIsDynamic );
|
|
|
|
if ( nFirstVertex + nVertexCount > m_nVertexCount )
|
|
{
|
|
Assert( 0 );
|
|
return NULL;
|
|
}
|
|
|
|
unsigned char *pData = m_pVertexMemory + ( nFirstVertex * m_VertexSize );
|
|
m_nVerticesLocked = nVertexCount;
|
|
|
|
m_Position = nFirstVertex * m_VertexSize;
|
|
m_bIsLocked = true;
|
|
|
|
return pData;
|
|
} |