Skip to content

Commit

Permalink
Merge pull request #11346 from unknownbrackets/startup-fail
Browse files Browse the repository at this point in the history
Core: Track graphics startup failures and cycle
  • Loading branch information
hrydgard authored Sep 4, 2018
2 parents f87dcef + e246a94 commit 562c5f6
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 4 deletions.
42 changes: 42 additions & 0 deletions Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <cstdlib>
#include <ctime>
#include <functional>
#include <set>

#include "base/display.h"
#include "base/NativeApp.h"
Expand Down Expand Up @@ -545,6 +546,46 @@ static int DefaultGPUBackend() {
return (int)GPUBackend::OPENGL;
}

int Config::NextValidBackend() {
std::vector<std::string> split;
std::set<int> failed;
SplitString(sFailedGPUBackends, ',', split);
for (const auto &str : split) {
if (!str.empty() && str != "ALL") {
failed.insert(atoi(str.c_str()));
}
}

if (failed.count(iGPUBackend)) {
#if (PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(ANDROID)) && !PPSSPP_PLATFORM(UWP)
if (VulkanMayBeAvailable() && !failed.count((int)GPUBackend::VULKAN)) {
return (int)GPUBackend::VULKAN;
}
#endif
#if PPSSPP_PLATFORM(WINDOWS)
if (DoesVersionMatchWindows(6, 1, 0, 0, true) && !failed.count((int)GPUBackend::DIRECT3D11)) {
return (int)GPUBackend::DIRECT3D11;
}
#endif
#if !PPSSPP_PLATFORM(UWP)
if (!failed.count((int)GPUBackend::OPENGL)) {
return (int)GPUBackend::OPENGL;
}
#endif
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
if (!failed.count((int)GPUBackend::DIRECT3D9)) {
return (int)GPUBackend::DIRECT3D9;
}
#endif

// They've all failed. Let them try the default.
sFailedGPUBackends += ",ALL";
return DefaultGPUBackend();
}

return iGPUBackend;
}

static bool DefaultVertexCache() {
return DefaultGPUBackend() == (int)GPUBackend::OPENGL;
}
Expand All @@ -556,6 +597,7 @@ static ConfigSetting graphicsSettings[] = {
ConfigSetting("CardboardYShift", &g_Config.iCardboardXShift, 0, true, true),
ConfigSetting("ShowFPSCounter", &g_Config.iShowFPSCounter, 0, true, true),
ReportedConfigSetting("GraphicsBackend", &g_Config.iGPUBackend, &DefaultGPUBackend),
ConfigSetting("FailedGraphicsBackends", &g_Config.sFailedGPUBackends, ""),
ConfigSetting("VulkanDevice", &g_Config.sVulkanDevice, "", true, false),
#ifdef _WIN32
ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", true, false),
Expand Down
2 changes: 2 additions & 0 deletions Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ struct Config {

// GFX
int iGPUBackend;
std::string sFailedGPUBackends;
// We have separate device parameters for each backend so it doesn't get erased if you switch backends.
// If not set, will use the "best" device.
std::string sVulkanDevice;
Expand Down Expand Up @@ -441,6 +442,7 @@ struct Config {
void GetReportingInfo(UrlEncoder &data);

bool IsPortrait() const;
int NextValidBackend();

protected:
void LoadStandardControllerIni();
Expand Down
59 changes: 55 additions & 4 deletions UI/NativeApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,10 @@
// in NativeShutdown.

#include <locale.h>
// Linux doesn't like using std::find with std::vector<int> without this :/
#if !defined(MOBILE_DEVICE)
#include <algorithm>
#endif
#include <memory>
#include <thread>
#include <mutex>
#include <thread>

#if defined(_WIN32)
#include "Windows/DSoundStream.h"
Expand Down Expand Up @@ -348,6 +345,53 @@ void CreateDirectoriesAndroid() {
File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SYSTEM) + ".nomedia");
}

static void CheckFailedGPUBackends() {
std::string cache = GetSysDirectory(DIRECTORY_APP_CACHE) + "/FailedGraphicsBackends.txt";

if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) {
std::string data;
if (readFileToString(true, cache.c_str(), data))
g_Config.sFailedGPUBackends = data;
}

// Use this if you want to debug a graphics crash...
if (g_Config.sFailedGPUBackends == "IGNORE")
return;

// Okay, let's not try a backend in the failed list.
g_Config.iGPUBackend = g_Config.NextValidBackend();
// And then let's - for now - add the current to the failed list.
if (g_Config.sFailedGPUBackends.empty()) {
g_Config.sFailedGPUBackends = StringFromFormat("%d", g_Config.iGPUBackend);
} else if (g_Config.sFailedGPUBackends.find("ALL") == std::string::npos) {
g_Config.sFailedGPUBackends += StringFromFormat(",%d", g_Config.iGPUBackend);
}

if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) {
// Let's try to create, in case it doesn't exist.
if (!File::Exists(GetSysDirectory(DIRECTORY_APP_CACHE)))
File::CreateDir(GetSysDirectory(DIRECTORY_APP_CACHE));
writeStringToFile(true, g_Config.sFailedGPUBackends, cache.c_str());
} else {
// Just save immediately, since we have storage.
g_Config.Save();
}
}

