From 0fa148e65e9c520339177d407b2029602b8912a0 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 18 Jul 2017 15:21:29 +0300 Subject: [PATCH] Improve CPU feature check Damn exit on SSSE3 failure Check AVX for Intel processors --- Utilities/JIT.cpp | 15 ++++++ Utilities/sysinfo.cpp | 50 ++++++++++++++++++++ Utilities/sysinfo.h | 35 ++++++++++++++ rpcs3/emucore.vcxproj | 8 ++++ rpcs3/emucore.vcxproj.filters | 6 +++ rpcs3/rpcs3.vcxproj | 1 - rpcs3/rpcs3.vcxproj.filters | 3 -- rpcs3/rpcs3qt/log_frame.cpp | 4 +- rpcs3/rpcs3qt/main_window.cpp | 10 ++-- rpcs3/rpcs3qt/system_info.h | 86 ----------------------------------- 10 files changed, 121 insertions(+), 97 deletions(-) create mode 100644 Utilities/sysinfo.cpp create mode 100644 Utilities/sysinfo.h delete mode 100644 rpcs3/rpcs3qt/system_info.h diff --git a/Utilities/JIT.cpp b/Utilities/JIT.cpp index 7b01109c80..7a22d33b7c 100644 --- a/Utilities/JIT.cpp +++ b/Utilities/JIT.cpp @@ -12,6 +12,7 @@ #include "File.h" #include "Log.h" #include "mutex.h" +#include "sysinfo.h" #include "VirtualMemory.h" #ifdef _MSC_VER @@ -377,6 +378,20 @@ jit_compiler::jit_compiler(const std::unordered_map if (m_cpu.empty()) { m_cpu = llvm::sys::getHostCPUName(); + + if (m_cpu == "sandybridge" || + m_cpu == "ivybridge" || + m_cpu == "haswell" || + m_cpu == "broadwell" || + m_cpu == "skylake" || + m_cpu == "skylake-avx512" || + m_cpu == "cannonlake") + { + if (!utils::has_avx()) + { + m_cpu = "nehalem"; + } + } } std::string result; diff --git a/Utilities/sysinfo.cpp b/Utilities/sysinfo.cpp new file mode 100644 index 0000000000..fe1593d453 --- /dev/null +++ b/Utilities/sysinfo.cpp @@ -0,0 +1,50 @@ +#include "sysinfo.h" +#include "StrFmt.h" + +#ifdef _WIN32 +#include "windows.h" +#else +#include +#endif + +std::string utils::get_system_info() +{ + std::string result; + std::string brand; + + if (get_cpuid(0x80000000, 0)[0] >= 0x80000004) + { + for (u32 i = 0; i < 3; i++) + { + brand.append(reinterpret_cast(get_cpuid(0x80000002 + i, 0).data()), 16); + } + } + else + { + brand = "Unknown CPU"; + } + + brand.erase(0, brand.find_first_not_of(' ')); + brand.erase(brand.find_last_not_of(' ') + 1); + + while (auto found = brand.find(" ") + 1) + { + brand.erase(brand.begin() + found); + } + +#ifdef _WIN32 + ::SYSTEM_INFO sysInfo; + ::GetNativeSystemInfo(&sysInfo); + ::MEMORYSTATUSEX memInfo; + memInfo.dwLength = sizeof(memInfo); + ::GlobalMemoryStatusEx(&memInfo); + const u32 num_proc = sysInfo.dwNumberOfProcessors; + const u64 mem_total = memInfo.ullTotalPhys; +#else + const u32 num_proc = ::sysconf(_SC_NPROCESSORS_ONLN); + const u64 mem_total = ::sysconf(_SC_PHYS_PAGES) * ::sysconf(_SC_PAGE_SIZE); +#endif + + fmt::append(result, "%s | %d Threads | %.2f GiB RAM", brand, num_proc, mem_total / (1024.0f * 1024 * 1024)); + return result; +} diff --git a/Utilities/sysinfo.h b/Utilities/sysinfo.h new file mode 100644 index 0000000000..6a719fa92c --- /dev/null +++ b/Utilities/sysinfo.h @@ -0,0 +1,35 @@ +#pragma once + +#include "types.h" +#include + +namespace utils +{ + inline std::array get_cpuid(u32 func, u32 subfunc) + { + int regs[4]; +#ifdef _MSC_VER + __cpuidex(regs, func, subfunc); +#else + __asm__ volatile("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3]) : "a" (func), "c" (subfunc)); +#endif + return {0u+regs[0], 0u+regs[1], 0u+regs[2], 0u+regs[3]}; + } + + inline bool has_ssse3() + { + return get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x200; + } + + inline bool has_avx() + { + return get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x10000000; + } + + inline bool has_rtm() + { + return get_cpuid(0, 0)[0] >= 0x7 && get_cpuid(7, 0)[1] & 0x800; + } + + std::string get_system_info(); +} diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 126049bf4e..6f4ebf683b 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -102,6 +102,13 @@ NotUsing + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + @@ -426,6 +433,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index c29c37d3a6..6afa94c69e 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -923,6 +923,9 @@ Emu\Cell\lv2 + + Utilities + @@ -1777,5 +1780,8 @@ Utilities + + Utilities + \ No newline at end of file diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 1c51cba33a..3b73722692 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -1201,7 +1201,6 @@ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" - diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index cd8191d3e4..25341f839d 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -514,9 +514,6 @@ Generated Files - - Gui - Gui diff --git a/rpcs3/rpcs3qt/log_frame.cpp b/rpcs3/rpcs3qt/log_frame.cpp index 47d2ba83e3..65c2e60c64 100644 --- a/rpcs3/rpcs3qt/log_frame.cpp +++ b/rpcs3/rpcs3qt/log_frame.cpp @@ -2,7 +2,7 @@ #include #include "rpcs3_version.h" -#include "system_info.h" +#include "Utilities/sysinfo.h" #include #include @@ -40,7 +40,7 @@ struct gui_listener : logs::listener read = new packet; last = new packet; read->next = last.load(); - last->msg = fmt::format("RPCS3 v%s\n%s\n", rpcs3::version.to_string(), System_Info::getCPU().first); + last->msg = fmt::format("RPCS3 v%s\n%s\n", rpcs3::version.to_string(), utils::get_system_info()); // Self-registration logs::listener::add(this); diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index d9b9d11f6d..dcea5be701 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -41,7 +41,7 @@ #include "Utilities/StrUtil.h" #include "rpcs3_version.h" -#include "system_info.h" +#include "Utilities/sysinfo.h" #include "ui_main_window.h" @@ -112,13 +112,13 @@ void main_window::Init() RequestGlobalStylesheetChange(guiSettings->GetCurrentStylesheetPath()); ConfigureGuiFromSettings(true); - if (!System_Info::getCPU().second) + if (!utils::has_ssse3()) { QMessageBox::critical(this, "SSSE3 Error (with three S, not two)", "Your system does not meet the minimum requirements needed to run RPCS3.\n" - "Your CPU does not support SSSE3 (with three S, not two).\n" - "\n" - "No games will run and RPCS3 will crash if you try."); + "Your CPU does not support SSSE3 (with three S, not two).\n"); + + std::exit(EXIT_FAILURE); } } diff --git a/rpcs3/rpcs3qt/system_info.h b/rpcs3/rpcs3qt/system_info.h deleted file mode 100644 index 77c5540eaf..0000000000 --- a/rpcs3/rpcs3qt/system_info.h +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#include - -#ifdef _WIN32 -#include "windows.h" -#include -typedef unsigned __int32 uint32_t; -#else -#include -#include -#include -#endif - -class System_Info -{ - class CPUID { - uint32_t regs[4]; - - public: - explicit CPUID(uint32_t func, uint32_t subfunc) { -#ifdef _WIN32 - __cpuidex((int *)regs, func, subfunc); -#else - asm volatile - ("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3]) - : "a" (func), "c" (subfunc)); - // ECX is set to zero for CPUID function 4 -#endif - } - - const uint32_t &EAX() const { return regs[0]; } - const uint32_t &EBX() const { return regs[1]; } - const uint32_t &ECX() const { return regs[2]; } - const uint32_t &EDX() const { return regs[3]; } - const uint32_t *data() const { return ®s[0]; } - }; - -public: - - /** - Retrieves various information about the system's hardware - @return a pair consisting of the compiled information as string value and a bool for SSSE3 compatibility - */ - static const std::pair getCPU() - { - int nIds_ = 0; - int nExIds_ = 0; - char brand[0x40]; - std::bitset<32> cpu_capabilities = 0; - - nIds_ = CPUID(0, 0).EAX(); - // load bitset with flags for function 0x00000001 - if (nIds_ >= 1) - { - cpu_capabilities = CPUID(1, 0).ECX(); - } - - nExIds_ = CPUID(0x80000000, 0).EAX(); - memset(brand, 0, sizeof(brand)); - if (nExIds_ >= 0x80000004) - { - memcpy(brand, CPUID(0x80000002, 0).data(), 16); - memcpy(brand + 16, CPUID(0x80000003, 0).data(), 16); - memcpy(brand + 32, CPUID(0x80000004, 0).data(), 16); - } - - bool supports_ssse3 = cpu_capabilities[9]; - - std::string s_sysInfo = fmt::format("%s | SSSE3 %s", std::regex_replace(brand, std::regex("^ +"), ""), supports_ssse3 ? "Supported" : "Not Supported"); - -#ifdef _WIN32 - SYSTEM_INFO sysInfo; - GetNativeSystemInfo(&sysInfo); - MEMORYSTATUSEX memInfo; - memInfo.dwLength = sizeof(memInfo); - GlobalMemoryStatusEx(&memInfo); - s_sysInfo += fmt::format(" | %d Threads | %.2f GB RAM", sysInfo.dwNumberOfProcessors, (float)memInfo.ullTotalPhys / std::pow(1024.0f, 3)); -#else - long mem_total = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE); - s_sysInfo += fmt::format(" | %d Threads | %.2f GB RAM", sysconf(_SC_NPROCESSORS_ONLN), (float)mem_total / std::pow(1024.0f, 3)); -#endif - - return std::pair(s_sysInfo, supports_ssse3); - }; -};