Files
Totterynine 2773eae4d7 shaderapidx11
use -dxlevel 110 to use it
2021-09-22 18:56:56 +05:00

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 )
{
}