diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 3b73722692..1c51cba33a 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -1201,6 +1201,7 @@ .\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 25341f839d..cd8191d3e4 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -514,6 +514,9 @@ Generated Files + + Gui + Gui diff --git a/rpcs3/rpcs3qt/log_frame.cpp b/rpcs3/rpcs3qt/log_frame.cpp index a5a7f24d44..47d2ba83e3 100644 --- a/rpcs3/rpcs3qt/log_frame.cpp +++ b/rpcs3/rpcs3qt/log_frame.cpp @@ -2,6 +2,7 @@ #include #include "rpcs3_version.h" +#include "system_info.h" #include #include @@ -39,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", rpcs3::version.to_string()); + last->msg = fmt::format("RPCS3 v%s\n%s\n", rpcs3::version.to_string(), System_Info::getCPU().first); // Self-registration logs::listener::add(this); diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index c43985408a..f5d425a4a0 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -41,6 +41,7 @@ #include "Utilities/StrUtil.h" #include "rpcs3_version.h" +#include "system_info.h" #include "ui_main_window.h" @@ -110,6 +111,15 @@ void main_window::Init() RequestGlobalStylesheetChange(guiSettings->GetCurrentStylesheetPath()); ConfigureGuiFromSettings(true); + + if (!System_Info::getCPU().second) + { + 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."); + } } void main_window::CreateThumbnailToolbar() diff --git a/rpcs3/rpcs3qt/system_info.h b/rpcs3/rpcs3qt/system_info.h new file mode 100644 index 0000000000..77c5540eaf --- /dev/null +++ b/rpcs3/rpcs3qt/system_info.h @@ -0,0 +1,86 @@ +#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); + }; +};