VertexCache: enforce cache alignment without read beyond buffer boundary during allocation and update

This commit is contained in:
Stephen Saunders 2023-12-12 18:51:50 -05:00 committed by Robert Beckebans
parent 341b90bc05
commit ad046923f5
4 changed files with 50 additions and 43 deletions

View file

@ -661,7 +661,7 @@ void idInteraction::CreateStaticInteraction( nvrhi::ICommandList* commandList )
{
// make a static index cache
sint->numLightTrisIndexes = lightTris->numIndexes;
sint->lightTrisIndexCache = vertexCache.AllocStaticIndex( lightTris->indexes, ALIGN( lightTris->numIndexes * sizeof( lightTris->indexes[0] ), INDEX_CACHE_ALIGN ), commandList );
sint->lightTrisIndexCache = vertexCache.AllocStaticIndex( lightTris->indexes, lightTris->numIndexes * sizeof( lightTris->indexes[0] ), commandList );
interactionGenerated = true;
R_FreeStaticTriSurf( lightTris );

View file

@ -30,6 +30,9 @@ If you have questions concerning this license or the applicable additional terms
#include "precompiled.h"
#pragma hdrstop
#include "../RenderCommon.h"
#include "../VertexCache.h"
extern idVertexCache vertexCache;
#include "sys/DeviceManager.h"
@ -185,24 +188,23 @@ bool idVertexBuffer::AllocBufferObject( const void* data, int allocSize, bufferU
idLib::Error( "idVertexBuffer::AllocBufferObject: allocSize = %i", allocSize );
}
size = allocSize;
size = ALIGN( allocSize, VERTEX_CACHE_ALIGN );
usage = _usage;
int numBytes = GetAllocedSize();
const int numBytes = GetAllocedSize();
nvrhi::BufferDesc vertexBufferDesc;
vertexBufferDesc.byteSize = numBytes;
vertexBufferDesc.isVertexBuffer = true;
vertexBufferDesc.initialState = nvrhi::ResourceStates::CopyDest;
if( usage == BU_DYNAMIC )
{
vertexBufferDesc.initialState = nvrhi::ResourceStates::CopyDest;
vertexBufferDesc.cpuAccess = nvrhi::CpuAccessMode::Write;
vertexBufferDesc.debugName = "Mapped idDrawVert vertex buffer";
}
else
{
vertexBufferDesc.initialState = nvrhi::ResourceStates::CopyDest;
vertexBufferDesc.keepInitialState = true;
vertexBufferDesc.debugName = "Static idDrawVert vertex buffer";
}
@ -307,14 +309,15 @@ void idVertexBuffer::Update( const void* data, int updateSize, int offset, bool
assert( bufferHandle );
assert_16_byte_aligned( data );
assert( ( GetOffset() & 15 ) == 0 );
assert( ( offset & VERTEX_CACHE_ALIGN - 1 ) == 0 );
if( updateSize > GetSize() )
const int numBytes = ( updateSize + 15 ) & ~15;
if( offset + numBytes > GetSize() )
{
idLib::FatalError( "idVertexBuffer::Update: size overrun, %i > %i\n", updateSize, GetSize() );
idLib::FatalError( "idVertexBuffer::Update: size overrun, %i + %i > %i\n", offset, numBytes, GetSize() );
}
int numBytes = ( updateSize + 15 ) & ~15;
if( usage == BU_DYNAMIC )
{
assert( IsMapped() );
@ -450,10 +453,10 @@ bool idIndexBuffer::AllocBufferObject( const void* data, int allocSize, bufferUs
idLib::Error( "idIndexBuffer::AllocBufferObject: allocSize = %i", allocSize );
}
size = allocSize;
size = ALIGN( allocSize, INDEX_CACHE_ALIGN );
usage = _usage;
int numBytes = GetAllocedSize();
const int numBytes = GetAllocedSize();
nvrhi::BufferDesc indexBufferDesc;
indexBufferDesc.byteSize = numBytes;
@ -573,14 +576,15 @@ void idIndexBuffer::Update( const void* data, int updateSize, int offset, bool i
assert( bufferHandle );
assert_16_byte_aligned( data );
assert( ( GetOffset() & 15 ) == 0 );
if( updateSize > GetSize() )
{
idLib::FatalError( "idIndexBuffer::Update: size overrun, %i > %i\n", updateSize, GetSize() );
}
assert( ( offset & INDEX_CACHE_ALIGN - 1 ) == 0 );
const int numBytes = ( updateSize + 15 ) & ~15;
if( offset + numBytes > GetSize() )
{
idLib::FatalError( "idIndexBuffer::Update: size overrun, %i + %i > %i\n", offset, numBytes, GetSize() );
}
if( usage == BU_DYNAMIC )
{
assert( IsMapped() );
@ -717,7 +721,7 @@ bool idUniformBuffer::AllocBufferObject( const void* data, int allocSize, buffer
idLib::Error( "idUniformBuffer::AllocBufferObject: allocSize = %i", allocSize );
}
size = allocSize;
size = ALIGN( allocSize, vertexCache.uniformBufferOffsetAlignment );
usage = allocatedUsage;
const int numBytes = GetAllocedSize();
@ -725,14 +729,9 @@ bool idUniformBuffer::AllocBufferObject( const void* data, int allocSize, buffer
// This buffer is a shader resource as opposed to a constant buffer due to
// constant buffers not being able to be sub-ranged.
nvrhi::BufferDesc bufferDesc;
//bufferDesc.initialState = nvrhi::ResourceStates::ConstantBuffer; // SRS - shouldn't this be initialized to CopyDest?
bufferDesc.initialState = nvrhi::ResourceStates::CopyDest;
//bufferDesc.keepInitialState = true; // SRS - shouldn't this be set for BU_STATIC only?
bufferDesc.canHaveTypedViews = true;
bufferDesc.canHaveRawViews = true;
bufferDesc.byteSize = numBytes;
bufferDesc.structStride = sizeof( idVec4 );
bufferDesc.isConstantBuffer = true;
bufferDesc.structStride = sizeof( idVec4 ); // SRS - this defines a structured storage buffer vs. a constant buffer
bufferDesc.initialState = nvrhi::ResourceStates::Common;
if( usage == BU_DYNAMIC )
{
@ -845,14 +844,15 @@ void idUniformBuffer::Update( const void* data, int updateSize, int offset, bool
assert( bufferHandle );
assert_16_byte_aligned( data );
assert( ( GetOffset() & 15 ) == 0 );
assert( ( offset & vertexCache.uniformBufferOffsetAlignment - 1 ) == 0 );
if( updateSize > GetSize() )
const int numBytes = ( updateSize + 15 ) & ~15;
if( offset + numBytes > GetSize() )
{
idLib::FatalError( "idUniformBuffer::Update: size overrun, %i > %i\n", updateSize, GetSize() );
idLib::FatalError( "idUniformBuffer::Update: size overrun, %i + %i > %i\n", offset, numBytes, GetSize() );
}
int numBytes = ( updateSize + 15 ) & ~15;
if( usage == BU_DYNAMIC )
{
assert( IsMapped() );

View file

@ -215,7 +215,8 @@ vertCacheHandle_t idVertexCache::ActuallyAlloc( geoBufferSet_t& vcs, const void*
assert( ( ( ( uintptr_t )( data ) ) & 15 ) == 0 );
// RB end
assert( ( bytes & 15 ) == 0 );
// SRS - enforce cache alignment without read beyond boundary for each cache type below
//assert( ( bytes & 15 ) == 0 );
int endPos = 0;
int offset = 0;
@ -224,13 +225,15 @@ vertCacheHandle_t idVertexCache::ActuallyAlloc( geoBufferSet_t& vcs, const void*
{
case CACHE_INDEX:
{
endPos = vcs.indexMemUsed.Add( bytes );
// SRS - calculate alignedBytes retaining original to prevent read beyond data boundary during update
int alignedBytes = ALIGN( bytes, INDEX_CACHE_ALIGN );
endPos = vcs.indexMemUsed.Add( alignedBytes );
if( endPos > vcs.indexBuffer.GetAllocedSize() )
{
idLib::Error( "Out of index cache" );
}
offset = endPos - bytes;
offset = endPos - alignedBytes;
if( data != NULL )
{
@ -245,13 +248,15 @@ vertCacheHandle_t idVertexCache::ActuallyAlloc( geoBufferSet_t& vcs, const void*
}
case CACHE_VERTEX:
{
endPos = vcs.vertexMemUsed.Add( bytes );
// SRS - calculate alignedBytes retaining original to prevent read beyond data boundary during update
int alignedBytes = ALIGN( bytes, VERTEX_CACHE_ALIGN );
endPos = vcs.vertexMemUsed.Add( alignedBytes );
if( endPos > vcs.vertexBuffer.GetAllocedSize() )
{
idLib::Error( "Out of vertex cache" );
}
offset = endPos - bytes;
offset = endPos - alignedBytes;
if( data != NULL )
{
@ -266,13 +271,15 @@ vertCacheHandle_t idVertexCache::ActuallyAlloc( geoBufferSet_t& vcs, const void*
}
case CACHE_JOINT:
{
endPos = vcs.jointMemUsed.Add( bytes );
// SRS - calculate alignedBytes retaining original to prevent read beyond data boundary during update
int alignedBytes = ALIGN( bytes, uniformBufferOffsetAlignment );
endPos = vcs.jointMemUsed.Add( alignedBytes );
if( endPos > vcs.jointBuffer.GetAllocedSize() )
{
idLib::Error( "Out of joint buffer cache" );
}
offset = endPos - bytes;
offset = endPos - alignedBytes;
if( data != NULL )
{
@ -308,7 +315,7 @@ idVertexCache::AllocVertex
*/
vertCacheHandle_t idVertexCache::AllocVertex( const void* data, int num, size_t size /*= sizeof( idDrawVert ) */, nvrhi::ICommandList* commandList )
{
return ActuallyAlloc( frameData[ listNum ], data, ALIGN( num * size, VERTEX_CACHE_ALIGN ), CACHE_VERTEX, commandList );
return ActuallyAlloc( frameData[ listNum ], data, num * size, CACHE_VERTEX, commandList );
}
/*
@ -318,7 +325,7 @@ idVertexCache::AllocIndex
*/
vertCacheHandle_t idVertexCache::AllocIndex( const void* data, int num, size_t size /*= sizeof( triIndex_t ) */, nvrhi::ICommandList* commandList )
{
return ActuallyAlloc( frameData[ listNum ], data, ALIGN( num * size, INDEX_CACHE_ALIGN ), CACHE_INDEX, commandList );
return ActuallyAlloc( frameData[ listNum ], data, num * size, CACHE_INDEX, commandList );
}
/*
@ -328,7 +335,7 @@ idVertexCache::AllocJoint
*/
vertCacheHandle_t idVertexCache::AllocJoint( const void* data, int num, size_t size /*= sizeof( idJointMat ) */, nvrhi::ICommandList* commandList )
{
return ActuallyAlloc( frameData[ listNum ], data, ALIGN( num * size, uniformBufferOffsetAlignment ), CACHE_JOINT, commandList );
return ActuallyAlloc( frameData[ listNum ], data, num * size, CACHE_JOINT, commandList );
}
/*

View file

@ -1819,8 +1819,8 @@ Uploads static vertices to the vertex cache.
*/
void R_CreateDeformStaticVertices( deformInfo_t* deform, nvrhi::ICommandList* commandList )
{
deform->staticAmbientCache = vertexCache.AllocStaticVertex( deform->verts, ALIGN( deform->numOutputVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ), commandList );
deform->staticIndexCache = vertexCache.AllocStaticIndex( deform->indexes, ALIGN( deform->numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ), commandList );
deform->staticAmbientCache = vertexCache.AllocStaticVertex( deform->verts, deform->numOutputVerts * sizeof( idDrawVert ), commandList );
deform->staticIndexCache = vertexCache.AllocStaticIndex( deform->indexes, deform->numIndexes * sizeof( triIndex_t ), commandList );
}
/*
@ -1948,13 +1948,13 @@ void R_CreateStaticBuffersForTri( srfTriangles_t& tri, nvrhi::ICommandList* comm
// index cache
if( tri.indexes != NULL )
{
tri.indexCache = vertexCache.AllocStaticIndex( tri.indexes, ALIGN( tri.numIndexes * sizeof( tri.indexes[0] ), INDEX_CACHE_ALIGN ), commandList );
tri.indexCache = vertexCache.AllocStaticIndex( tri.indexes, tri.numIndexes * sizeof( tri.indexes[0] ), commandList );
}
// vertex cache
if( tri.verts != NULL )
{
tri.ambientCache = vertexCache.AllocStaticVertex( tri.verts, ALIGN( tri.numVerts * sizeof( tri.verts[0] ), VERTEX_CACHE_ALIGN ), commandList );
tri.ambientCache = vertexCache.AllocStaticVertex( tri.verts, tri.numVerts * sizeof( tri.verts[0] ), commandList );
}
}
@ -2128,4 +2128,4 @@ idVec3 R_ClosestPointPointTriangle( const idVec3& point, const idVec3& vertex1,
result = vertex1 + ab * v2 + ac * w2; //= u*vertex1 + v*vertex2 + w*vertex3, u = va * denom = 1.0f - v - w
return result;
}
}