flush uploaded buffers

This commit is contained in:
Samuliak 2025-01-18 18:01:40 +01:00
parent 6d6c04ae3c
commit bf93f90739
No known key found for this signature in database
5 changed files with 42 additions and 34 deletions

View file

@ -9,7 +9,7 @@ MetalBufferChunkedHeap::~MetalBufferChunkedHeap()
uint32 MetalBufferChunkedHeap::allocateNewChunk(uint32 chunkIndex, uint32 minimumAllocationSize) uint32 MetalBufferChunkedHeap::allocateNewChunk(uint32 chunkIndex, uint32 minimumAllocationSize)
{ {
size_t allocationSize = std::max<size_t>(m_minimumBufferAllocationSize, minimumAllocationSize); size_t allocationSize = std::max<size_t>(m_minimumBufferAllocationSize, minimumAllocationSize);
MTL::Buffer* buffer = m_mtlr->GetDevice()->newBuffer(allocationSize, MTL::ResourceStorageModeShared); MTL::Buffer* buffer = m_mtlr->GetDevice()->newBuffer(allocationSize, m_options);
cemu_assert_debug(buffer); cemu_assert_debug(buffer);
cemu_assert_debug(m_chunkBuffers.size() == chunkIndex); cemu_assert_debug(m_chunkBuffers.size() == chunkIndex);
m_chunkBuffers.emplace_back(buffer); m_chunkBuffers.emplace_back(buffer);
@ -36,7 +36,7 @@ void MetalSynchronizedRingAllocator::allocateAdditionalUploadBuffer(uint32 sizeR
AllocatorBuffer_t newBuffer{}; AllocatorBuffer_t newBuffer{};
newBuffer.writeIndex = 0; newBuffer.writeIndex = 0;
newBuffer.basePtr = nullptr; newBuffer.basePtr = nullptr;
newBuffer.mtlBuffer = m_mtlr->GetDevice()->newBuffer(bufferAllocSize, MTL::ResourceStorageModeShared); newBuffer.mtlBuffer = m_mtlr->GetDevice()->newBuffer(bufferAllocSize, m_options);
newBuffer.basePtr = (uint8*)newBuffer.mtlBuffer->contents(); newBuffer.basePtr = (uint8*)newBuffer.mtlBuffer->contents();
newBuffer.size = bufferAllocSize; newBuffer.size = bufferAllocSize;
newBuffer.index = (uint32)m_buffers.size(); newBuffer.index = (uint32)m_buffers.size();
@ -105,16 +105,10 @@ MetalSynchronizedRingAllocator::AllocatorReservation_t MetalSynchronizedRingAllo
void MetalSynchronizedRingAllocator::FlushReservation(AllocatorReservation_t& uploadReservation) void MetalSynchronizedRingAllocator::FlushReservation(AllocatorReservation_t& uploadReservation)
{ {
/* if (RequiresFlush())
cemu_assert_debug(m_bufferType == VKR_BUFFER_TYPE::STAGING); // only the staging buffer isn't coherent {
// todo - use nonCoherentAtomSize for flush size (instead of hardcoded constant) uploadReservation.mtlBuffer->didModifyRange(NS::Range(uploadReservation.bufferOffset, uploadReservation.size));
VkMappedMemoryRange flushedRange{}; }
flushedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
flushedRange.memory = uploadReservation.vkMem;
flushedRange.offset = uploadReservation.bufferOffset;
flushedRange.size = uploadReservation.size;
vkFlushMappedMemoryRanges(m_vkr->GetLogicalDevice(), 1, &flushedRange);
*/
} }
void MetalSynchronizedRingAllocator::CleanupBuffer(MTL::CommandBuffer* latestFinishedCommandBuffer) void MetalSynchronizedRingAllocator::CleanupBuffer(MTL::CommandBuffer* latestFinishedCommandBuffer)
@ -172,9 +166,6 @@ void MetalSynchronizedRingAllocator::GetStats(uint32& numBuffers, size_t& totalB
/* MetalSynchronizedHeapAllocator */ /* MetalSynchronizedHeapAllocator */
MetalSynchronizedHeapAllocator::MetalSynchronizedHeapAllocator(class MetalRenderer* mtlRenderer, size_t minimumBufferAllocSize)
: m_mtlr(mtlRenderer), m_chunkedHeap(m_mtlr, minimumBufferAllocSize) {};
MetalSynchronizedHeapAllocator::AllocatorReservation* MetalSynchronizedHeapAllocator::AllocateBufferMemory(uint32 size, uint32 alignment) MetalSynchronizedHeapAllocator::AllocatorReservation* MetalSynchronizedHeapAllocator::AllocateBufferMemory(uint32 size, uint32 alignment)
{ {
CHAddr addr = m_chunkedHeap.alloc(size, alignment); CHAddr addr = m_chunkedHeap.alloc(size, alignment);
@ -202,17 +193,10 @@ void MetalSynchronizedHeapAllocator::FreeReservation(AllocatorReservation* uploa
void MetalSynchronizedHeapAllocator::FlushReservation(AllocatorReservation* uploadReservation) void MetalSynchronizedHeapAllocator::FlushReservation(AllocatorReservation* uploadReservation)
{ {
/* if (m_chunkedHeap.RequiresFlush())
if (m_chunkedHeap.RequiresFlush(uploadReservation->bufferIndex))
{ {
VkMappedMemoryRange flushedRange{}; uploadReservation->mtlBuffer->didModifyRange(NS::Range(uploadReservation->bufferOffset, uploadReservation->size));
flushedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
flushedRange.memory = uploadReservation->vkMem;
flushedRange.offset = uploadReservation->bufferOffset;
flushedRange.size = uploadReservation->size;
vkFlushMappedMemoryRanges(VulkanRenderer::GetInstance()->GetLogicalDevice(), 1, &flushedRange);
} }
*/
} }
void MetalSynchronizedHeapAllocator::CleanupBuffer(MTL::CommandBuffer* latestFinishedCommandBuffer) void MetalSynchronizedHeapAllocator::CleanupBuffer(MTL::CommandBuffer* latestFinishedCommandBuffer)

View file

@ -1,15 +1,24 @@
#pragma once #pragma once
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
#include "Metal/MTLResource.hpp"
#include "util/ChunkedHeap/ChunkedHeap.h" #include "util/ChunkedHeap/ChunkedHeap.h"
#include "util/helpers/MemoryPool.h" #include "util/helpers/MemoryPool.h"
#include <utility> #include <utility>
inline MTL::ResourceOptions GetResourceOptions(MTL::ResourceOptions options)
{
if (options & MTL::ResourceStorageModeShared || options & MTL::ResourceStorageModeManaged)
options |= MTL::ResourceCPUCacheModeWriteCombined;
return options;
}
class MetalBufferChunkedHeap : private ChunkedHeap<> class MetalBufferChunkedHeap : private ChunkedHeap<>
{ {
public: public:
MetalBufferChunkedHeap(const class MetalRenderer* mtlRenderer, size_t minimumBufferAllocationSize) : m_mtlr(mtlRenderer), m_minimumBufferAllocationSize(minimumBufferAllocationSize) { }; MetalBufferChunkedHeap(const class MetalRenderer* mtlRenderer, MTL::ResourceOptions options, size_t minimumBufferAllocationSize) : m_mtlr(mtlRenderer), m_options(GetResourceOptions(options)), m_minimumBufferAllocationSize(minimumBufferAllocationSize) { };
~MetalBufferChunkedHeap(); ~MetalBufferChunkedHeap();
using ChunkedHeap::alloc; using ChunkedHeap::alloc;
@ -30,6 +39,11 @@ class MetalBufferChunkedHeap : private ChunkedHeap<>
return m_chunkBuffers[index]; return m_chunkBuffers[index];
} }
bool RequiresFlush() const
{
return m_options & MTL::ResourceStorageModeManaged;
}
void GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const void GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const
{ {
numBuffers = m_chunkBuffers.size(); numBuffers = m_chunkBuffers.size();
@ -42,15 +56,17 @@ class MetalBufferChunkedHeap : private ChunkedHeap<>
const class MetalRenderer* m_mtlr; const class MetalRenderer* m_mtlr;
std::vector<MTL::Buffer*> m_chunkBuffers; MTL::ResourceOptions m_options;
size_t m_minimumBufferAllocationSize; size_t m_minimumBufferAllocationSize;
std::vector<MTL::Buffer*> m_chunkBuffers;
}; };
// a circular ring-buffer which tracks and releases memory per command-buffer // a circular ring-buffer which tracks and releases memory per command-buffer
class MetalSynchronizedRingAllocator class MetalSynchronizedRingAllocator
{ {
public: public:
MetalSynchronizedRingAllocator(class MetalRenderer* mtlRenderer, uint32 minimumBufferAllocSize) : m_mtlr(mtlRenderer), m_minimumBufferAllocSize(minimumBufferAllocSize) {}; MetalSynchronizedRingAllocator(class MetalRenderer* mtlRenderer, MTL::ResourceOptions options, uint32 minimumBufferAllocSize) : m_mtlr(mtlRenderer), m_options(GetResourceOptions(options)), m_minimumBufferAllocSize(minimumBufferAllocSize) {};
MetalSynchronizedRingAllocator(const MetalSynchronizedRingAllocator&) = delete; // disallow copy MetalSynchronizedRingAllocator(const MetalSynchronizedRingAllocator&) = delete; // disallow copy
struct BufferSyncPoint_t struct BufferSyncPoint_t
@ -88,6 +104,11 @@ public:
void CleanupBuffer(MTL::CommandBuffer* latestFinishedCommandBuffer); void CleanupBuffer(MTL::CommandBuffer* latestFinishedCommandBuffer);
MTL::Buffer* GetBufferByIndex(uint32 index) const; MTL::Buffer* GetBufferByIndex(uint32 index) const;
bool RequiresFlush() const
{
return m_options & MTL::ResourceStorageModeManaged;
}
void GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const; void GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const;
private: private:
@ -95,6 +116,8 @@ private:
void addUploadBufferSyncPoint(AllocatorBuffer_t& buffer, uint32 offset); void addUploadBufferSyncPoint(AllocatorBuffer_t& buffer, uint32 offset);
const class MetalRenderer* m_mtlr; const class MetalRenderer* m_mtlr;
MTL::ResourceOptions m_options;
const uint32 m_minimumBufferAllocSize; const uint32 m_minimumBufferAllocSize;
std::vector<AllocatorBuffer_t> m_buffers; std::vector<AllocatorBuffer_t> m_buffers;
@ -110,7 +133,7 @@ class MetalSynchronizedHeapAllocator
}; };
public: public:
MetalSynchronizedHeapAllocator(class MetalRenderer* mtlRenderer, size_t minimumBufferAllocSize); MetalSynchronizedHeapAllocator(class MetalRenderer* mtlRenderer, MTL::ResourceOptions options, size_t minimumBufferAllocSize) : m_mtlr(mtlRenderer), m_chunkedHeap(m_mtlr, options, minimumBufferAllocSize) {}
MetalSynchronizedHeapAllocator(const MetalSynchronizedHeapAllocator&) = delete; // disallow copy MetalSynchronizedHeapAllocator(const MetalSynchronizedHeapAllocator&) = delete; // disallow copy
struct AllocatorReservation struct AllocatorReservation

View file

@ -77,6 +77,7 @@ void MetalMemoryManager::UploadToBufferCache(const void* data, size_t offset, si
auto allocation = m_stagingAllocator.AllocateBufferMemory(size, 1); auto allocation = m_stagingAllocator.AllocateBufferMemory(size, 1);
memcpy(allocation.memPtr, data, size); memcpy(allocation.memPtr, data, size);
m_stagingAllocator.FlushReservation(allocation);
blitCommandEncoder->copyFromBuffer(allocation.mtlBuffer, allocation.bufferOffset, m_bufferCache, offset, size); blitCommandEncoder->copyFromBuffer(allocation.mtlBuffer, allocation.bufferOffset, m_bufferCache, offset, size);

View file

@ -7,7 +7,7 @@
class MetalMemoryManager class MetalMemoryManager
{ {
public: public:
MetalMemoryManager(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer}, m_stagingAllocator(m_mtlr/*, m_mtlr->GetOptimalBufferStorageMode()*/, 32u * 1024 * 1024), m_indexAllocator(m_mtlr/*, m_mtlr->GetOptimalBufferStorageMode()*/, 4u * 1024 * 1024) {} MetalMemoryManager(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer}, m_stagingAllocator(m_mtlr, m_mtlr->GetOptimalBufferStorageMode(), 32u * 1024 * 1024), m_indexAllocator(m_mtlr, m_mtlr->GetOptimalBufferStorageMode(), 4u * 1024 * 1024) {}
~MetalMemoryManager(); ~MetalMemoryManager();
MetalSynchronizedRingAllocator& GetStagingAllocator() MetalSynchronizedRingAllocator& GetStagingAllocator()

View file

@ -702,6 +702,7 @@ void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, s
// Allocate a temporary buffer // Allocate a temporary buffer
auto& bufferAllocator = m_memoryManager->GetStagingAllocator(); auto& bufferAllocator = m_memoryManager->GetStagingAllocator();
auto allocation = bufferAllocator.AllocateBufferMemory(compressedImageSize, 1); auto allocation = bufferAllocator.AllocateBufferMemory(compressedImageSize, 1);
bufferAllocator.FlushReservation(allocation);
// Copy the data to the temporary buffer // Copy the data to the temporary buffer
memcpy(allocation.memPtr, pixelData, compressedImageSize); memcpy(allocation.memPtr, pixelData, compressedImageSize);
@ -2092,12 +2093,11 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
size_t size = shader->uniform.uniformRangeSize; size_t size = shader->uniform.uniformRangeSize;
auto& bufferAllocator = m_memoryManager->GetStagingAllocator(); auto& bufferAllocator = m_memoryManager->GetStagingAllocator();
auto supportBuffer = bufferAllocator.AllocateBufferMemory(size, 1); auto allocation = bufferAllocator.AllocateBufferMemory(size, 1);
memcpy(supportBuffer.memPtr, supportBufferData, size); memcpy(allocation.memPtr, supportBufferData, size);
//if (!HasUnifiedMemory()) bufferAllocator.FlushReservation(allocation);
// buffer->didModifyRange(NS::Range(supportBuffer.offset, size));
SetBuffer(renderCommandEncoder, mtlShaderType, supportBuffer.mtlBuffer, supportBuffer.bufferOffset, shader->resourceMapping.uniformVarsBufferBindingPoint); SetBuffer(renderCommandEncoder, mtlShaderType, allocation.mtlBuffer, allocation.bufferOffset, shader->resourceMapping.uniformVarsBufferBindingPoint);
} }
// Uniform buffers // Uniform buffers