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