fix: vertex buffer leaks

This commit is contained in:
Samuliak 2024-08-11 14:17:40 +02:00
parent caba20da4b
commit c6ab45a098
5 changed files with 30 additions and 27 deletions

View File

@ -1,5 +1,9 @@
#pragma once
#include <Metal/Metal.hpp>
constexpr size_t INVALID_OFFSET = std::numeric_limits<size_t>::max();
inline size_t Align(size_t size, size_t alignment)
{
return (size + alignment - 1) & ~(alignment - 1);

View File

@ -70,11 +70,11 @@ MetalVertexBufferCache::~MetalVertexBufferCache()
for (uint32 i = 0; i < LATTE_MAX_VERTEX_BUFFERS; i++)
{
auto vertexBufferRange = m_bufferRanges[i];
if (vertexBufferRange)
if (vertexBufferRange.offset != INVALID_OFFSET)
{
if (vertexBufferRange->restrideInfo.buffer)
if (vertexBufferRange.restrideInfo->buffer)
{
vertexBufferRange->restrideInfo.buffer->release();
vertexBufferRange.restrideInfo->buffer->release();
}
}
}
@ -83,29 +83,30 @@ MetalVertexBufferCache::~MetalVertexBufferCache()
MetalRestridedBufferRange MetalVertexBufferCache::RestrideBufferIfNeeded(MTL::Buffer* bufferCache, uint32 bufferIndex, size_t stride)
{
auto vertexBufferRange = m_bufferRanges[bufferIndex];
auto& restrideInfo = vertexBufferRange->restrideInfo;
auto& restrideInfo = *vertexBufferRange.restrideInfo;
if (stride % 4 == 0)
{
// No restride needed
return {bufferCache, vertexBufferRange->offset};
return {bufferCache, vertexBufferRange.offset};
}
if (restrideInfo.memoryInvalidated || stride != restrideInfo.lastStride)
{
// TODO: use compute/void vertex function instead
size_t newStride = Align(stride, 4);
size_t newSize = vertexBufferRange->size / stride * newStride;
size_t newSize = vertexBufferRange.size / stride * newStride;
restrideInfo.buffer = m_mtlr->GetDevice()->newBuffer(newSize, MTL::StorageModeShared);
uint8* oldPtr = (uint8*)bufferCache->contents() + vertexBufferRange->offset;
uint8* oldPtr = (uint8*)bufferCache->contents() + vertexBufferRange.offset;
uint8* newPtr = (uint8*)restrideInfo.buffer->contents();
for (size_t elem = 0; elem < vertexBufferRange->size / stride; elem++)
for (size_t elem = 0; elem < vertexBufferRange.size / stride; elem++)
{
memcpy(newPtr + elem * newStride, oldPtr + elem * stride, stride);
}
debug_printf("Restrided vertex buffer (old stride: %zu, new stride: %zu, old size: %zu, new size: %zu)\n", stride, newStride, vertexBufferRange->size, newSize);
// TODO: remove
debug_printf("Restrided vertex buffer (old stride: %zu, new stride: %zu, old size: %zu, new size: %zu)\n", stride, newStride, vertexBufferRange.size, newSize);
restrideInfo.memoryInvalidated = false;
restrideInfo.lastStride = newStride;
@ -119,15 +120,15 @@ void MetalVertexBufferCache::MemoryRangeChanged(size_t offset, size_t size)
for (uint32 i = 0; i < LATTE_MAX_VERTEX_BUFFERS; i++)
{
auto vertexBufferRange = m_bufferRanges[i];
if (vertexBufferRange)
if (vertexBufferRange.offset != INVALID_OFFSET)
{
if ((offset < vertexBufferRange->offset && (offset + size) < (vertexBufferRange->offset + vertexBufferRange->size)) ||
(offset > vertexBufferRange->offset && (offset + size) > (vertexBufferRange->offset + vertexBufferRange->size)))
if ((offset < vertexBufferRange.offset && (offset + size) < (vertexBufferRange.offset + vertexBufferRange.size)) ||
(offset > vertexBufferRange.offset && (offset + size) > (vertexBufferRange.offset + vertexBufferRange.size)))
{
continue;
}
vertexBufferRange->restrideInfo.memoryInvalidated = true;
vertexBufferRange.restrideInfo->memoryInvalidated = true;
}
}
}

View File

@ -1,9 +1,8 @@
#pragma once
#include <Metal/Metal.hpp>
#include "Cafe/HW/Latte/ISA/LatteReg.h"
#include "Cafe/HW/Latte/Core/LatteConst.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
//const uint32 bufferAllocatorIndexShift = 24;
@ -68,9 +67,9 @@ struct MetalRestrideInfo
struct MetalVertexBufferRange
{
size_t offset;
size_t offset = INVALID_OFFSET;
size_t size;
MetalRestrideInfo& restrideInfo;
MetalRestrideInfo* restrideInfo;
};
class MetalVertexBufferCache
@ -82,19 +81,19 @@ public:
~MetalVertexBufferCache();
// Vertex buffer cache
void TrackVertexBuffer(uint32 bufferIndex, size_t offset, size_t size, MetalRestrideInfo& restrideInfo)
void TrackVertexBuffer(uint32 bufferIndex, size_t offset, size_t size, MetalRestrideInfo* restrideInfo)
{
m_bufferRanges[bufferIndex] = new MetalVertexBufferRange{offset, size, restrideInfo};
m_bufferRanges[bufferIndex] = MetalVertexBufferRange{offset, size, restrideInfo};
}
void UntrackVertexBuffer(uint32 bufferIndex)
{
auto& range = m_bufferRanges[bufferIndex];
if (range->restrideInfo.buffer)
if (range.restrideInfo->buffer)
{
range->restrideInfo.buffer->release();
range.restrideInfo->buffer->release();
}
range = nullptr;
range.offset = INVALID_OFFSET;
}
MetalRestridedBufferRange RestrideBufferIfNeeded(MTL::Buffer* bufferCache, uint32 bufferIndex, size_t stride);
@ -102,7 +101,7 @@ public:
private:
class MetalRenderer* m_mtlr;
MetalVertexBufferRange* m_bufferRanges[LATTE_MAX_VERTEX_BUFFERS] = {nullptr};
MetalVertexBufferRange m_bufferRanges[LATTE_MAX_VERTEX_BUFFERS] = {};
void MemoryRangeChanged(size_t offset, size_t size);
};
@ -147,7 +146,7 @@ public:
void CopyBufferCache(size_t srcOffset, size_t dstOffset, size_t size);
// Vertex buffer cache
void TrackVertexBuffer(uint32 bufferIndex, size_t offset, size_t size, MetalRestrideInfo& restrideInfo)
void TrackVertexBuffer(uint32 bufferIndex, size_t offset, size_t size, MetalRestrideInfo* restrideInfo)
{
m_vertexBufferCache.TrackVertexBuffer(bufferIndex, offset, size, restrideInfo);
}

View File

@ -77,6 +77,7 @@ void MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow)
m_metalLayer = (CA::MetalLayer*)CreateMetalLayer(windowInfo.handle);
m_metalLayer->setDevice(m_device);
// TODO: don't always force sRGB
// TODO: shouldn't this be handled differently?
m_metalLayer->setPixelFormat(MTL::PixelFormatRGBA8Unorm_sRGB);
@ -476,7 +477,7 @@ void MetalRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, u
buffer.size = size;
buffer.restrideInfo = {};
m_memoryManager->TrackVertexBuffer(bufferIndex, offset, size, buffer.restrideInfo);
m_memoryManager->TrackVertexBuffer(bufferIndex, offset, size, &buffer.restrideInfo);
}
void MetalRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size)

View File

@ -16,8 +16,6 @@
#define MAX_MTL_TEXTURES 31
#define MAX_MTL_SAMPLERS 16
constexpr size_t INVALID_OFFSET = std::numeric_limits<size_t>::max();
struct MetalBoundBuffer
{
bool needsRebind = false;