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

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;
}