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);
+ };
+};