mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-02 21:11:17 +12:00
128 lines
4.6 KiB
C++
128 lines
4.6 KiB
C++
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
|
|
#include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h"
|
|
#include "Cafe/HW/Latte/Renderer/Metal/MetalVoidVertexPipeline.h"
|
|
|
|
#include "CafeSystem.h"
|
|
#include "Cemu/Logging/CemuLogging.h"
|
|
#include "Common/precompiled.h"
|
|
#include "HW/MMU/MMU.h"
|
|
#include "config/CemuConfig.h"
|
|
|
|
MetalMemoryManager::~MetalMemoryManager()
|
|
{
|
|
if (m_bufferCache)
|
|
{
|
|
m_bufferCache->release();
|
|
}
|
|
}
|
|
|
|
void* MetalMemoryManager::AcquireTextureUploadBuffer(size_t size)
|
|
{
|
|
if (m_textureUploadBuffer.size() < size)
|
|
{
|
|
m_textureUploadBuffer.resize(size);
|
|
}
|
|
|
|
return m_textureUploadBuffer.data();
|
|
}
|
|
|
|
void MetalMemoryManager::ReleaseTextureUploadBuffer(uint8* mem)
|
|
{
|
|
cemu_assert_debug(m_textureUploadBuffer.data() == mem);
|
|
m_textureUploadBuffer.clear();
|
|
}
|
|
|
|
void MetalMemoryManager::InitBufferCache(size_t size)
|
|
{
|
|
cemu_assert_debug(!m_bufferCache);
|
|
|
|
m_metalBufferCacheMode = g_current_game_profile->GetBufferCacheMode();
|
|
|
|
if (m_metalBufferCacheMode == MetalBufferCacheMode::Auto)
|
|
{
|
|
// TODO: do this for all unified memory systems?
|
|
if (m_mtlr->IsAppleGPU())
|
|
{
|
|
switch (CafeSystem::GetForegroundTitleId())
|
|
{
|
|
// The Legend of Zelda: Wind Waker HD
|
|
case 0x0005000010143600: // EUR
|
|
case 0x0005000010143500: // USA
|
|
case 0x0005000010143400: // JPN
|
|
// TODO: use host instead?
|
|
m_metalBufferCacheMode = MetalBufferCacheMode::DeviceShared;
|
|
break;
|
|
default:
|
|
m_metalBufferCacheMode = MetalBufferCacheMode::DevicePrivate;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_metalBufferCacheMode = MetalBufferCacheMode::DevicePrivate;
|
|
}
|
|
}
|
|
|
|
// First, try to import the host memory as a buffer
|
|
if (m_metalBufferCacheMode == MetalBufferCacheMode::Host)
|
|
{
|
|
if (m_mtlr->HasUnifiedMemory())
|
|
{
|
|
m_importedMemBaseAddress = mmuRange_MEM2.getBase();
|
|
m_hostAllocationSize = mmuRange_MEM2.getSize();
|
|
m_bufferCache = m_mtlr->GetDevice()->newBuffer(memory_getPointerFromVirtualOffset(m_importedMemBaseAddress), m_hostAllocationSize, MTL::ResourceStorageModeShared, nullptr);
|
|
if (!m_bufferCache)
|
|
{
|
|
cemuLog_log(LogType::Force, "Failed to import host memory as a buffer, using device shared mode instead");
|
|
m_metalBufferCacheMode = MetalBufferCacheMode::DeviceShared;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cemuLog_log(LogType::Force, "Host buffer cache mode is only available on unified memory systems, using device shared mode instead");
|
|
m_metalBufferCacheMode = MetalBufferCacheMode::DeviceShared;
|
|
}
|
|
}
|
|
|
|
if (!m_bufferCache)
|
|
m_bufferCache = m_mtlr->GetDevice()->newBuffer(size, (m_metalBufferCacheMode == MetalBufferCacheMode::DevicePrivate ? MTL::ResourceStorageModePrivate : MTL::ResourceStorageModeShared));
|
|
|
|
#ifdef CEMU_DEBUG_ASSERT
|
|
m_bufferCache->setLabel(GetLabel("Buffer cache", m_bufferCache));
|
|
#endif
|
|
}
|
|
|
|
void MetalMemoryManager::UploadToBufferCache(const void* data, size_t offset, size_t size)
|
|
{
|
|
cemu_assert_debug(m_metalBufferCacheMode != MetalBufferCacheMode::Host);
|
|
cemu_assert_debug(m_bufferCache);
|
|
cemu_assert_debug((offset + size) <= m_bufferCache->length());
|
|
|
|
if (m_metalBufferCacheMode == MetalBufferCacheMode::DevicePrivate)
|
|
{
|
|
auto blitCommandEncoder = m_mtlr->GetBlitCommandEncoder();
|
|
|
|
auto allocation = m_stagingAllocator.AllocateBufferMemory(size, 1);
|
|
memcpy(allocation.memPtr, data, size);
|
|
m_stagingAllocator.FlushReservation(allocation);
|
|
|
|
blitCommandEncoder->copyFromBuffer(allocation.mtlBuffer, allocation.bufferOffset, m_bufferCache, offset, size);
|
|
|
|
//m_mtlr->CopyBufferToBuffer(allocation.mtlBuffer, allocation.bufferOffset, m_bufferCache, offset, size, ALL_MTL_RENDER_STAGES, ALL_MTL_RENDER_STAGES);
|
|
}
|
|
else
|
|
{
|
|
memcpy((uint8*)m_bufferCache->contents() + offset, data, size);
|
|
}
|
|
}
|
|
|
|
void MetalMemoryManager::CopyBufferCache(size_t srcOffset, size_t dstOffset, size_t size)
|
|
{
|
|
cemu_assert_debug(m_metalBufferCacheMode != MetalBufferCacheMode::Host);
|
|
cemu_assert_debug(m_bufferCache);
|
|
|
|
if (m_metalBufferCacheMode == MetalBufferCacheMode::DevicePrivate)
|
|
m_mtlr->CopyBufferToBuffer(m_bufferCache, srcOffset, m_bufferCache, dstOffset, size, ALL_MTL_RENDER_STAGES, ALL_MTL_RENDER_STAGES);
|
|
else
|
|
memcpy((uint8*)m_bufferCache->contents() + dstOffset, (uint8*)m_bufferCache->contents() + srcOffset, size);
|
|
}
|