static void ClearFailedGPUBackends() {
if (g_Config.sFailedGPUBackends == "IGNORE")
return;

// We've successfully started graphics without crashing, hurray.
// In case they update drivers and have totally different problems much later, clear the failed list.
g_Config.sFailedGPUBackends.clear();
if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) {
File::Delete(GetSysDirectory(DIRECTORY_APP_CACHE) + "/FailedGraphicsBackends.txt");
} else {
g_Config.Save();
}
}

void NativeInit(int argc, const char *argv[], const char *savegame_dir, const char *external_dir, const char *cache_dir) {
net::Init(); // This needs to happen before we load the config. So on Windows we also run it in Main. It's fine to call multiple times.

Expand Down Expand Up @@ -631,6 +675,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch

// We do this here, instead of in NativeInitGraphics, because the display may be reset.
// When it's reset we don't want to forget all our managed things.
CheckFailedGPUBackends();
SetGPUBackend((GPUBackend) g_Config.iGPUBackend);

// Must be done restarting by now.
Expand Down Expand Up @@ -952,6 +997,12 @@ void NativeRender(GraphicsContext *graphicsContext) {

ui_draw2d.PopDrawMatrix();
ui_draw2d_front.PopDrawMatrix();

static int renderCounter = 0;
if (renderCounter < 10 && ++renderCounter == 10) {
// We're rendering fine, clear out failure info.
ClearFailedGPUBackends();
}
}

void HandleGlobalMessage(const std::string &msg, const std::string &value) {
Expand Down
14 changes: 14 additions & 0 deletions Windows/EmuThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@ void MainThreadFunc() {
bool performingRestart = NativeIsRestarting();
NativeInit(static_cast<int>(args.size()), &args[0], "1234", "1234", nullptr);

if (g_Config.sFailedGPUBackends.find("ALL") != std::string::npos) {
Reporting::ReportMessage("Graphics init error: %s", "ALL");

I18NCategory *err = GetI18NCategory("Error");
const char *defaultErrorAll = "Failed initializing any graphics. Try upgrading your graphics drivers.";
const char *genericError = err->T("GenericAllGraphicsError", defaultErrorAll);
std::wstring title = ConvertUTF8ToWString(err->T("GenericGraphicsError", "Graphics Error"));
MessageBox(0, ConvertUTF8ToWString(genericError).c_str(), title.c_str(), MB_OK);

// Let's continue (and probably crash) just so they have a way to keep trying.
}

host->UpdateUI();

std::string error_string;
Expand Down Expand Up @@ -182,6 +194,8 @@ void MainThreadFunc() {
if (yes) {
// Change the config to the alternative and restart.
g_Config.iGPUBackend = (int)nextBackend;
// Clear this to ensure we try their selection.
g_Config.sFailedGPUBackends.clear();
g_Config.Save();

W32Util::ExitAndRestart();
Expand Down
1 change: 1 addition & 0 deletions Windows/GPU/D3D11Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
if (yes) {
// Change the config to D3D and restart.
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D9;
g_Config.sFailedGPUBackends.clear();
g_Config.Save();

W32Util::ExitAndRestart();
Expand Down
1 change: 1 addition & 0 deletions Windows/GPU/WindowsGLContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) {
std::wstring whichD3D9 = ConvertUTF8ToWString(err->T("D3D9or11", d3d9Or11));
bool d3d9 = IDYES == MessageBox(hWnd_, whichD3D9.c_str(), title.c_str(), MB_YESNO);
g_Config.iGPUBackend = d3d9 ? (int)GPUBackend::DIRECT3D9 : (int)GPUBackend::DIRECT3D11;
g_Config.sFailedGPUBackends.clear();
g_Config.Save();

W32Util::ExitAndRestart();
Expand Down

0 comments on commit 562c5f6

Please sign in to comment.