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 #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) inline size_t Align(size_t size, size_t alignment)
{ {
return (size + alignment - 1) & ~(alignment - 1); return (size + alignment - 1) & ~(alignment - 1);

View File

@ -70,11 +70,11 @@ MetalVertexBufferCache::~MetalVertexBufferCache()
for (uint32 i = 0; i < LATTE_MAX_VERTEX_BUFFERS; i++) for (uint32 i = 0; i < LATTE_MAX_VERTEX_BUFFERS; i++)
{ {
auto vertexBufferRange = m_bufferRanges[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) MetalRestridedBufferRange MetalVertexBufferCache::RestrideBufferIfNeeded(MTL::Buffer* bufferCache, uint32 bufferIndex, size_t stride)
{ {
auto vertexBufferRange = m_bufferRanges[bufferIndex]; auto vertexBufferRange = m_bufferRanges[bufferIndex];
auto& restrideInfo = vertexBufferRange->restrideInfo; auto& restrideInfo = *vertexBufferRange.restrideInfo;
if (stride % 4 == 0) if (stride % 4 == 0)
{ {
// No restride needed // No restride needed
return {bufferCache, vertexBufferRange->offset}; return {bufferCache, vertexBufferRange.offset};
} }
if (restrideInfo.memoryInvalidated || stride != restrideInfo.lastStride) if (restrideInfo.memoryInvalidated || stride != restrideInfo.lastStride)
{ {
// TODO: use compute/void vertex function instead // TODO: use compute/void vertex function instead
size_t newStride = Align(stride, 4); 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); 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(); 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); 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.memoryInvalidated = false;
restrideInfo.lastStride = newStride; 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++) for (uint32 i = 0; i < LATTE_MAX_VERTEX_BUFFERS; i++)
{ {
auto vertexBufferRange = m_bufferRanges[i]; auto vertexBufferRange = m_bufferRanges[i];
if (vertexBufferRange) if (vertexBufferRange.offset != INVALID_OFFSET)
{ {
if ((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))) (offset > vertexBufferRange.offset && (offset + size) > (vertexBufferRange.offset + vertexBufferRange.size)))
{ {
continue; continue;
} }
vertexBufferRange->restrideInfo.memoryInvalidated = true; vertexBufferRange.restrideInfo->memoryInvalidated = true;
} }
} }
} }

View File

@ -1,9 +1,8 @@
#pragma once #pragma once
#include <Metal/Metal.hpp>
#include "Cafe/HW/Latte/ISA/LatteReg.h" #include "Cafe/HW/Latte/ISA/LatteReg.h"
#include "Cafe/HW/Latte/Core/LatteConst.h" #include "Cafe/HW/Latte/Core/LatteConst.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
//const uint32 bufferAllocatorIndexShift = 24; //const uint32 bufferAllocatorIndexShift = 24;
@ -68,9 +67,9 @@ struct MetalRestrideInfo
struct MetalVertexBufferRange struct MetalVertexBufferRange
{ {
size_t offset; size_t offset = INVALID_OFFSET;
size_t size; size_t size;
MetalRestrideInfo& restrideInfo; MetalRestrideInfo* restrideInfo;
}; };
class MetalVertexBufferCache class MetalVertexBufferCache
@ -82,19 +81,19 @@ public:
~MetalVertexBufferCache(); ~MetalVertexBufferCache();
// Vertex buffer cache // 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) void UntrackVertexBuffer(uint32 bufferIndex)
{ {
auto& range = m_bufferRanges[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); MetalRestridedBufferRange RestrideBufferIfNeeded(MTL::Buffer* bufferCache, uint32 bufferIndex, size_t stride);
@ -102,7 +101,7 @@ public:
private: private:
class MetalRenderer* m_mtlr; 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); void MemoryRangeChanged(size_t offset, size_t size);
}; };
@ -147,7 +146,7 @@ public:
void CopyBufferCache(size_t srcOffset, size_t dstOffset, size_t size); void CopyBufferCache(size_t srcOffset, size_t dstOffset, size_t size);
// Vertex buffer cache // 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); 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 = (CA::MetalLayer*)CreateMetalLayer(windowInfo.handle);
m_metalLayer->setDevice(m_device); m_metalLayer->setDevice(m_device);
// TODO: don't always force sRGB
// TODO: shouldn't this be handled differently? // TODO: shouldn't this be handled differently?
m_metalLayer->setPixelFormat(MTL::PixelFormatRGBA8Unorm_sRGB); m_metalLayer->setPixelFormat(MTL::PixelFormatRGBA8Unorm_sRGB);
@ -476,7 +477,7 @@ void MetalRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, u
buffer.size = size; buffer.size = size;
buffer.restrideInfo = {}; 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) 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_TEXTURES 31
#define MAX_MTL_SAMPLERS 16 #define MAX_MTL_SAMPLERS 16
constexpr size_t INVALID_OFFSET = std::numeric_limits<size_t>::max();
struct MetalBoundBuffer struct MetalBoundBuffer
{ {
bool needsRebind = false; bool needsRebind = false;