mirror of https://github.com/PCSX2/pcsx2.git
Qt: Add hardware check for SSE4 and AVX2
This commit is contained in:
parent
c70afc24bd
commit
30096a5ae4
|
@ -46,6 +46,11 @@ using namespace x86Emitter;
|
|||
|
||||
alignas(16) x86capabilities x86caps;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// We disable optimizations for this function, because we need x86capabilities for AVX
|
||||
// detection, but if we keep opts on, it'll use AVX instructions for inlining memzero.
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
x86capabilities::x86capabilities()
|
||||
: isIdentified(false)
|
||||
, VendorID(x86Vendor_Unknown)
|
||||
|
@ -65,6 +70,9 @@ x86capabilities::x86capabilities()
|
|||
memzero(VendorName);
|
||||
memzero(FamilyName);
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
// Warning! We've had problems with the MXCSR detection code causing stack corruption in
|
||||
// MSVC PGO builds. The problem was fixed when I moved the MXCSR code to this function, and
|
||||
|
|
|
@ -19,6 +19,7 @@ target_sources(pcsx2-qt PRIVATE
|
|||
AutoUpdaterDialog.ui
|
||||
DisplayWidget.cpp
|
||||
DisplayWidget.h
|
||||
EarlyHardwareCheck.cpp
|
||||
EmuThread.cpp
|
||||
EmuThread.h
|
||||
Main.cpp
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
|
||||
#include "pcsx2/VMManager.h"
|
||||
|
||||
#include "common/RedtapeWindows.h"
|
||||
|
||||
// The problem with AVX2 builds on Windows, is that MSVC generates AVX instructions for zeroing memory,
|
||||
// which is pretty common in our global object constructors. So, we have to use a special object which
|
||||
// gets initialized before all other global objects, that does the hardware check, and terminates the
|
||||
// process before main() or any of the other objects are constructed (which would subsequently crash).
|
||||
struct EarlyHardwareCheckObject
|
||||
{
|
||||
#pragma optimize("", off)
|
||||
EarlyHardwareCheckObject()
|
||||
{
|
||||
const char* error;
|
||||
if (VMManager::PerformEarlyHardwareChecks(&error))
|
||||
return;
|
||||
|
||||
// we can't use StringUtil::UTF8StringToWideString because *that* constructor uses AVX..
|
||||
const int error_len = static_cast<int>(std::strlen(error));
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, error, error_len, nullptr, 0);
|
||||
if (wlen > 0)
|
||||
{
|
||||
wchar_t* werror = static_cast<wchar_t*>(HeapAlloc(GetProcessHeap(), 0, sizeof(wchar_t) * (error_len + 1)));
|
||||
if (werror && (wlen = MultiByteToWideChar(CP_UTF8, 0, error, error_len, werror, wlen)) > 0)
|
||||
{
|
||||
werror[wlen] = 0;
|
||||
MessageBoxW(NULL, werror, L"Hardware Check Failed", MB_ICONERROR);
|
||||
HeapFree(GetProcessHeap(), 0, werror);
|
||||
}
|
||||
}
|
||||
|
||||
TerminateProcess(GetCurrentProcess(), 0xFFFFFFFF);
|
||||
}
|
||||
#pragma optimize("", on)
|
||||
};
|
||||
#pragma warning(disable : 4075) // warning C4075: initializers put in unrecognized initialization area
|
||||
#pragma init_seg(".CRT$XCT")
|
||||
EarlyHardwareCheckObject s_hardware_checker;
|
||||
|
||||
#endif
|
|
@ -16,6 +16,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <cstdlib>
|
||||
#include <csignal>
|
||||
|
||||
|
@ -182,6 +183,23 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
// See note at the end of the file as to why we don't do this on Windows.
|
||||
static bool PerformEarlyHardwareChecks()
|
||||
{
|
||||
// NOTE: No point translating this message, because the configuration isn't loaded yet, so we
|
||||
// won't know which language to use, and loading the configuration uses float instructions.
|
||||
const char* error;
|
||||
if (VMManager::PerformEarlyHardwareChecks(&error))
|
||||
return true;
|
||||
|
||||
QMessageBox::critical(nullptr, QStringLiteral("Hardware Check Failed"), QString::fromUtf8(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CrashHandler::Install();
|
||||
|
@ -191,6 +209,12 @@ int main(int argc, char* argv[])
|
|||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!PerformEarlyHardwareChecks())
|
||||
return EXIT_FAILURE;
|
||||
#endif
|
||||
|
||||
std::shared_ptr<VMBootParameters> autoboot;
|
||||
if (!ParseCommandLineOptions(argc, argv, autoboot))
|
||||
return EXIT_FAILURE;
|
||||
|
|
|
@ -134,6 +134,7 @@
|
|||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="EarlyHardwareCheck.cpp" />
|
||||
<ClCompile Include="Tools\InputRecording\NewInputRecordingDlg.cpp" />
|
||||
<ClCompile Include="Settings\BIOSSettingsWidget.cpp" />
|
||||
<ClCompile Include="Settings\ControllerBindingWidgets.cpp" />
|
||||
|
|
|
@ -204,6 +204,7 @@
|
|||
<ClCompile Include="Tools\InputRecording\NewInputRecordingDlg.cpp">
|
||||
<Filter>Tools\Input Recording</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EarlyHardwareCheck.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
|
||||
|
|
|
@ -128,6 +128,38 @@ static s32 s_current_save_slot = 1;
|
|||
static u32 s_frame_advance_count = 0;
|
||||
static u32 s_mxcsr_saved;
|
||||
|
||||
bool VMManager::PerformEarlyHardwareChecks(const char** error)
|
||||
{
|
||||
#define COMMON_DOWNLOAD_MESSAGE \
|
||||
"PCSX2 builds can be downloaded from https://pcsx2.net/downloads/"
|
||||
|
||||
#if defined(_M_X86)
|
||||
// On Windows, this gets called as a global object constructor, before any of our objects are constructed.
|
||||
// So, we have to put it on the stack instead.
|
||||
x86capabilities temp_x86_caps;
|
||||
temp_x86_caps.Identify();
|
||||
|
||||
if (!temp_x86_caps.hasStreamingSIMD4Extensions)
|
||||
{
|
||||
*error = "PCSX2 requires the Streaming SIMD 4 Extensions instruction set, which your CPU does not support.\n\n"
|
||||
"SSE4 is now a minimum requirement for PCSX2. You should either upgrade your CPU, or use an older build such as 1.6.0.\n\n" COMMON_DOWNLOAD_MESSAGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if _M_SSE >= 0x0501
|
||||
if (!temp_x86_caps.hasAVX || !temp_x86_caps.hasAVX2)
|
||||
{
|
||||
*error = "This build of PCSX2 requires the Advanced Vector Extensions 2 instruction set, which your CPU does not support.\n\n"
|
||||
"You should download and run the SSE4 build of PCSX2 instead, or upgrade to a CPU that supports AVX2 to use this build.\n\n" COMMON_DOWNLOAD_MESSAGE;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef COMMON_DOWNLOAD_MESSAGE
|
||||
return true;
|
||||
}
|
||||
|
||||
VMState VMManager::GetState()
|
||||
{
|
||||
return s_state.load();
|
||||
|
|
|
@ -52,6 +52,9 @@ struct VMBootParameters
|
|||
|
||||
namespace VMManager
|
||||
{
|
||||
/// Makes sure that AVX2 is available if we were compiled with it.
|
||||
bool PerformEarlyHardwareChecks(const char** error);
|
||||
|
||||
/// Returns the current state of the VM.
|
||||
VMState GetState();
|
||||
|
||||
|
|
Loading…
Reference in New Issue