mirror of
https://github.com/celisej567/cool-source-archive.git
synced 2026-09-15 20:09:19 +03:00
458 lines
12 KiB
C++
458 lines
12 KiB
C++
// HUH???
|
|
#define RAD_TELEMETRY_DISABLED
|
|
|
|
#include "IndexBufferDx11.h"
|
|
#include "shaderapidx9/locald3dtypes.h"
|
|
#include "shaderapidx11_global.h"
|
|
#include "shaderdevicedx11.h"
|
|
#include "shaderapi/ishaderutil.h"
|
|
#include "tier0/vprof.h"
|
|
|
|
// NOTE: This has to be the last file included!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Dx11 implementation of an index buffer
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// globals
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// shove indices into this if you don't actually want indices
|
|
static unsigned int s_nScratchIndexBuffer = 0;
|
|
|
|
#ifdef _DEBUG
|
|
int CIndexBufferDx11::s_nBufferCount = 0;
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// constructor, destructor
|
|
//-----------------------------------------------------------------------------
|
|
CIndexBufferDx11::CIndexBufferDx11( ShaderBufferType_t type, MaterialIndexFormat_t fmt, int nIndexCount, const char* pBudgetGroupName ) :
|
|
BaseClass( pBudgetGroupName )
|
|
{
|
|
// NOTE: MATERIAL_INDEX_FORMAT_UNKNOWN can't be dealt with under dx9
|
|
// because format is bound at buffer creation time. What we'll do
|
|
// is just arbitrarily choose to use a 16-bit index buffer of the same size
|
|
if ( fmt == MATERIAL_INDEX_FORMAT_UNKNOWN )
|
|
{
|
|
fmt = MATERIAL_INDEX_FORMAT_16BIT;
|
|
nIndexCount /= 2;
|
|
}
|
|
|
|
//Assert( nIndexCount != 0 );
|
|
Assert( IsDynamicBufferType( type ) || ( fmt != MATERIAL_INDEX_FORMAT_UNKNOWN ) );
|
|
|
|
m_pIndexMemory = NULL;
|
|
m_pIndexBuffer = NULL;
|
|
m_IndexFormat = fmt;
|
|
m_nIndexSize = SizeForIndex( fmt );
|
|
m_nIndexCount = nIndexCount;
|
|
m_nBufferSize = nIndexCount * m_nIndexSize;
|
|
m_Position = 0;
|
|
m_bIsLocked = false;
|
|
m_bIsDynamic = IsDynamicBufferType( type );
|
|
m_nIndicesLocked = 0;
|
|
m_bFlush = false;
|
|
|
|
#ifdef _DEBUG
|
|
m_pShadowIndices = new unsigned short[m_nIndexCount];
|
|
m_NumIndices = nIndexCount;
|
|
#endif
|
|
|
|
// NOTE: This has to happen at the end since m_IndexFormat must be valid for IndexSize() to work
|
|
//if ( m_bIsDynamic )
|
|
//{
|
|
// m_IndexFormat = MATERIAL_INDEX_FORMAT_UNKNOWN;
|
|
// m_nIndexCount = 0;
|
|
//}
|
|
}
|
|
|
|
CIndexBufferDx11::~CIndexBufferDx11()
|
|
{
|
|
#ifdef _DEBUG
|
|
if ( m_pShadowIndices )
|
|
{
|
|
delete[] m_pShadowIndices;
|
|
m_pShadowIndices = NULL;
|
|
}
|
|
#endif
|
|
Free();
|
|
}
|
|
|
|
bool CIndexBufferDx11::HasEnoughRoom( int nIndexCount ) const
|
|
{
|
|
return ( GetRoomRemaining() - nIndexCount ) >= 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates, destroys the index buffer
|
|
//-----------------------------------------------------------------------------
|
|
bool CIndexBufferDx11::Allocate()
|
|
{
|
|
Assert( !m_pIndexBuffer );
|
|
|
|
if ( !m_bIsDynamic )
|
|
{
|
|
m_pIndexMemory = (unsigned char *)malloc( m_nBufferSize );
|
|
memset( m_pIndexMemory, 0, m_nBufferSize );
|
|
}
|
|
else
|
|
{
|
|
m_pIndexMemory = NULL;
|
|
}
|
|
|
|
m_Position = 0;
|
|
|
|
//Log( "Creating D3D index buffer: size: %i\n", m_nBufferSize );
|
|
|
|
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_INDEX_BUFFER;
|
|
|
|
bd.MiscFlags = 0;
|
|
|
|
HRESULT hr = D3D11Device()->CreateBuffer( &bd, NULL, &m_pIndexBuffer );
|
|
bool bOk = !FAILED( hr ) && ( m_pIndexBuffer != NULL );
|
|
|
|
if ( bOk )
|
|
{
|
|
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 );
|
|
}
|
|
#ifdef _DEBUG
|
|
++s_nBufferCount;
|
|
#endif
|
|
}
|
|
|
|
return bOk;
|
|
}
|
|
|
|
void CIndexBufferDx11::Free()
|
|
{
|
|
if ( m_pIndexBuffer )
|
|
{
|
|
#ifdef _DEBUG
|
|
--s_nBufferCount;
|
|
#endif
|
|
|
|
m_pIndexBuffer->Release();
|
|
m_pIndexBuffer = 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_pIndexMemory )
|
|
{
|
|
free( m_pIndexMemory );
|
|
m_pIndexMemory = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the buffer size (only valid for static index buffers)
|
|
//-----------------------------------------------------------------------------
|
|
int CIndexBufferDx11::IndexCount() const
|
|
{
|
|
//Assert( !m_bIsDynamic );
|
|
return m_nIndexCount;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the buffer format (only valid for static index buffers)
|
|
//-----------------------------------------------------------------------------
|
|
MaterialIndexFormat_t CIndexBufferDx11::IndexFormat() const
|
|
{
|
|
//Assert( !m_bIsDynamic );
|
|
return m_IndexFormat;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns true if the buffer is dynamic
|
|
//-----------------------------------------------------------------------------
|
|
bool CIndexBufferDx11::IsDynamic() const
|
|
{
|
|
return m_bIsDynamic;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Only used by dynamic buffers, indicates the next lock should perform a discard.
|
|
//-----------------------------------------------------------------------------
|
|
void CIndexBufferDx11::Flush()
|
|
{
|
|
// This strange-looking line makes a flush only occur if the buffer is dynamic.
|
|
m_bFlush = m_bIsDynamic;
|
|
}
|
|
|
|
int CIndexBufferDx11::SizeForIndex( MaterialIndexFormat_t fmt ) const
|
|
{
|
|
switch ( fmt )
|
|
{
|
|
default:
|
|
case MATERIAL_INDEX_FORMAT_UNKNOWN:
|
|
return 0;
|
|
case MATERIAL_INDEX_FORMAT_16BIT:
|
|
return 2;
|
|
case MATERIAL_INDEX_FORMAT_32BIT:
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Casts a dynamic buffer to be a particular index type
|
|
//-----------------------------------------------------------------------------
|
|
void CIndexBufferDx11::BeginCastBuffer( MaterialIndexFormat_t format )
|
|
{
|
|
Assert( format != MATERIAL_INDEX_FORMAT_UNKNOWN );
|
|
Assert( m_bIsDynamic && ( m_IndexFormat == MATERIAL_INDEX_FORMAT_UNKNOWN || m_IndexFormat == format ) );
|
|
if ( !m_bIsDynamic )
|
|
return;
|
|
|
|
m_IndexFormat = format;
|
|
m_nIndexSize = SizeForIndex( m_IndexFormat );
|
|
m_nIndexCount = m_nBufferSize / IndexSize();
|
|
}
|
|
|
|
void CIndexBufferDx11::EndCastBuffer()
|
|
{
|
|
Assert( m_bIsDynamic && m_IndexFormat != MATERIAL_INDEX_FORMAT_UNKNOWN );
|
|
if ( !m_bIsDynamic )
|
|
return;
|
|
m_IndexFormat = MATERIAL_INDEX_FORMAT_UNKNOWN;
|
|
m_nIndexCount = 0;
|
|
m_nIndexSize = 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the number of indices that can be written into the buffer
|
|
//-----------------------------------------------------------------------------
|
|
int CIndexBufferDx11::GetRoomRemaining() const
|
|
{
|
|
return ( m_nBufferSize - m_Position ) / IndexSize();
|
|
}
|
|
|
|
bool CIndexBufferDx11::LockEx( int nFirstIndex, int nMaxIndexCount, IndexDesc_t &desc )
|
|
{
|
|
Assert( !m_bIsLocked && ( nMaxIndexCount <= m_nIndexCount ) );
|
|
Assert( m_IndexFormat != MATERIAL_INDEX_FORMAT_UNKNOWN );
|
|
|
|
// 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_IndexFormat == MATERIAL_INDEX_FORMAT_UNKNOWN )
|
|
goto indexBufferLockFailed;
|
|
|
|
// Just give the app crap buffers to fill up while we're suppressed...
|
|
if ( g_pShaderDevice->IsDeactivated() || ( nMaxIndexCount == 0 ) )
|
|
goto indexBufferLockFailed;
|
|
|
|
// Did we ask for something too large?
|
|
if ( nMaxIndexCount > m_nIndexCount )
|
|
{
|
|
Warning( "Too many indices for index buffer. . tell a programmer (%d>%d)\n", nMaxIndexCount, m_nIndexCount );
|
|
//DebuggerBreak();
|
|
goto indexBufferLockFailed;
|
|
}
|
|
|
|
// We might not have a buffer owing to alt-tab type stuff
|
|
if ( !m_pIndexBuffer )
|
|
{
|
|
if ( !Allocate() )
|
|
goto indexBufferLockFailed;
|
|
}
|
|
|
|
//Log( "Locking index buffer %p\n", m_pIndexBuffer );
|
|
|
|
if ( m_bIsDynamic )
|
|
{
|
|
// Check to see if we have enough memory
|
|
int nMemoryRequired = nMaxIndexCount * IndexSize();
|
|
bool bHasEnoughMemory = ( m_Position + nMemoryRequired <= m_nBufferSize );
|
|
|
|
D3D11_MAPPED_SUBRESOURCE lockedData;
|
|
HRESULT hr;
|
|
|
|
D3D11_MAP map;
|
|
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;
|
|
}
|
|
|
|
//goto indexBufferLockFailed;
|
|
hr = D3D11DeviceContext()->Map( m_pIndexBuffer, 0, map, 0, &lockedData );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
Warning( "Failed to lock index buffer in CIndexBufferDx11::Lock\n" );
|
|
goto indexBufferLockFailed;
|
|
}
|
|
//Log( "LOcking index buffer at %i\n", m_Position );
|
|
desc.m_pIndices = (unsigned short *)( (unsigned char *)lockedData.pData + m_Position );
|
|
desc.m_nIndexSize = IndexSize() >> 1;
|
|
desc.m_nOffset = m_Position;
|
|
desc.m_nFirstIndex = desc.m_nOffset / IndexSize();
|
|
#ifdef _DEBUG
|
|
m_LockedStartIndex = desc.m_nFirstIndex;
|
|
m_LockedNumIndices = nMaxIndexCount;
|
|
#endif
|
|
m_bIsLocked = true;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Static index buffer case
|
|
// Check to see if we have enough memory
|
|
int nOffset;
|
|
if ( nFirstIndex >= 0 )
|
|
nOffset = nFirstIndex * IndexSize();
|
|
else
|
|
nOffset = m_Position;
|
|
int nMemoryRequired = nMaxIndexCount * IndexSize();
|
|
bool bHasEnoughMemory = ( nOffset + nMemoryRequired <= m_nBufferSize );
|
|
|
|
if ( !bHasEnoughMemory )
|
|
{
|
|
goto indexBufferLockFailed;
|
|
}
|
|
|
|
m_Position = nOffset;
|
|
|
|
desc.m_pIndices = (unsigned short *)( m_pIndexMemory + nOffset );
|
|
|
|
desc.m_nIndexSize = IndexSize() >> 1;
|
|
desc.m_nOffset = nOffset;
|
|
desc.m_nFirstIndex = desc.m_nOffset / IndexSize();
|
|
|
|
m_nIndicesLocked = nMaxIndexCount;
|
|
m_bIsLocked = true;
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
indexBufferLockFailed:
|
|
g_ShaderMutex.Unlock();
|
|
|
|
// Set up a bogus index descriptor
|
|
desc.m_pIndices = (unsigned short *)( &s_nScratchIndexBuffer );
|
|
desc.m_nFirstIndex = 0;
|
|
desc.m_nIndexSize = 0;
|
|
desc.m_nOffset = 0;
|
|
return false;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Locks, unlocks the mesh
|
|
//-----------------------------------------------------------------------------
|
|
bool CIndexBufferDx11::Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t &desc )
|
|
{
|
|
return LockEx( 0, nMaxIndexCount, desc );
|
|
}
|
|
|
|
void CIndexBufferDx11::Unlock( int nWrittenIndexCount, IndexDesc_t& desc )
|
|
{
|
|
//Log( "Unlocking index buffer %p\n", m_pIndexBuffer );
|
|
Assert( nWrittenIndexCount <= m_nIndexCount );
|
|
|
|
//Log( "Wrote %i indices\n", nWrittenIndexCount );
|
|
|
|
// NOTE: This can happen if the lock occurs during alt-tab
|
|
// or if another application is initializing
|
|
if ( !m_bIsLocked )
|
|
return;
|
|
|
|
//Spew( nWrittenIndexCount, desc );
|
|
if ( m_pIndexBuffer )
|
|
{
|
|
if ( m_bIsDynamic )
|
|
{
|
|
D3D11DeviceContext()->Unmap( m_pIndexBuffer, 0 );
|
|
m_Position += nWrittenIndexCount * IndexSize();
|
|
}
|
|
else
|
|
{
|
|
// Static vertex buffers
|
|
D3D11_BOX box;
|
|
box.back = 1;
|
|
box.front = 0;
|
|
box.bottom = 1;
|
|
box.top = 0;
|
|
box.left = m_Position;
|
|
box.right = box.left + ( m_nIndicesLocked * IndexSize() );
|
|
D3D11DeviceContext()->UpdateSubresource( m_pIndexBuffer, 0, &box, m_pIndexMemory + m_Position, 0, 0 );
|
|
m_Position += m_nIndicesLocked * IndexSize();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
m_LockedStartIndex = 0;
|
|
m_LockedNumIndices = 0;
|
|
#endif
|
|
|
|
//Log( "Unlock index buffer: just wrote %i indices\n", nWrittenIndexCount );
|
|
|
|
|
|
m_bIsLocked = false;
|
|
g_ShaderMutex.Unlock();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Locks, unlocks an existing mesh
|
|
//-----------------------------------------------------------------------------
|
|
void CIndexBufferDx11::ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc )
|
|
{
|
|
Assert( 0 );
|
|
}
|
|
|
|
void CIndexBufferDx11::ModifyEnd( IndexDesc_t& desc )
|
|
{
|
|
|
|
} |