diff --git a/testing/cemu/APKBUILD b/testing/cemu/APKBUILD index fd8679d315f..3250b3d34f7 100644 --- a/testing/cemu/APKBUILD +++ b/testing/cemu/APKBUILD @@ -1,9 +1,9 @@ # Contributor: Joshua Murphy # Maintainer: Joshua Murphy pkgname=cemu -pkgver=2.0.41 -_pkgver=2.0-41 -pkgrel=1 +pkgver=2.0.46 +_pkgver=2.0-46 +pkgrel=0 _cubeb=2071354a69aca7ed6df3b4222e305746c2113f60 _imgui=f65bcf481ab34cd07d3909aab1479f409fa79f2f pkgdesc="Wii U Emulator" @@ -48,6 +48,7 @@ source="$pkgname-$_pkgver.tar.gz::https://github.com/cemu-project/Cemu/archive/v imgui-$_imgui.tar.gz::https://github.com/ocornut/imgui/archive/$_imgui.tar.gz cmake-fixes.patch execinfo.patch + fmt10.patch " builddir="$srcdir/Cemu-$_pkgver" options="!check" # no tests @@ -98,9 +99,10 @@ lang() { } sha512sums=" -b9f33344256fb5f5fad9fdabe62556d0f175f3610919fa2336f9f4f7d8b1058f3c7024b6f961ee40d2f5d056e2ae5161fed7ae0c0e6612cdeea0bf1caeea557c cemu-2.0-41.tar.gz +5e0b59eeb659f54cd638f66a590c645c94b0cb18102ca04c3a5d8bd22d0056d01ce9d4c3bb15b272029a44c88fb114c5ee12920e46f0de7be92c77f30689c159 cemu-2.0-46.tar.gz 64a25d58f6a842947ac8ee1125574fc6a34b261e97a11a9fcdf27cccaf35dad49f12f3f2d8abb1e057932059629c3e568421cf2c09b064d76de21c1a8d8542a3 cubeb-2071354a69aca7ed6df3b4222e305746c2113f60.tar.gz 6e5bbede4435bd7248ae426eed519d702c5770ac211d2cf18c4b9f9fa7e83b901e4f80662c0f39e1d688bc3eaf674dd21c9d3e42e7324e5ab9bc16af67c13429 imgui-f65bcf481ab34cd07d3909aab1479f409fa79f2f.tar.gz -12d33c9f6506a4cd2ee1bb148ca26a57dba31de2b3d21583c4d067e6d7ecef2996e3895af4cec6808860b6f4599906f3d0178b4fe0c52fcc7f842f88bf9f39bd cmake-fixes.patch +e334fa162098d73d14e231662fdcaa423ab3b57217fbc26c95b576b3c79349bde2559fae81533af63433797f1980fa51fc8f272f31d67e0432f3c57682d5c9c3 cmake-fixes.patch 0467091365c2cdb475bb6034115be4998af71803e351e5fdf7591a640eb328a22c7cc27c2760096410e2fd597989e6986e3fb6fceb91acde5ea47cdf9ba2bce6 execinfo.patch +15e715926b258e1429e34b741162225409ce219bf7c4ad761a7165112c2609cc6e52c31636b78db1b2e3eaa13a7e256120fe699dcd7338c661a067265be4616e fmt10.patch " diff --git a/testing/cemu/cmake-fixes.patch b/testing/cemu/cmake-fixes.patch index fb8d834dc8b..fe2a8b7a28e 100644 --- a/testing/cemu/cmake-fixes.patch +++ b/testing/cemu/cmake-fixes.patch @@ -1,8 +1,7 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index b973a3f..9a39fcb 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -83,6 +83,8 @@ option(ENABLE_CUBEB "Enabled cubeb backend" ON) +diff -Nurp a/CMakeLists.txt b/CMakeLists.txt +--- a/CMakeLists.txt 2023-08-03 18:31:12.000000000 +0000 ++++ b/CMakeLists.txt 2023-08-12 15:24:14.737662630 +0000 +@@ -101,6 +101,8 @@ option(ENABLE_CUBEB "Enabled cubeb backe option(ENABLE_WXWIDGETS "Build with wxWidgets UI (Currently required)" ON) @@ -11,14 +10,15 @@ index b973a3f..9a39fcb 100644 set(THREADS_PREFER_PTHREAD_FLAG true) find_package(Threads REQUIRED) find_package(SDL2 REQUIRED) -@@ -95,9 +97,11 @@ find_package(glslang REQUIRED) +@@ -113,9 +115,11 @@ find_package(glslang REQUIRED) find_package(ZLIB REQUIRED) find_package(zstd MODULE REQUIRED) # MODULE so that zstd::zstd is available find_package(OpenSSL COMPONENTS Crypto SSL REQUIRED) -find_package(glm REQUIRED) +-find_package(fmt 9.1.0...<10 REQUIRED) +pkg_check_modules(glm REQUIRED glm IMPORTED_TARGET) +add_library(glm::glm ALIAS PkgConfig::glm) - find_package(fmt 9.1.0 REQUIRED) ++find_package(fmt 9.1.0 REQUIRED) find_package(PNG REQUIRED) +pkg_check_modules(EGL REQUIRED egl IMPORTED_TARGET GLOBAL) diff --git a/testing/cemu/fmt10.patch b/testing/cemu/fmt10.patch new file mode 100644 index 00000000000..f51302fafcf --- /dev/null +++ b/testing/cemu/fmt10.patch @@ -0,0 +1,794 @@ +From bb12b2fcfa7e49835f5d678012a606ae85542875 Mon Sep 17 00:00:00 2001 +From: Alexandre Bouvier +Date: Mon, 31 Jul 2023 16:58:07 +0200 +Subject: [PATCH] fmt: enable compatibility with fmt>=10 + +--- + CMakeLists.txt | 2 +- + src/Cafe/HW/Latte/Core/LatteConst.h | 2 + + src/Cafe/HW/Latte/ISA/LatteInstructions.h | 5 +++ + src/Cafe/HW/Latte/ISA/LatteReg.h | 2 + + .../HW/Latte/Renderer/Vulkan/CocoaSurface.mm | 2 +- + .../Renderer/Vulkan/RendererShaderVk.cpp | 2 +- + .../Latte/Renderer/Vulkan/SwapchainInfoVk.cpp | 14 +++---- + .../Vulkan/VulkanPipelineCompiler.cpp | 2 +- + .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 42 +++++++++---------- + .../Renderer/Vulkan/VulkanSurfaceCopy.cpp | 2 +- + src/Cafe/IOSU/fsa/fsa_types.h | 5 +++ + src/Cafe/OS/libs/TCL/TCL.cpp | 1 + + src/Cafe/OS/libs/coreinit/coreinit_FS.cpp | 2 + + .../OS/libs/coreinit/coreinit_HWInterface.cpp | 2 + + src/Cafe/OS/libs/coreinit/coreinit_MEM.h | 2 + + .../OS/libs/coreinit/coreinit_MEM_FrmHeap.h | 2 + + src/Cafe/OS/libs/coreinit/coreinit_Thread.h | 6 +++ + src/Cafe/OS/libs/gx2/GX2_Blit.h | 2 + + src/Cafe/OS/libs/gx2/GX2_Command.cpp | 2 + + src/Cafe/OS/libs/gx2/GX2_Event.cpp | 1 + + src/Cafe/OS/libs/gx2/GX2_Event.h | 2 + + src/Cafe/OS/libs/gx2/GX2_Misc.h | 2 + + src/Cafe/OS/libs/gx2/GX2_Shader.h | 5 +++ + src/Cafe/OS/libs/gx2/GX2_State.cpp | 2 + + src/Cafe/OS/libs/nn_acp/nn_acp.h | 2 + + src/Cafe/OS/libs/nn_boss/nn_boss.cpp | 2 + + src/Cafe/OS/libs/nn_ndm/nn_ndm.cpp | 1 + + src/Cafe/OS/libs/nn_olv/nn_olv_PostTypes.h | 2 + + src/Cemu/Logging/CemuLogging.h | 17 +------- + src/Cemu/napi/napi.h | 7 ++++ + src/Common/MemPtr.h | 2 +- + src/Common/betype.h | 6 +++ + src/Common/precompiled.h | 10 ++--- + src/audio/IAudioAPI.h | 5 +++ + src/audio/IAudioInputAPI.h | 5 +++ + src/input/api/InputAPI.h | 5 +++ + src/util/EventService.h | 5 +++ + 37 files changed, 123 insertions(+), 57 deletions(-) + +diff --git a/src/Cafe/HW/Latte/Core/LatteConst.h b/src/Cafe/HW/Latte/Core/LatteConst.h +index ffbead1cf..0f8a7cecf 100644 +--- a/src/Cafe/HW/Latte/Core/LatteConst.h ++++ b/src/Cafe/HW/Latte/Core/LatteConst.h +@@ -103,6 +103,8 @@ using LatteIndexType = Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE; + + namespace LatteConst + { ++ using fmt::enums::format_as; ++ + enum class ShaderType : uint32 + { + Reserved = 0, +diff --git a/src/Cafe/HW/Latte/ISA/LatteInstructions.h b/src/Cafe/HW/Latte/ISA/LatteInstructions.h +index 702911045..b1d372e9a 100644 +--- a/src/Cafe/HW/Latte/ISA/LatteInstructions.h ++++ b/src/Cafe/HW/Latte/ISA/LatteInstructions.h +@@ -117,6 +117,11 @@ class LatteCFInstruction + uint32 word1; + }; + ++inline auto format_as(LatteCFInstruction::OPCODE opcode) ++{ ++ return fmt::underlying(opcode); ++} ++ + // default encoding, CF_DWORD0 + CF_DWORD1 + // used for opcodes: See list in MatchesOpcode() + class LatteCFInstruction_DEFAULT : public LatteCFInstruction +diff --git a/src/Cafe/HW/Latte/ISA/LatteReg.h b/src/Cafe/HW/Latte/ISA/LatteReg.h +index e539902f0..1b2d3955b 100644 +--- a/src/Cafe/HW/Latte/ISA/LatteReg.h ++++ b/src/Cafe/HW/Latte/ISA/LatteReg.h +@@ -2,6 +2,8 @@ + + namespace Latte + { ++ using fmt::enums::format_as; ++ + // common enums + enum class E_DIM : uint32 // shared between Latte backend and GX2 code + { +diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm b/src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm +index 731a6a267..30ac686c8 100644 +--- a/src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm ++++ b/src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm +@@ -53,7 +53,7 @@ VkSurfaceKHR CreateCocoaSurface(VkInstance instance, void* handle) + if ((err = vkCreateMetalSurfaceEXT(instance, &surface, nullptr, &result)) != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "Cannot create a Metal Vulkan surface: {}", (sint32)err); +- throw std::runtime_error(fmt::format("Cannot create a Metal Vulkan surface: {}", err)); ++ throw std::runtime_error(fmt::format("Cannot create a Metal Vulkan surface: {}", fmt::underlying(err))); + } + + return result; +diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp +index 804d03cc3..c813249a7 100644 +--- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp ++++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp +@@ -240,7 +240,7 @@ void RendererShaderVk::CreateVkShaderModule(std::span spirvBuffer) + if (result != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "Vulkan: Shader error"); +- throw std::runtime_error(fmt::format("Failed to create shader module: {}", result)); ++ throw std::runtime_error(fmt::format("Failed to create shader module: {}", fmt::underlying(result))); + } + + // set debug name +diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp +index 14b7a17cb..2c03ec10c 100644 +--- a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp ++++ b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp +@@ -214,7 +214,7 @@ bool SwapchainInfoVk::AcquireImage(uint64 timeout) + { + swapchainImageIndex = -1; + if (result != VK_ERROR_OUT_OF_DATE_KHR) +- throw std::runtime_error(fmt::format("Failed to acquire next image: {}", result)); ++ throw std::runtime_error(fmt::format("Failed to acquire next image: {}", fmt::underlying(result))); + return false; + } + m_currentSemaphore = acquireSemaphore; +@@ -249,7 +249,7 @@ SwapchainInfoVk::QueueFamilyIndices SwapchainInfoVk::FindQueueFamilies(VkSurface + VkBool32 presentSupport = false; + const VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); + if (result != VK_SUCCESS) +- throw std::runtime_error(fmt::format("Error while attempting to check if a surface supports presentation: {}", result)); ++ throw std::runtime_error(fmt::format("Error while attempting to check if a surface supports presentation: {}", fmt::underlying(result))); + + if (queueFamily.queueCount > 0 && presentSupport) + indices.presentFamily = i; +@@ -270,7 +270,7 @@ SwapchainInfoVk::SwapchainSupportDetails SwapchainInfoVk::QuerySwapchainSupport( + { + if (result != VK_ERROR_SURFACE_LOST_KHR) + cemuLog_log(LogType::Force, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed. Error {}", (sint32)result); +- throw std::runtime_error(fmt::format("Unable to retrieve physical device surface capabilities: {}", result)); ++ throw std::runtime_error(fmt::format("Unable to retrieve physical device surface capabilities: {}", fmt::underlying(result))); + } + + uint32_t formatCount = 0; +@@ -278,7 +278,7 @@ SwapchainInfoVk::SwapchainSupportDetails SwapchainInfoVk::QuerySwapchainSupport( + if (result != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "vkGetPhysicalDeviceSurfaceFormatsKHR failed. Error {}", (sint32)result); +- throw std::runtime_error(fmt::format("Unable to retrieve the number of formats for a surface on a physical device: {}", result)); ++ throw std::runtime_error(fmt::format("Unable to retrieve the number of formats for a surface on a physical device: {}", fmt::underlying(result))); + } + + if (formatCount != 0) +@@ -288,7 +288,7 @@ SwapchainInfoVk::SwapchainSupportDetails SwapchainInfoVk::QuerySwapchainSupport( + if (result != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "vkGetPhysicalDeviceSurfaceFormatsKHR failed. Error {}", (sint32)result); +- throw std::runtime_error(fmt::format("Unable to retrieve the formats for a surface on a physical device: {}", result)); ++ throw std::runtime_error(fmt::format("Unable to retrieve the formats for a surface on a physical device: {}", fmt::underlying(result))); + } + } + +@@ -297,7 +297,7 @@ SwapchainInfoVk::SwapchainSupportDetails SwapchainInfoVk::QuerySwapchainSupport( + if (result != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "vkGetPhysicalDeviceSurfacePresentModesKHR failed. Error {}", (sint32)result); +- throw std::runtime_error(fmt::format("Unable to retrieve the count of present modes for a surface on a physical device: {}", result)); ++ throw std::runtime_error(fmt::format("Unable to retrieve the count of present modes for a surface on a physical device: {}", fmt::underlying(result))); + } + + if (presentModeCount != 0) +@@ -307,7 +307,7 @@ SwapchainInfoVk::SwapchainSupportDetails SwapchainInfoVk::QuerySwapchainSupport( + if (result != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "vkGetPhysicalDeviceSurfacePresentModesKHR failed. Error {}", (sint32)result); +- throw std::runtime_error(fmt::format("Unable to retrieve the present modes for a surface on a physical device: {}", result)); ++ throw std::runtime_error(fmt::format("Unable to retrieve the present modes for a surface on a physical device: {}", fmt::underlying(result))); + } + } + +diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp +index ce582b9ac..e945d60bb 100644 +--- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp ++++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp +@@ -921,7 +921,7 @@ bool PipelineCompiler::InitFromCurrentGPUState(PipelineInfo* pipelineInfo, const + VkResult result = vkCreatePipelineLayout(vkRenderer->m_logicalDevice, &pipelineLayoutInfo, nullptr, &m_pipeline_layout); + if (result != VK_SUCCESS) + { +- cemuLog_log(LogType::Force, "Failed to create pipeline layout: {}", result); ++ cemuLog_log(LogType::Force, "Failed to create pipeline layout: {}", fmt::underlying(result)); + s_nvidiaWorkaround.unlock(); + return false; + } +diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +index 937e32663..f9be5879f 100644 +--- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp ++++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +@@ -141,7 +141,7 @@ std::vector VulkanRenderer::GetDevices() + { + VkResult err; + if ((err = vkCreateInstance(&create_info, nullptr, &instance)) != VK_SUCCESS) +- throw std::runtime_error(fmt::format("Unable to create a Vulkan instance: {}", err)); ++ throw std::runtime_error(fmt::format("Unable to create a Vulkan instance: {}", fmt::underlying(err))); + + if (!InitializeInstanceVulkan(instance)) + throw std::runtime_error("can't initialize instanced vulkan functions"); +@@ -358,7 +358,7 @@ VulkanRenderer::VulkanRenderer() + } + + if (err != VK_SUCCESS) +- throw std::runtime_error(fmt::format("Unable to create a Vulkan instance: {}", err)); ++ throw std::runtime_error(fmt::format("Unable to create a Vulkan instance: {}", fmt::underlying(err))); + + if (!InitializeInstanceVulkan(m_instance)) + throw std::runtime_error("Unable to load instanced Vulkan functions"); +@@ -495,7 +495,7 @@ VulkanRenderer::VulkanRenderer() + if (result != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "Vulkan: Unable to create a logical device. Error {}", (sint32)result); +- throw std::runtime_error(fmt::format("Unable to create a logical device: {}", result)); ++ throw std::runtime_error(fmt::format("Unable to create a logical device: {}", fmt::underlying(result))); + } + + InitializeDeviceVulkan(m_logicalDevice); +@@ -1112,12 +1112,12 @@ bool VulkanRenderer::CheckDeviceExtensionSupport(const VkPhysicalDevice device, + uint32_t extensionCount; + VkResult result = vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); + if (result != VK_SUCCESS) +- throw std::runtime_error(fmt::format("Cannot retrieve count of properties for a physical device: {}", result)); ++ throw std::runtime_error(fmt::format("Cannot retrieve count of properties for a physical device: {}", fmt::underlying(result))); + + availableDeviceExtensions.resize(extensionCount); + result = vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableDeviceExtensions.data()); + if (result != VK_SUCCESS) +- throw std::runtime_error(fmt::format("Cannot retrieve properties for a physical device: {}", result)); ++ throw std::runtime_error(fmt::format("Cannot retrieve properties for a physical device: {}", fmt::underlying(result))); + + std::set requiredExtensions(kRequiredDeviceExtensions.begin(), kRequiredDeviceExtensions.end()); + for (const auto& extension : availableDeviceExtensions) +@@ -1179,11 +1179,11 @@ std::vector VulkanRenderer::CheckInstanceExtensionSupport(FeatureCo + // get list of available instance extensions + uint32_t count; + if ((err = vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr)) != VK_SUCCESS) +- throw std::runtime_error(fmt::format("Failed to retrieve the instance extension properties : {}", err)); ++ throw std::runtime_error(fmt::format("Failed to retrieve the instance extension properties : {}", fmt::underlying(err))); + + availableInstanceExtensions.resize(count); + if ((err = vkEnumerateInstanceExtensionProperties(nullptr, &count, availableInstanceExtensions.data())) != VK_SUCCESS) +- throw std::runtime_error(fmt::format("Failed to retrieve the instance extension properties: {}", err)); ++ throw std::runtime_error(fmt::format("Failed to retrieve the instance extension properties: {}", fmt::underlying(err))); + + // build list of required extensions + std::vector requiredInstanceExtensions; +@@ -1270,7 +1270,7 @@ VkSurfaceKHR VulkanRenderer::CreateWinSurface(VkInstance instance, HWND hwindow) + if ((err = vkCreateWin32SurfaceKHR(instance, &sci, nullptr, &result)) != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "Cannot create a Win32 Vulkan surface: {}", (sint32)err); +- throw std::runtime_error(fmt::format("Cannot create a Win32 Vulkan surface: {}", err)); ++ throw std::runtime_error(fmt::format("Cannot create a Win32 Vulkan surface: {}", fmt::underlying(err))); + } + + return result; +@@ -1291,7 +1291,7 @@ VkSurfaceKHR VulkanRenderer::CreateXlibSurface(VkInstance instance, Display* dpy + if ((err = vkCreateXlibSurfaceKHR(instance, &sci, nullptr, &result)) != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "Cannot create a X11 Vulkan surface: {}", (sint32)err); +- throw std::runtime_error(fmt::format("Cannot create a X11 Vulkan surface: {}", err)); ++ throw std::runtime_error(fmt::format("Cannot create a X11 Vulkan surface: {}", fmt::underlying(err))); + } + + return result; +@@ -1310,7 +1310,7 @@ VkSurfaceKHR VulkanRenderer::CreateXcbSurface(VkInstance instance, xcb_connectio + if ((err = vkCreateXcbSurfaceKHR(instance, &sci, nullptr, &result)) != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "Cannot create a XCB Vulkan surface: {}", (sint32)err); +- throw std::runtime_error(fmt::format("Cannot create a XCB Vulkan surface: {}", err)); ++ throw std::runtime_error(fmt::format("Cannot create a XCB Vulkan surface: {}", fmt::underlying(err))); + } + + return result; +@@ -1329,7 +1329,7 @@ VkSurfaceKHR VulkanRenderer::CreateWaylandSurface(VkInstance instance, wl_displa + if ((err = vkCreateWaylandSurfaceKHR(instance, &sci, nullptr, &result)) != VK_SUCCESS) + { + cemuLog_log(LogType::Force, "Cannot create a Wayland Vulkan surface: {}", (sint32)err); +- throw std::runtime_error(fmt::format("Cannot create a Wayland Vulkan surface: {}", err)); ++ throw std::runtime_error(fmt::format("Cannot create a Wayland Vulkan surface: {}", fmt::underlying(err))); + } + + return result; +@@ -1363,7 +1363,7 @@ void VulkanRenderer::CreateCommandPool() + + VkResult result = vkCreateCommandPool(m_logicalDevice, &poolInfo, nullptr, &m_commandPool); + if (result != VK_SUCCESS) +- throw std::runtime_error(fmt::format("Failed to create command pool: {}", result)); ++ throw std::runtime_error(fmt::format("Failed to create command pool: {}", fmt::underlying(result))); + } + + void VulkanRenderer::CreateCommandBuffers() +@@ -1389,8 +1389,8 @@ void VulkanRenderer::CreateCommandBuffers() + const VkResult result = vkAllocateCommandBuffers(m_logicalDevice, &allocInfo, m_commandBuffers.data()); + if (result != VK_SUCCESS) + { +- cemuLog_log(LogType::Force, "Failed to allocate command buffers: {}", result); +- throw std::runtime_error(fmt::format("Failed to allocate command buffers: {}", result)); ++ cemuLog_log(LogType::Force, "Failed to allocate command buffers: {}", fmt::underlying(result)); ++ throw std::runtime_error(fmt::format("Failed to allocate command buffers: {}", fmt::underlying(result))); + } + + for (auto& semItr : m_commandBufferSemaphores) +@@ -1963,7 +1963,7 @@ void VulkanRenderer::SubmitCommandBuffer(VkSemaphore signalSemaphore, VkSemaphor + + const VkResult result = vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_cmd_buffer_fences[m_commandBufferIndex]); + if (result != VK_SUCCESS) +- UnrecoverableError(fmt::format("failed to submit command buffer. Error {}", result).c_str()); ++ UnrecoverableError(fmt::format("failed to submit command buffer. Error {}", fmt::underlying(result)).c_str()); + m_numSubmittedCmdBuffers++; + + // check if any previously submitted command buffers have finished execution +@@ -2101,7 +2101,7 @@ void VulkanRenderer::PipelineCacheSaveThread(size_t cache_size) + } + else + { +- cemuLog_log(LogType::Force, "can't retrieve pipeline cache data: 0x{:x}", res); ++ cemuLog_log(LogType::Force, "can't retrieve pipeline cache data: 0x{:x}", fmt::underlying(res)); + } + } + else +@@ -2140,7 +2140,7 @@ void VulkanRenderer::CreatePipelineCache() + createInfo.pInitialData = cacheData.data(); + VkResult result = vkCreatePipelineCache(m_logicalDevice, &createInfo, nullptr, &m_pipeline_cache); + if (result != VK_SUCCESS) +- UnrecoverableError(fmt::format("Failed to create pipeline cache: {}", result).c_str()); ++ UnrecoverableError(fmt::format("Failed to create pipeline cache: {}", fmt::underlying(result)).c_str()); + + size_t cache_size = 0; + vkGetPipelineCacheData(m_logicalDevice, m_pipeline_cache, &cache_size, nullptr); +@@ -2565,7 +2565,7 @@ VkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSet + + VkResult result = vkCreatePipelineLayout(m_logicalDevice, &pipelineLayoutInfo, nullptr, &m_pipelineLayout); + if (result != VK_SUCCESS) +- throw std::runtime_error(fmt::format("Failed to create pipeline layout: {}", result)); ++ throw std::runtime_error(fmt::format("Failed to create pipeline layout: {}", fmt::underlying(result))); + + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; +@@ -2588,8 +2588,8 @@ VkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSet + result = vkCreateGraphicsPipelines(m_logicalDevice, m_pipeline_cache, 1, &pipelineInfo, nullptr, &pipeline); + if (result != VK_SUCCESS) + { +- cemuLog_log(LogType::Force, "Failed to create graphics pipeline. Error {}", result); +- throw std::runtime_error(fmt::format("Failed to create graphics pipeline: {}", result)); ++ cemuLog_log(LogType::Force, "Failed to create graphics pipeline. Error {}", fmt::underlying(result)); ++ throw std::runtime_error(fmt::format("Failed to create graphics pipeline: {}", fmt::underlying(result))); + } + + s_pipeline_cache[hash] = pipeline; +@@ -2730,7 +2730,7 @@ void VulkanRenderer::SwapBuffer(bool mainWindow) + VkResult result = vkQueuePresentKHR(m_presentQueue, &presentInfo); + if (result < 0 && result != VK_ERROR_OUT_OF_DATE_KHR) + { +- throw std::runtime_error(fmt::format("Failed to present image: {}", result)); ++ throw std::runtime_error(fmt::format("Failed to present image: {}", fmt::underlying(result))); + } + if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) + chainInfo.m_shouldRecreate = true; +diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp +index 6d5d94025..37681b51a 100644 +--- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp ++++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp +@@ -353,7 +353,7 @@ CopySurfacePipelineInfo* VulkanRenderer::copySurface_getOrCreateGraphicsPipeline + VkResult result = vkCreatePipelineLayout(m_logicalDevice, &pipelineLayoutInfo, nullptr, &vkObjPipeline->pipeline_layout); + if (result != VK_SUCCESS) + { +- cemuLog_log(LogType::Force, "Failed to create pipeline layout: {}", result); ++ cemuLog_log(LogType::Force, "Failed to create pipeline layout: {}", fmt::underlying(result)); + vkObjPipeline->pipeline = VK_NULL_HANDLE; + return copyPipeline; + } +diff --git a/src/Cafe/IOSU/fsa/fsa_types.h b/src/Cafe/IOSU/fsa/fsa_types.h +index a7757486f..de1e46f34 100644 +--- a/src/Cafe/IOSU/fsa/fsa_types.h ++++ b/src/Cafe/IOSU/fsa/fsa_types.h +@@ -40,6 +40,11 @@ enum class FSA_RESULT : sint32 // aka FSError/FSAStatus + FATAL_ERROR = -0x30000 - 0x400, + }; + ++inline auto format_as(FSA_RESULT result) ++{ ++ return fmt::underlying(result); ++} ++ + enum class FSA_CMD_OPERATION_TYPE : uint32 + { + CHANGEDIR = 0x5, +diff --git a/src/Cafe/OS/libs/TCL/TCL.cpp b/src/Cafe/OS/libs/TCL/TCL.cpp +index d0c29d445..dff4050c5 100644 +--- a/src/Cafe/OS/libs/TCL/TCL.cpp ++++ b/src/Cafe/OS/libs/TCL/TCL.cpp +@@ -3,6 +3,7 @@ + + namespace TCL + { ++ using fmt::enums::format_as; + + enum class TCL_SUBMISSION_FLAG : uint32 + { +diff --git a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp +index 26636eaed..3b79b65ad 100644 +--- a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp ++++ b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp +@@ -42,6 +42,8 @@ bool strcpy_whole(char* dst, size_t dstLength, const char* src) + + namespace coreinit + { ++ using fmt::enums::format_as; ++ + std::mutex sFSClientLock; + std::recursive_mutex sFSGlobalMutex; + +diff --git a/src/Cafe/OS/libs/coreinit/coreinit_HWInterface.cpp b/src/Cafe/OS/libs/coreinit/coreinit_HWInterface.cpp +index b95720f70..a32d43b6a 100644 +--- a/src/Cafe/OS/libs/coreinit/coreinit_HWInterface.cpp ++++ b/src/Cafe/OS/libs/coreinit/coreinit_HWInterface.cpp +@@ -3,6 +3,8 @@ + + namespace coreinit + { ++ using fmt::enums::format_as; ++ + enum class RegisterInterfaceId : uint32 // for __OSRead/__OSWrite API (register access in userspace) + { + INTERFACE_VI_UKN = 0, // 0x0C1E0000 +diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MEM.h b/src/Cafe/OS/libs/coreinit/coreinit_MEM.h +index 7e5831951..7d6dff487 100644 +--- a/src/Cafe/OS/libs/coreinit/coreinit_MEM.h ++++ b/src/Cafe/OS/libs/coreinit/coreinit_MEM.h +@@ -49,6 +49,8 @@ void coreinitExport_MEMGetBaseHeapHandle(PPCInterpreter_t* hCPU); + + namespace coreinit + { ++ using fmt::enums::format_as; ++ + #define MEM_HEAP_INVALID_HANDLE (nullptr) + #define MEM_HEAP_DEFAULT_ALIGNMENT 4 + #define MIN_ALIGNMENT 4 +diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MEM_FrmHeap.h b/src/Cafe/OS/libs/coreinit/coreinit_MEM_FrmHeap.h +index 43556ec43..bcb1c7252 100644 +--- a/src/Cafe/OS/libs/coreinit/coreinit_MEM_FrmHeap.h ++++ b/src/Cafe/OS/libs/coreinit/coreinit_MEM_FrmHeap.h +@@ -3,6 +3,8 @@ + + namespace coreinit + { ++ using fmt::enums::format_as; ++ + struct MEMFrmHeapRecordedState + { + uint32be id; +diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Thread.h b/src/Cafe/OS/libs/coreinit/coreinit_Thread.h +index e2f5bef2b..a3cbfa973 100644 +--- a/src/Cafe/OS/libs/coreinit/coreinit_Thread.h ++++ b/src/Cafe/OS/libs/coreinit/coreinit_Thread.h +@@ -87,6 +87,7 @@ static_assert(sizeof(crt_t) == 0x1D8, ""); + + namespace coreinit + { ++ using fmt::enums::format_as; + + /********* OSThreadQueue *********/ + +@@ -492,6 +493,11 @@ struct OSThread_t + /* +0x680 */ uint32 padding680[28 / 4]; + }; + ++inline auto format_as(OSThread_t::THREAD_TYPE type) ++{ ++ return fmt::underlying(type); ++} ++ + static_assert(sizeof(OSThread_t) == 0x6A0-4); // todo - determine correct size + + namespace coreinit +diff --git a/src/Cafe/OS/libs/gx2/GX2_Blit.h b/src/Cafe/OS/libs/gx2/GX2_Blit.h +index f8256f515..d1b8a70c0 100644 +--- a/src/Cafe/OS/libs/gx2/GX2_Blit.h ++++ b/src/Cafe/OS/libs/gx2/GX2_Blit.h +@@ -2,6 +2,8 @@ + + namespace GX2 + { ++ using fmt::enums::format_as; ++ + enum class GX2ClearFlags : uint32 + { + CLEAR_DEPTH = 0x01, // clear depth to given clear value +diff --git a/src/Cafe/OS/libs/gx2/GX2_Command.cpp b/src/Cafe/OS/libs/gx2/GX2_Command.cpp +index 8d5841904..b3edd939c 100644 +--- a/src/Cafe/OS/libs/gx2/GX2_Command.cpp ++++ b/src/Cafe/OS/libs/gx2/GX2_Command.cpp +@@ -42,6 +42,8 @@ void gx2WriteGather_submitU32AsLEArray(uint32* v, uint32 numValues) + + namespace GX2 + { ++ using fmt::enums::format_as; ++ + sint32 gx2WriteGatherCurrentMainCoreIndex = -1; + bool gx2WriteGatherInited = false; + +diff --git a/src/Cafe/OS/libs/gx2/GX2_Event.cpp b/src/Cafe/OS/libs/gx2/GX2_Event.cpp +index ba498477d..1b8c2a75d 100644 +--- a/src/Cafe/OS/libs/gx2/GX2_Event.cpp ++++ b/src/Cafe/OS/libs/gx2/GX2_Event.cpp +@@ -12,6 +12,7 @@ + + namespace GX2 + { ++ using fmt::enums::format_as; + + SysAllocator g_vsyncThreadQueue; + SysAllocator g_flipThreadQueue; +diff --git a/src/Cafe/OS/libs/gx2/GX2_Event.h b/src/Cafe/OS/libs/gx2/GX2_Event.h +index 09cb073c2..e59fa89b5 100644 +--- a/src/Cafe/OS/libs/gx2/GX2_Event.h ++++ b/src/Cafe/OS/libs/gx2/GX2_Event.h +@@ -2,6 +2,8 @@ + + namespace GX2 + { ++ using fmt::enums::format_as; ++ + void GX2Init_event(); + void GX2EventResetToDefaultState(); + +diff --git a/src/Cafe/OS/libs/gx2/GX2_Misc.h b/src/Cafe/OS/libs/gx2/GX2_Misc.h +index e6ac8010c..f7a76c799 100644 +--- a/src/Cafe/OS/libs/gx2/GX2_Misc.h ++++ b/src/Cafe/OS/libs/gx2/GX2_Misc.h +@@ -2,6 +2,8 @@ + + namespace GX2 + { ++ using fmt::enums::format_as; ++ + extern uint32 sGX2MainCoreIndex; + + enum class E_TVRES +diff --git a/src/Cafe/OS/libs/gx2/GX2_Shader.h b/src/Cafe/OS/libs/gx2/GX2_Shader.h +index 1d1c79cc6..d48a9b0ec 100644 +--- a/src/Cafe/OS/libs/gx2/GX2_Shader.h ++++ b/src/Cafe/OS/libs/gx2/GX2_Shader.h +@@ -23,6 +23,11 @@ struct GX2FetchShader_t + } + }; + ++inline auto format_as(GX2FetchShader_t::FetchShaderType type) ++{ ++ return fmt::underlying(type); ++} ++ + static_assert(sizeof(GX2FetchShader_t) == 0x20); + static_assert(sizeof(betype) == 4); + +diff --git a/src/Cafe/OS/libs/gx2/GX2_State.cpp b/src/Cafe/OS/libs/gx2/GX2_State.cpp +index d9c0420f3..e09933209 100644 +--- a/src/Cafe/OS/libs/gx2/GX2_State.cpp ++++ b/src/Cafe/OS/libs/gx2/GX2_State.cpp +@@ -7,6 +7,8 @@ + + namespace GX2 + { ++ using fmt::enums::format_as; ++ + using namespace Latte; + + void GX2InitAlphaTestReg(GX2AlphaTestReg* reg, uint32 alphaTestEnable, GX2_ALPHAFUNC alphaFunc, float alphaRef) +diff --git a/src/Cafe/OS/libs/nn_acp/nn_acp.h b/src/Cafe/OS/libs/nn_acp/nn_acp.h +index cbf36c643..586f8af4d 100644 +--- a/src/Cafe/OS/libs/nn_acp/nn_acp.h ++++ b/src/Cafe/OS/libs/nn_acp/nn_acp.h +@@ -4,6 +4,8 @@ namespace nn + { + namespace acp + { ++ using fmt::enums::format_as; ++ + enum ACPStatus : uint32 + { + SUCCESS = 0, +diff --git a/src/Cafe/OS/libs/nn_boss/nn_boss.cpp b/src/Cafe/OS/libs/nn_boss/nn_boss.cpp +index c2d65a5f3..0cdfe1a41 100644 +--- a/src/Cafe/OS/libs/nn_boss/nn_boss.cpp ++++ b/src/Cafe/OS/libs/nn_boss/nn_boss.cpp +@@ -23,6 +23,8 @@ memset(bossRequest, 0, sizeof(iosuBossCemuRequest_t)); \ + memset(bossBufferVector, 0, sizeof(ioBufferVector_t)); \ + bossBufferVector->buffer = (uint8*)bossRequest; + ++ using fmt::enums::format_as; ++ + SysAllocator g_mutex; + sint32 g_initCounter = 0; + bool g_isInitialized = false; +diff --git a/src/Cafe/OS/libs/nn_ndm/nn_ndm.cpp b/src/Cafe/OS/libs/nn_ndm/nn_ndm.cpp +index 5a69b787e..1d87c39a4 100644 +--- a/src/Cafe/OS/libs/nn_ndm/nn_ndm.cpp ++++ b/src/Cafe/OS/libs/nn_ndm/nn_ndm.cpp +@@ -6,6 +6,7 @@ namespace nn + { + namespace ndm + { ++ using fmt::enums::format_as; + + enum class DAEMON_NAME : uint32 + { +diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_PostTypes.h b/src/Cafe/OS/libs/nn_olv/nn_olv_PostTypes.h +index e6078a7aa..547253c7f 100644 +--- a/src/Cafe/OS/libs/nn_olv/nn_olv_PostTypes.h ++++ b/src/Cafe/OS/libs/nn_olv/nn_olv_PostTypes.h +@@ -6,6 +6,8 @@ namespace nn + { + namespace olv + { ++ using fmt::enums::format_as; ++ + struct DownloadedDataBase + { + enum class FLAGS : uint32 +diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h +index d55256c9d..75f3c4cae 100644 +--- a/src/Cemu/Logging/CemuLogging.h ++++ b/src/Cemu/Logging/CemuLogging.h +@@ -60,21 +60,6 @@ bool cemuLog_log(LogType type, std::u8string_view text); + bool cemuLog_log(LogType type, std::wstring_view text); + void cemuLog_waitForFlush(); // wait until all log lines are written + +-template +-auto ForwardEnum(T t) +-{ +- if constexpr (std::is_enum_v) +- return fmt::underlying(t); +- else +- return std::forward(t); +-} +- +-template +-auto ForwardEnum(std::tuple t) +-{ +- return std::apply([](auto... x) { return std::make_tuple(ForwardEnum(x)...); }, t); +-} +- + template + bool cemuLog_log(LogType type, std::basic_string formatStr, TArgs&&... args) + { +@@ -88,7 +73,7 @@ bool cemuLog_log(LogType type, std::basic_string formatStr, TArgs&&... args) + else + { + const auto format_view = fmt::basic_string_view(formatStr); +- const auto text = fmt::vformat(format_view, fmt::make_format_args>(ForwardEnum(args)...)); ++ const auto text = fmt::vformat(format_view, fmt::make_format_args>(args...)); + cemuLog_log(type, std::basic_string_view(text.data(), text.size())); + } + return true; +diff --git a/src/Cemu/napi/napi.h b/src/Cemu/napi/napi.h +index ab17a7b30..df346daa8 100644 +--- a/src/Cemu/napi/napi.h ++++ b/src/Cemu/napi/napi.h +@@ -11,8 +11,15 @@ enum class NAPI_RESULT + SERVICE_ERROR = 4, // server reply indicates error. Extended error code (serviceError) is set + }; + ++inline auto format_as(NAPI_RESULT apiError) ++{ ++ return fmt::underlying(apiError); ++} ++ + namespace NAPI + { ++ using fmt::enums::format_as; ++ + // common auth info structure shared by ACT, ECS and IAS service + struct AuthInfo + { +diff --git a/src/Common/MemPtr.h b/src/Common/MemPtr.h +index dc1ecd36d..d8e4e945d 100644 +--- a/src/Common/MemPtr.h ++++ b/src/Common/MemPtr.h +@@ -159,5 +159,5 @@ template + struct fmt::formatter> : formatter + { + template +- auto format(const MEMPTR& v, FormatContext& ctx) { return formatter::format(fmt::format("{:#x}", v.GetMPTR()), ctx); } ++ auto format(const MEMPTR& v, FormatContext& ctx) const { return formatter::format(fmt::format("{:#x}", v.GetMPTR()), ctx); } + }; +diff --git a/src/Common/betype.h b/src/Common/betype.h +index e684fb933..27e43af86 100644 +--- a/src/Common/betype.h ++++ b/src/Common/betype.h +@@ -204,6 +204,12 @@ class betype + T m_value; + }; + ++template ++inline auto format_as(const betype& v) ++{ ++ return v.value(); ++} ++ + using uint64be = betype; + using uint32be = betype; + using uint16be = betype; +diff --git a/src/Common/precompiled.h b/src/Common/precompiled.h +index 7152f2c12..2c4dfa9ea 100644 +--- a/src/Common/precompiled.h ++++ b/src/Common/precompiled.h +@@ -16,13 +16,9 @@ + + #define SDL_MAIN_HANDLED + +-// #if FMT_VERSION > 80102 +-// // restore generic formatter for enum (class) to underlying. We currently utilize this for HLE call logging +-// template ::value, int> = 0> +-// constexpr auto format_as(Enum e) noexcept -> std::underlying_type { +-// return static_cast>(e); +-// } +-// #endif ++#if FMT_VERSION >= 100000 ++using fmt::enums::format_as; ++#endif + + // arch defines + +diff --git a/src/audio/IAudioAPI.h b/src/audio/IAudioAPI.h +index 935e30245..846be84db 100644 +--- a/src/audio/IAudioAPI.h ++++ b/src/audio/IAudioAPI.h +@@ -82,6 +82,11 @@ class IAudioAPI + + }; + ++inline auto format_as(IAudioAPI::AudioAPI api) ++{ ++ return fmt::underlying(api); ++} ++ + using AudioAPIPtr = std::unique_ptr; + extern std::shared_mutex g_audioMutex; + extern AudioAPIPtr g_tvAudio; +diff --git a/src/audio/IAudioInputAPI.h b/src/audio/IAudioInputAPI.h +index 66c431657..a85bf406e 100644 +--- a/src/audio/IAudioInputAPI.h ++++ b/src/audio/IAudioInputAPI.h +@@ -66,6 +66,11 @@ class IAudioInputAPI + private: + }; + ++inline auto format_as(IAudioInputAPI::AudioInputAPI api) ++{ ++ return fmt::underlying(api); ++} ++ + using AudioInputAPIPtr = std::unique_ptr; + extern std::shared_mutex g_audioInputMutex; + extern AudioInputAPIPtr g_inputAudio; +diff --git a/src/input/api/InputAPI.h b/src/input/api/InputAPI.h +index 07ae16cfd..128cb3d68 100644 +--- a/src/input/api/InputAPI.h ++++ b/src/input/api/InputAPI.h +@@ -49,6 +49,11 @@ namespace InputAPI + throw std::runtime_error(fmt::format("unknown input api: {}", to_underlying(type))); + } + ++ inline auto format_as(Type type) ++ { ++ return to_string(type); ++ } ++ + constexpr Type from_string(std::string_view str) + { + if (str == to_string(Keyboard)) +diff --git a/src/util/EventService.h b/src/util/EventService.h +index 4fe1737a6..6b1ece77e 100644 +--- a/src/util/EventService.h ++++ b/src/util/EventService.h +@@ -10,6 +10,11 @@ enum class Events : int32_t + ControllerChanged, + }; + ++inline auto format_as(Events event) ++{ ++ return fmt::underlying(event); ++} ++ + using ControllerChangedFunc = void(void); + + class EventService : public Singleton