From 88b3dff27879910b33a7c8657060f37409641873 Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Thu, 29 May 2025 22:21:05 +0200 Subject: [PATCH] citra_common: Enable SSE4.2 on x86_64 builds Enables the use of SSE4.2 instructions on x86_64 CPUs, allowing compilers to automatically vectorize some loops on citra_common. A CMake toggle ENABLE_SSE42 (ON by default) has been added to enable this behaviour. This change breaks compatibility with CPUs that do not have SSE4.2 instructions. All modern CPUs (from 2011 onwards) should always have these instructions. Manual compilation will be needed for older CPUs. A message has been added to report if the CPU is incompatible when starting the emulator. Co-authored-by: OpenSauce04 --- CMakeLists.txt | 11 ++++++++ src/citra_meta/CMakeLists.txt | 4 +++ src/citra_meta/main.cpp | 53 +++++++++++++++++++++++++++++++++++ src/common/CMakeLists.txt | 5 ++++ 4 files changed, 73 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5de1ddec..54051a4ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,6 +105,8 @@ option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) option(ENABLE_MICROPROFILE "Enables microprofile capabilities" OFF) +option(ENABLE_SSE42 "Enable SSE4.2 optimizations on x86_64" ON) + # Compile options CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ${IS_DEBUG_BUILD} "MINGW" OFF) option(ENABLE_LTO "Enable link time optimization" ${DEFAULT_ENABLE_LTO}) @@ -126,6 +128,15 @@ if (ENABLE_SDL2_FRONTEND) add_definitions(-DENABLE_SDL2_FRONTEND) endif() +if(ENABLE_SSE42 AND (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")) + message(STATUS "SSE4.2 enabled for x86_64") + if(MSVC) + SET(SSE42_COMPILE_OPTION /arch:SSE4.2) + else() + SET(SSE42_COMPILE_OPTION -msse4.1 -msse4.2) + endif() +endif() + include(CitraHandleSystemLibs) if (CITRA_USE_PRECOMPILED_HEADERS) diff --git a/src/citra_meta/CMakeLists.txt b/src/citra_meta/CMakeLists.txt index 68f35bbae..9f9dcd574 100644 --- a/src/citra_meta/CMakeLists.txt +++ b/src/citra_meta/CMakeLists.txt @@ -77,6 +77,10 @@ if (CITRA_USE_PRECOMPILED_HEADERS) target_precompile_headers(citra_meta PRIVATE precompiled_headers.h) endif() +if (SSE42_COMPILE_OPTION) + target_compile_definitions(citra_meta PRIVATE CITRA_HAS_SSE42) +endif() + # Bundle in-place on MSVC so dependencies can be resolved by builds. if (ENABLE_QT AND MSVC) include(BundleTarget) diff --git a/src/citra_meta/main.cpp b/src/citra_meta/main.cpp index 5c8936f30..8b581af6c 100644 --- a/src/citra_meta/main.cpp +++ b/src/citra_meta/main.cpp @@ -21,7 +21,60 @@ __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; } #endif +#if CITRA_HAS_SSE42 +#if defined(_WIN32) +#include +#if defined(_MSC_VER) +#include +#else +#include +#endif // _MSC_VER +#else +#include +#endif // _WIN32 + +static bool CpuSupportsSSE42() { + uint32_t ecx; + +#if defined(_MSC_VER) + int cpu_info[4]; + __cpuid(cpu_info, 1); + ecx = static_cast(cpu_info[2]); +#elif defined(__GNUC__) || defined(__clang__) + uint32_t eax, ebx, edx; + if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { + return false; + } +#else +#error "Unsupported compiler" +#endif + + // Bit 20 of ECX indicates SSE4.2 + return (ecx & (1 << 20)) != 0; +} + +static bool CheckAndReportSSE42() { + if (!CpuSupportsSSE42()) { + const std::string error_msg = + "This application requires a CPU with SSE4.2 support or higher.\nTo run on unsupported " + "systems, recompile the application with the ENABLE_SSE42 option disabled."; +#if defined(_WIN32) + MessageBoxA(nullptr, error_msg.c_str(), "Incompatible CPU", MB_OK | MB_ICONERROR); +#endif + std::cerr << "Error: " << error_msg << std::endl; + return false; + } + return true; +} +#endif + int main(int argc, char* argv[]) { +#if CITRA_HAS_SSE42 + if (!CheckAndReportSSE42()) { + return 1; + } +#endif + #if ENABLE_ROOM bool launch_room = false; for (int i = 1; i < argc; i++) { diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 1bf1c2182..6aceceaa4 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -206,3 +206,8 @@ if (BACKTRACE_LIBRARY AND ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND CMAKE_CXX_CO target_link_libraries(citra_common PRIVATE ${BACKTRACE_LIBRARY} dl) target_compile_definitions(citra_common PRIVATE CITRA_LINUX_GCC_BACKTRACE) endif() + +if (SSE42_COMPILE_OPTION) + target_compile_definitions(citra_common PRIVATE CITRA_HAS_SSE42) + target_compile_options(citra_common PRIVATE ${SSE42_COMPILE_OPTION}) +endif() \ No newline at end of file