diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index 6a440b69..09020130 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -260,7 +260,7 @@ void InfoLog_PrintActiveSettings() cemuLog_log(LogType::Force, "Async compile: {}", GetConfig().async_compile.GetValue() ? "true" : "false"); cemuLog_log(LogType::Force, "Fast math: {}", g_current_game_profile->GetFastMath() ? "true" : "false"); cemuLog_log(LogType::Force, "Buffer cache type: {}", g_current_game_profile->GetBufferCacheMode()); - cemuLog_log(LogType::Force, "Position invariance: {}", g_current_game_profile->GetPositionInvariance() ? "true" : "false"); + cemuLog_log(LogType::Force, "Position invariance: {}", g_current_game_profile->GetPositionInvariance()); if (!GetConfig().vk_accurate_barriers.GetValue()) cemuLog_log(LogType::Force, "Accurate barriers are disabled!"); } diff --git a/src/Cafe/GameProfile/GameProfile.cpp b/src/Cafe/GameProfile/GameProfile.cpp index ff397860..16812d1c 100644 --- a/src/Cafe/GameProfile/GameProfile.cpp +++ b/src/Cafe/GameProfile/GameProfile.cpp @@ -227,8 +227,8 @@ bool GameProfile::Load(uint64_t title_id) gameProfile_loadEnumOption(iniParser, "accurateShaderMul", m_accurateShaderMul); gameProfile_loadBooleanOption2(iniParser, "fastMath", m_fastMath); - gameProfile_loadEnumOption(iniParser, "bufferCacheMode", m_bufferCacheMode); - gameProfile_loadBooleanOption2(iniParser, "positionInvariance", m_positionInvariance); + gameProfile_loadEnumOption(iniParser, "bufferCacheMode2", m_bufferCacheMode); + gameProfile_loadEnumOption(iniParser, "positionInvariance2", m_positionInvariance); // legacy support auto option_precompiledShaders = iniParser.FindOption("precompiledShaders"); @@ -295,25 +295,23 @@ void GameProfile::Save(uint64_t title_id) #define WRITE_OPTIONAL_ENTRY(__NAME) if (m_##__NAME) fs->writeLine(fmt::format("{} = {}", #__NAME, m_##__NAME.value()).c_str()); #define WRITE_ENTRY(__NAME) fs->writeLine(fmt::format("{} = {}", #__NAME, m_##__NAME).c_str()); +#define WRITE_ENTRY_NUMBERED(__NAME, __NUM) fs->writeLine(fmt::format("{} = {}", #__NAME #__NUM, m_##__NAME).c_str()); fs->writeLine("[General]"); WRITE_OPTIONAL_ENTRY(loadSharedLibraries); WRITE_ENTRY(startWithPadView); - fs->writeLine(""); - fs->writeLine("[CPU]"); WRITE_OPTIONAL_ENTRY(cpuMode); WRITE_ENTRY(threadQuantum); - fs->writeLine(""); fs->writeLine("[Graphics]"); WRITE_ENTRY(accurateShaderMul); WRITE_ENTRY(fastMath); - WRITE_ENTRY(bufferCacheMode); - WRITE_ENTRY(positionInvariance); + WRITE_ENTRY_NUMBERED(bufferCacheMode, 2); + WRITE_ENTRY_NUMBERED(positionInvariance, 2); WRITE_OPTIONAL_ENTRY(precompiledShaders); WRITE_OPTIONAL_ENTRY(graphics_api); fs->writeLine(""); @@ -329,6 +327,7 @@ void GameProfile::Save(uint64_t title_id) #undef WRITE_OPTIONAL_ENTRY #undef WRITE_ENTRY +#undef WRITE_ENTRY_NUMBERED delete fs; } @@ -344,8 +343,8 @@ void GameProfile::ResetOptional() // graphic settings m_accurateShaderMul = AccurateShaderMulOption::True; m_fastMath = true; - m_bufferCacheMode = BufferCacheMode::DevicePrivate; - m_positionInvariance = false; + m_bufferCacheMode = BufferCacheMode::Auto; + m_positionInvariance = PositionInvariance::Auto; // cpu settings m_threadQuantum = kThreadQuantumDefault; m_cpuMode.reset(); // CPUModeOption::kSingleCoreRecompiler; @@ -367,8 +366,8 @@ void GameProfile::Reset() // graphic settings m_accurateShaderMul = AccurateShaderMulOption::True; m_fastMath = true; - m_bufferCacheMode = BufferCacheMode::DevicePrivate; - m_positionInvariance = false; + m_bufferCacheMode = BufferCacheMode::Auto; + m_positionInvariance = PositionInvariance::Auto; m_precompiledShaders = PrecompiledShaderOption::Auto; // cpu settings m_threadQuantum = kThreadQuantumDefault; diff --git a/src/Cafe/GameProfile/GameProfile.h b/src/Cafe/GameProfile/GameProfile.h index 359e6a0a..58fd099b 100644 --- a/src/Cafe/GameProfile/GameProfile.h +++ b/src/Cafe/GameProfile/GameProfile.h @@ -33,7 +33,7 @@ public: [[nodiscard]] const AccurateShaderMulOption& GetAccurateShaderMul() const { return m_accurateShaderMul; } [[nodiscard]] bool GetFastMath() const { return m_fastMath; } [[nodiscard]] BufferCacheMode GetBufferCacheMode() const { return m_bufferCacheMode; } - [[nodiscard]] bool GetPositionInvariance() const { return m_positionInvariance; } + [[nodiscard]] PositionInvariance GetPositionInvariance() const { return m_positionInvariance; } [[nodiscard]] const std::optional& GetPrecompiledShadersState() const { return m_precompiledShaders; } [[nodiscard]] uint32 GetThreadQuantum() const { return m_threadQuantum; } @@ -58,8 +58,8 @@ private: std::optional m_graphics_api{}; AccurateShaderMulOption m_accurateShaderMul = AccurateShaderMulOption::True; bool m_fastMath = true; - BufferCacheMode m_bufferCacheMode = BufferCacheMode::DevicePrivate; - bool m_positionInvariance = false; + BufferCacheMode m_bufferCacheMode = BufferCacheMode::Auto; + PositionInvariance m_positionInvariance = PositionInvariance::Auto; std::optional m_precompiledShaders{}; // cpu settings uint32 m_threadQuantum = kThreadQuantumDefault; // values: 20000 45000 60000 80000 100000 diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp index 7b1dd53f..11afd892 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp @@ -2,9 +2,11 @@ #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() { @@ -36,6 +38,31 @@ void MetalMemoryManager::InitBufferCache(size_t size) m_bufferCacheMode = g_current_game_profile->GetBufferCacheMode(); + if (m_bufferCacheMode == BufferCacheMode::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_bufferCacheMode = BufferCacheMode::DeviceShared; + break; + default: + m_bufferCacheMode = BufferCacheMode::DevicePrivate; + break; + } + } + else + { + m_bufferCacheMode = BufferCacheMode::DevicePrivate; + } + } + // First, try to import the host memory as a buffer if (m_bufferCacheMode == BufferCacheMode::Host) { diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 61e5c94a..d2bd89b0 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -17,6 +17,7 @@ #include "Cafe/HW/Latte/Core/LatteShader.h" #include "Cafe/HW/Latte/Core/LatteIndices.h" #include "Cafe/HW/Latte/Core/LatteBufferCache.h" +#include "CafeSystem.h" #include "Cemu/Logging/CemuLogging.h" #include "Cafe/HW/Latte/Core/FetchShader.h" #include "Cafe/HW/Latte/Core/LatteConst.h" @@ -54,6 +55,59 @@ std::vector MetalRenderer::GetDevices() MetalRenderer::MetalRenderer() { + // Options + + // Position invariance + switch (g_current_game_profile->GetPositionInvariance()) + { + case PositionInvariance::Auto: + switch (CafeSystem::GetForegroundTitleId()) + { + // Minecraft: Story Mode + case 0x000500001020A300: // EUR + case 0x00050000101E0100: // USA + //case 0x000500001020a200: // USA + // Resident Evil: Revelations + case 0x000500001012B400: // EUR + case 0x000500001012CF00: // USA + // The Legend of Zelda: Breath of the Wild + case 0x00050000101C9500: // EUR + case 0x00050000101C9400: // USA + case 0x00050000101C9300: // JPN + // Ninja Gaiden 3: Razor's Edge + case 0x0005000010110B00: // EUR + case 0x0005000010139B00: // EUR (TODO: check) + case 0x0005000010110A00: // USA + case 0x0005000010110900: // JPN + // Bayonetta 2 + case 0x0005000010172700: // EUR + case 0x0005000010172600: // USA + // LEGO STAR WARS: The Force Awakens + case 0x00050000101DAA00: // EUR + case 0x00050000101DAB00: // USA + // Bayonetta + case 0x0005000010157F00: // EUR + case 0x0005000010157E00: // USA + case 0x000500001014DB00: // JPN + // Disney Planes + case 0x0005000010136900: // EUR + case 0x0005000010136A00: // EUR + case 0x0005000010136B00: // EUR + case 0x000500001011C500: // USA (TODO: check) + m_positionInvariance = true; + break; + default: + m_positionInvariance = false; + break; + } + case PositionInvariance::False: + m_positionInvariance = false; + break; + case PositionInvariance::True: + m_positionInvariance = true; + break; + } + // Pick a device auto& config = GetConfig(); const bool hasDeviceSet = config.mtl_graphic_device_uuid != 0; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index 04c63be8..2aa68973 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -358,6 +358,11 @@ public: void CopyBufferToBuffer(MTL::Buffer* src, uint32 srcOffset, MTL::Buffer* dst, uint32 dstOffset, uint32 size, MTL::RenderStages after, MTL::RenderStages before); // Getters + bool GetPositionInvariance() const + { + return m_positionInvariance; + } + bool IsAppleGPU() const { return m_isAppleGPU; @@ -464,6 +469,9 @@ private: MetalPerformanceMonitor m_performanceMonitor; + // Options + bool m_positionInvariance; + // Metal objects MTL::Device* m_device = nullptr; MTL::CommandQueue* m_commandQueue; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp index 07073e08..b0ba48a4 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp @@ -2,8 +2,8 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h" -#include "Cemu/FileCache/FileCache.h" -#include "config/ActiveSettings.h" +//#include "Cemu/FileCache/FileCache.h" +//#include "config/ActiveSettings.h" #include "Cemu/Logging/CemuLogging.h" #include "Common/precompiled.h" #include "GameProfile/GameProfile.h" @@ -279,8 +279,12 @@ MTL::Library* RendererShaderMtl::LibraryFromSource() MTL::CompileOptions* options = MTL::CompileOptions::alloc()->init(); if (g_current_game_profile->GetFastMath()) options->setFastMathEnabled(true); - if (g_current_game_profile->GetPositionInvariance()) + + if (m_mtlr->GetPositionInvariance()) + { + // TODO: filter out based on GPU state options->setPreserveInvariance(true); + } NS::Error* error = nullptr; MTL::Library* library = m_mtlr->GetDevice()->newLibrary(ToNSString(m_mslCode), options, &error); diff --git a/src/config/CemuConfig.h b/src/config/CemuConfig.h index 991d9a89..17f224ab 100644 --- a/src/config/CemuConfig.h +++ b/src/config/CemuConfig.h @@ -126,11 +126,20 @@ ENABLE_ENUM_ITERATORS(AccurateShaderMulOption, AccurateShaderMulOption::False, A enum class BufferCacheMode { + Auto, DevicePrivate, DeviceShared, Host, }; -ENABLE_ENUM_ITERATORS(BufferCacheMode, BufferCacheMode::DevicePrivate, BufferCacheMode::Host); +ENABLE_ENUM_ITERATORS(BufferCacheMode, BufferCacheMode::Auto, BufferCacheMode::Host); + +enum class PositionInvariance +{ + Auto, + False, + True, +}; +ENABLE_ENUM_ITERATORS(PositionInvariance, PositionInvariance::False, PositionInvariance::True); enum class CPUMode { @@ -236,6 +245,7 @@ struct fmt::formatter : formatter { string_view name; switch (c) { + case BufferCacheMode::Auto: name = "auto"; break; case BufferCacheMode::DevicePrivate: name = "device private"; break; case BufferCacheMode::DeviceShared: name = "device shared"; break; case BufferCacheMode::Host: name = "host"; break; @@ -245,6 +255,21 @@ struct fmt::formatter : formatter { } }; template <> +struct fmt::formatter : formatter { + template + auto format(const PositionInvariance c, FormatContext &ctx) const { + string_view name; + switch (c) + { + case PositionInvariance::Auto: name = "auto"; break; + case PositionInvariance::False: name = "false"; break; + case PositionInvariance::True: name = "true"; break; + default: name = "unknown"; break; + } + return formatter::format(name, ctx); + } +}; +template <> struct fmt::formatter : formatter { template auto format(const CPUMode c, FormatContext &ctx) const { diff --git a/src/gui/GameProfileWindow.cpp b/src/gui/GameProfileWindow.cpp index c46f0f25..3ff718a8 100644 --- a/src/gui/GameProfileWindow.cpp +++ b/src/gui/GameProfileWindow.cpp @@ -132,21 +132,21 @@ GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id) wxString math_values[] = { _("false"), _("true") }; m_fast_math = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(math_values), math_values); - m_fast_math->SetToolTip(_("Enables fast math for all shaders. May (rarely) cause graphical bugs.\n\nMetal only\n\nRecommended: true")); + m_fast_math->SetToolTip(_("EXPERT OPTION\nEnables fast math for all shaders. May (rarely) cause graphical bugs.\n\nMetal only\n\nRecommended: true")); first_row->Add(m_fast_math, 0, wxALL, 5); first_row->Add(new wxStaticText(panel, wxID_ANY, _("Buffer cache mode")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - wxString cache_values[] = { _("device private"), _("device shared"), _("host") }; + wxString cache_values[] = { _("auto"), _("device private"), _("device shared"), _("host") }; m_buffer_cache_mode = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(cache_values), cache_values); - m_buffer_cache_mode->SetToolTip(_("EXPERT OPTION\nDecides how the buffer cache memory will be managed.\n\nMetal only\n\nRecommended: device private")); + m_buffer_cache_mode->SetToolTip(_("EXPERT OPTION\nDecides how the buffer cache memory will be managed.\n\nMetal only\n\nRecommended: auto")); first_row->Add(m_buffer_cache_mode, 0, wxALL, 5); first_row->Add(new wxStaticText(panel, wxID_ANY, _("Position invariance")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - wxString pos_values[] = { _("false"), _("true") }; + wxString pos_values[] = { _("auto"), _("false"), _("true") }; m_position_invariance = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(pos_values), pos_values); - m_position_invariance->SetToolTip(_("Disables most optimizations for vertex positions. May fix polygon cutouts in some games.\n\nMetal only\n\nRecommended: false")); + m_position_invariance->SetToolTip(_("EXPERT OPTION\nDisables most optimizations for vertex positions. May fix polygon cutouts or flickering in some games.\n\nMetal only\n\nRecommended: auto")); first_row->Add(m_position_invariance, 0, wxALL, 5); /*first_row->Add(new wxStaticText(panel, wxID_ANY, _("GPU buffer cache accuracy")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); @@ -357,11 +357,11 @@ void GameProfileWindow::SaveProfile() // gpu m_game_profile.m_accurateShaderMul = (AccurateShaderMulOption)m_shader_mul_accuracy->GetSelection(); - m_game_profile.m_fastMath = (bool)m_fast_math->GetSelection(); - m_game_profile.m_bufferCacheMode = (BufferCacheMode)m_buffer_cache_mode->GetSelection(); - m_game_profile.m_positionInvariance = (bool)m_position_invariance->GetSelection(); if (m_game_profile.m_accurateShaderMul != AccurateShaderMulOption::False && m_game_profile.m_accurateShaderMul != AccurateShaderMulOption::True) m_game_profile.m_accurateShaderMul = AccurateShaderMulOption::True; // force a legal value + m_game_profile.m_fastMath = (bool)m_fast_math->GetSelection(); + m_game_profile.m_bufferCacheMode = (BufferCacheMode)m_buffer_cache_mode->GetSelection(); + m_game_profile.m_positionInvariance = (PositionInvariance)m_position_invariance->GetSelection(); if (m_graphic_api->GetSelection() == 0) m_game_profile.m_graphics_api = {};