Error handling cleanup, with some Claude help

This commit is contained in:
Henrik Rydgård committed 2026-08-03 23:53:48 +02:00
1 parent 6272eca2e7
commit ced24079cb
3 files changed
+102 -52

No files matched your search

+87 -43
View File
@@ -8,6 +8,7 @@
#include "Common/System/NativeApp.h" #include "Common/System/NativeApp.h"
#include "Common/System/System.h" #include "Common/System/System.h"
#include "Common/System/Display.h" #include "Common/System/Display.h"
#include "Common/StringUtils.h"
#include "Core/Config.h" #include "Core/Config.h"
#include "Core/ConfigValues.h" #include "Core/ConfigValues.h"
#include "Core/System.h" #include "Core/System.h"
@@ -32,7 +33,7 @@ static bool g_XDisplayOpen = false;
static EGLNativeWindowType g_Window = (EGLNativeWindowType)nullptr; static EGLNativeWindowType g_Window = (EGLNativeWindowType)nullptr;
static bool useEGLSwap = false; static bool useEGLSwap = false;
int CheckEGLErrors(const char *file, int line) { int CheckEGLErrors(const char *file, int line, std::string *errorMessage) {
EGLenum error; EGLenum error;
const char *errortext = "unknown"; const char *errortext = "unknown";
error = eglGetError(); error = eglGetError();
@@ -54,27 +55,25 @@ int CheckEGLErrors(const char *file, int line) {
case EGL_BAD_NATIVE_WINDOW: errortext = "EGL_BAD_NATIVE_WINDOW"; break; case EGL_BAD_NATIVE_WINDOW: errortext = "EGL_BAD_NATIVE_WINDOW"; break;
default: errortext = "unknown"; break; default: errortext = "unknown"; break;
} }
fprintf( stderr, "ERROR: EGL Error %s detected in file %s at line %d (0x%X)\n", errortext, file, line, error ); if (errorMessage) {
*errorMessage += StringFromFormat("EGL Error %s detected in file %s at line %d (0x%X)\n", errortext, file, line, error);
}
return 1; return 1;
} }
#define EGL_ERROR(str, check) { \ static bool EGL_OpenInit(std::string *errorMessage) {
if (check) CheckEGLErrors( __FILE__, __LINE__ ); \
fprintf(stderr, "EGL ERROR: " str "\n"); \
return 1; \
}
static bool EGL_OpenInit() {
// NOTE: Not using the EGL_ERROR macro here since it always does "return 1",
// which means "success" for this bool-returning function.
if ((g_eglDisplay = eglGetDisplay(g_Display)) == EGL_NO_DISPLAY) { if ((g_eglDisplay = eglGetDisplay(g_Display)) == EGL_NO_DISPLAY) {
CheckEGLErrors(__FILE__, __LINE__); CheckEGLErrors(__FILE__, __LINE__, errorMessage);
fprintf(stderr, "EGL ERROR: Unable to create EGL display.\n"); if (errorMessage) {
*errorMessage += "Unable to create EGL display.\n";
}
return false; return false;
} }
if (eglInitialize(g_eglDisplay, NULL, NULL) != EGL_TRUE) { if (eglInitialize(g_eglDisplay, NULL, NULL) != EGL_TRUE) {
CheckEGLErrors(__FILE__, __LINE__); CheckEGLErrors(__FILE__, __LINE__, errorMessage);
fprintf(stderr, "EGL ERROR: Unable to initialize EGL display.\n"); if (errorMessage) {
*errorMessage += "Unable to initialize EGL display.\n";
}
eglTerminate(g_eglDisplay); eglTerminate(g_eglDisplay);
g_eglDisplay = EGL_NO_DISPLAY; g_eglDisplay = EGL_NO_DISPLAY;
return false; return false;
@@ -83,15 +82,19 @@ static bool EGL_OpenInit() {
return true; return true;
} }
static int8_t EGL_Open(SDL_Window *window) { static int8_t EGL_Open(SDL_Window *window, std::string *errorMessage) {
#if defined(USING_FBDEV) #if defined(USING_FBDEV)
g_Display = (EGLNativeDisplayType)nullptr; g_Display = (EGLNativeDisplayType)nullptr;
g_Window = (EGLNativeWindowType)nullptr; g_Window = (EGLNativeWindowType)nullptr;
#elif defined(__APPLE__) #elif defined(__APPLE__)
g_Display = (EGLNativeDisplayType)XOpenDisplay(nullptr); g_Display = (EGLNativeDisplayType)XOpenDisplay(nullptr);
g_XDisplayOpen = g_Display != nullptr; g_XDisplayOpen = g_Display != nullptr;
if (!g_XDisplayOpen) if (!g_XDisplayOpen) {
EGL_ERROR("Unable to get display!", false); if (errorMessage) {
*errorMessage += "Unable to get display!\n";
}
return 1;
}
g_Window = (EGLNativeWindowType)nullptr; g_Window = (EGLNativeWindowType)nullptr;
#else #else
// Get the SDL window native handle // Get the SDL window native handle
@@ -107,26 +110,36 @@ static int8_t EGL_Open(SDL_Window *window) {
g_Display = (EGLNativeDisplayType)waylandDisplay; g_Display = (EGLNativeDisplayType)waylandDisplay;
g_Window = (EGLNativeWindowType)waylandEGLWindow; g_Window = (EGLNativeWindowType)waylandEGLWindow;
} else { } else {
fprintf(stderr, "ERROR: Unable to retrieve native window properties\n"); if (errorMessage) {
*errorMessage += "Unable to retrieve native window properties, falling back to X11.\n";
}
g_Display = (EGLNativeDisplayType)XOpenDisplay(nullptr); g_Display = (EGLNativeDisplayType)XOpenDisplay(nullptr);
g_XDisplayOpen = g_Display != nullptr; g_XDisplayOpen = g_Display != nullptr;
if (!g_XDisplayOpen) if (!g_XDisplayOpen) {
EGL_ERROR("Unable to get display!", false); if (errorMessage) {
*errorMessage += "Unable to get display!\n";
}
return 1;
}
g_Window = (EGLNativeWindowType)nullptr; g_Window = (EGLNativeWindowType)nullptr;
} }
} }
if (!EGL_OpenInit()) { if (!EGL_OpenInit(errorMessage)) {
g_Display = (EGLNativeDisplayType)XOpenDisplay(nullptr); g_Display = (EGLNativeDisplayType)XOpenDisplay(nullptr);
g_XDisplayOpen = g_Display != nullptr; g_XDisplayOpen = g_Display != nullptr;
if (!g_XDisplayOpen) if (!g_XDisplayOpen) {
EGL_ERROR("Unable to get display!", false); if (errorMessage) {
*errorMessage += "Unable to get display!\n";
}
return 1;
}
g_Window = (EGLNativeWindowType)nullptr; g_Window = (EGLNativeWindowType)nullptr;
} }
#endif #endif
if (g_eglDisplay == EGL_NO_DISPLAY) if (g_eglDisplay == EGL_NO_DISPLAY)
EGL_OpenInit(); EGL_OpenInit(errorMessage);
return g_eglDisplay == EGL_NO_DISPLAY ? 1 : 0; return g_eglDisplay == EGL_NO_DISPLAY ? 1 : 0;
} }
@@ -134,18 +147,26 @@ static int8_t EGL_Open(SDL_Window *window) {
#define EGL_OPENGL_ES3_BIT_KHR (1 << 6) #define EGL_OPENGL_ES3_BIT_KHR (1 << 6)
#endif #endif
EGLConfig EGL_FindConfig(int *contextVersion) { EGLConfig EGL_FindConfig(int *contextVersion, std::string *errorMessage) {
std::vector<EGLConfig> configs; std::vector<EGLConfig> configs;
EGLint numConfigs = 0; EGLint numConfigs = 0;
EGLBoolean result = eglGetConfigs(g_eglDisplay, nullptr, 0, &numConfigs); EGLBoolean result = eglGetConfigs(g_eglDisplay, nullptr, 0, &numConfigs);
if (result != EGL_TRUE || numConfigs == 0) { if (result != EGL_TRUE || numConfigs == 0) {
CheckEGLErrors(__FILE__, __LINE__, errorMessage);
if (errorMessage) {
*errorMessage += "eglGetConfigs failed to return any configs.\n";
}
return nullptr; return nullptr;
} }
configs.resize(numConfigs); configs.resize(numConfigs);
result = eglGetConfigs(g_eglDisplay, &configs[0], numConfigs, &numConfigs); result = eglGetConfigs(g_eglDisplay, &configs[0], numConfigs, &numConfigs);
if (result != EGL_TRUE || numConfigs == 0) { if (result != EGL_TRUE || numConfigs == 0) {
CheckEGLErrors(__FILE__, __LINE__, errorMessage);
if (errorMessage) {
*errorMessage += "eglGetConfigs failed to return any configs.\n";
}
return nullptr; return nullptr;
} }
@@ -228,11 +249,13 @@ EGLConfig EGL_FindConfig(int *contextVersion) {
return best; return best;
} }
int8_t EGL_Init(SDL_Window *window) { int8_t EGL_Init(SDL_Window *window, std::string *errorMessage) {
int contextVersion = 0; int contextVersion = 0;
EGLConfig eglConfig = EGL_FindConfig(&contextVersion); EGLConfig eglConfig = EGL_FindConfig(&contextVersion, errorMessage);
if (!eglConfig) { if (!eglConfig) {
EGL_ERROR("Unable to find a usable EGL config.", true); if (errorMessage) {
*errorMessage += "Unable to find a usable EGL config.\n";
}
return 1; return 1;
} }
@@ -246,18 +269,27 @@ int8_t EGL_Init(SDL_Window *window) {
g_eglContext = eglCreateContext(g_eglDisplay, eglConfig, nullptr, contextAttributes); g_eglContext = eglCreateContext(g_eglDisplay, eglConfig, nullptr, contextAttributes);
if (g_eglContext == EGL_NO_CONTEXT) { if (g_eglContext == EGL_NO_CONTEXT) {
EGL_ERROR("Unable to create GLES context!", true); CheckEGLErrors(__FILE__, __LINE__, errorMessage);
if (errorMessage) {
*errorMessage += "Unable to create GLES context!\n";
}
return 1; return 1;
} }
g_eglSurface = eglCreateWindowSurface(g_eglDisplay, eglConfig, g_Window, nullptr); g_eglSurface = eglCreateWindowSurface(g_eglDisplay, eglConfig, g_Window, nullptr);
if (g_eglSurface == EGL_NO_SURFACE) { if (g_eglSurface == EGL_NO_SURFACE) {
EGL_ERROR("Unable to create EGL surface!", true); CheckEGLErrors(__FILE__, __LINE__, errorMessage);
if (errorMessage) {
*errorMessage += "Unable to create EGL surface!\n";
}
return 1; return 1;
} }
if (eglMakeCurrent(g_eglDisplay, g_eglSurface, g_eglSurface, g_eglContext) != EGL_TRUE) { if (eglMakeCurrent(g_eglDisplay, g_eglSurface, g_eglSurface, g_eglContext) != EGL_TRUE) {
EGL_ERROR("Unable to make GLES context current.", true); CheckEGLErrors(__FILE__, __LINE__, errorMessage);
if (errorMessage) {
*errorMessage += "Unable to make GLES context current.\n";
}
return 1; return 1;
} }
@@ -290,7 +322,7 @@ void EGL_Close() {
#endif // USING_EGL #endif // USING_EGL
SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, int forceGLVersion, SDL_GLContext *glContextOut) { SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, int forceGLVersion, SDL_GLContext *glContextOut, std::string *errorMessage) {
// We start hidden because we have to try several windows. // We start hidden because we have to try several windows.
// On Mac, full screen animates so each attempt is slow. // On Mac, full screen animates so each attempt is slow.
mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN; mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN;
@@ -333,7 +365,9 @@ SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, in
window = SDL_CreateWindow("PPSSPP", w, h, (SDL_WindowFlags)mode); window = SDL_CreateWindow("PPSSPP", w, h, (SDL_WindowFlags)mode);
if (!window) { if (!window) {
// Definitely don't shutdown here: we'll keep trying more GL versions. // Definitely don't shutdown here: we'll keep trying more GL versions.
fprintf(stderr, "SDL_CreateWindow failed for GL %d.%d: %s\n", ver.major, ver.minor, SDL_GetError()); if (errorMessage) {
*errorMessage += StringFromFormat("SDL_CreateWindow failed for GL %d.%d: %s\n", ver.major, ver.minor, SDL_GetError());
}
// Skip the DestroyWindow. // Skip the DestroyWindow.
continue; continue;
} }
@@ -360,14 +394,18 @@ SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, in
window = SDL_CreateWindow("PPSSPP", w, h, (SDL_WindowFlags)mode); window = SDL_CreateWindow("PPSSPP", w, h, (SDL_WindowFlags)mode);
if (window == nullptr) { if (window == nullptr) {
fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); if (errorMessage) {
*errorMessage += StringFromFormat("SDL_CreateWindow failed: %s\n", SDL_GetError());
}
return nullptr; return nullptr;
} }
glContext = SDL_GL_CreateContext(window); glContext = SDL_GL_CreateContext(window);
if (!glContext) { if (!glContext) {
// OK, now we really have tried everything. We give up. // OK, now we really have tried everything. We give up.
fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError()); if (errorMessage) {
*errorMessage += StringFromFormat("SDL_GL_CreateContext failed: %s\n", SDL_GetError());
}
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
return nullptr; return nullptr;
} }
@@ -379,10 +417,12 @@ SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, in
} }
#ifdef USING_EGL #ifdef USING_EGL
if (EGL_Open(window) != 0) { // EGL is optional here - if it fails, we just keep using the regular SDL/GLX swap set up above.
fprintf(stderr, "EGL_Open() failed\n"); std::string eglError;
} else if (EGL_Init(window) != 0) { if (EGL_Open(window, &eglError) != 0) {
fprintf(stderr, "EGL_Init() failed\n"); WARN_LOG(Log::G3D, "EGL_Open() failed: %s", eglError.c_str());
} else if (EGL_Init(window, &eglError) != 0) {
WARN_LOG(Log::G3D, "EGL_Init() failed: %s", eglError.c_str());
} else { } else {
useEGLSwap = true; useEGLSwap = true;
} }
@@ -397,7 +437,9 @@ SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, in
GLenum glew_err = glewInit(); GLenum glew_err = glewInit();
// glx is not required, igore. // glx is not required, igore.
if (glew_err != GLEW_OK && glew_err != GLEW_ERROR_NO_GLX_DISPLAY) { if (glew_err != GLEW_OK && glew_err != GLEW_ERROR_NO_GLX_DISPLAY) {
fprintf(stderr, "Failed to initialize glew!\n"); if (errorMessage) {
*errorMessage += StringFromFormat("Failed to initialize glew: %s\n", (const char *)glewGetErrorString(glew_err));
}
SDL_GL_DestroyContext(glContext); SDL_GL_DestroyContext(glContext);
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
return nullptr; return nullptr;
@@ -407,9 +449,11 @@ SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, in
glGetError(); glGetError();
if (GLEW_VERSION_2_0) { if (GLEW_VERSION_2_0) {
fprintf(stderr, "OpenGL 2.0 or higher.\n"); INFO_LOG(Log::G3D, "OpenGL 2.0 or higher.");
} else { } else {
fprintf(stderr, "Sorry, this program requires OpenGL 2.0.\n"); if (errorMessage) {
*errorMessage += "Sorry, this program requires OpenGL 2.0.\n";
}
SDL_GL_DestroyContext(glContext); SDL_GL_DestroyContext(glContext);
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
return nullptr; return nullptr;
+1 -1
View File
@@ -46,4 +46,4 @@ private:
GLRenderManager *renderManager_ = nullptr; GLRenderManager *renderManager_ = nullptr;
}; };
SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, int forceGLVersion, SDL_GLContext *glContextOut); SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, int forceGLVersion, SDL_GLContext *glContextOut, std::string *errorMessage);
+14 -8
View File
@@ -1748,7 +1748,7 @@ void UpdateSDLCursor() {
#endif #endif
} }
bool DetermineVulkanWindowSystem(SDL_Window *window, WindowSystem *windowSystem, void **data1, void **data2) { bool DetermineVulkanWindowSystem(SDL_Window *window, WindowSystem *windowSystem, void **data1, void **data2, std::string *errorMessage) {
_dbg_assert_(window); _dbg_assert_(window);
SDL_PropertiesID windowProps = SDL_GetWindowProperties(window); SDL_PropertiesID windowProps = SDL_GetWindowProperties(window);
void *x11Display = SDL_GetPointerProperty(windowProps, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, nullptr); void *x11Display = SDL_GetPointerProperty(windowProps, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, nullptr);
@@ -1794,7 +1794,9 @@ bool DetermineVulkanWindowSystem(SDL_Window *window, WindowSystem *windowSystem,
} }
#endif #endif
#endif // VK_USE_PLATFORM_METAL_EXT #endif // VK_USE_PLATFORM_METAL_EXT
fprintf(stderr, "Unable to determine Vulkan window system from SDL3 window properties\n"); if (errorMessage) {
*errorMessage = "Unable to determine Vulkan window system from SDL3 window properties";
}
return false; return false;
} }
@@ -2067,25 +2069,29 @@ int main(int argc, char *argv[]) {
GraphicsContext *ctx = nullptr; GraphicsContext *ctx = nullptr;
if (backend == GPUBackend::OPENGL) { if (backend == GPUBackend::OPENGL) {
SDL_GLContext glContext = nullptr; SDL_GLContext glContext = nullptr;
window = CreateSDLGLWindowAndContext(x, y, w, h, mode, cmdLineOptions.force_gl_version, &glContext); window = CreateSDLGLWindowAndContext(x, y, w, h, mode, cmdLineOptions.force_gl_version, &glContext, errorMessage);
data1 = (void *)window; data1 = (void *)window;
data2 = (void *)glContext; data2 = (void *)glContext;
ctx = new SDLGLGraphicsContext(); ctx = new SDLGLGraphicsContext();
} else { } else {
mode |= SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN; // Use a local copy of mode: this flag combination is Vulkan-specific, and if we fall back to
window = SDL_CreateWindow("Initializing graphics...", w, h, (SDL_WindowFlags)mode); // OpenGL below, we don't want SDL_WINDOW_VULKAN to stick around and get OR'd in there too.
Uint32 vulkanMode = mode | SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN;
window = SDL_CreateWindow("Initializing graphics...", w, h, (SDL_WindowFlags)vulkanMode);
if (!window) { if (!window) {
fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError()); if (errorMessage) {
exit(1); *errorMessage = StringFromFormat("Error creating SDL window: %s", SDL_GetError());
}
return false;
} }
if (x != SDL_WINDOWPOS_UNDEFINED && y != SDL_WINDOWPOS_UNDEFINED) { if (x != SDL_WINDOWPOS_UNDEFINED && y != SDL_WINDOWPOS_UNDEFINED) {
SDL_SetWindowPosition(window, x, y); SDL_SetWindowPosition(window, x, y);
} }
// Overwrite the surface init params with what we need for Vulkan.. // Overwrite the surface init params with what we need for Vulkan..
if (!DetermineVulkanWindowSystem(window, &windowSystem, &data1, &data2)) { if (!DetermineVulkanWindowSystem(window, &windowSystem, &data1, &data2, errorMessage)) {
return false; return false;
} }
// NOTE : This should match the lines below in the Vulkan case. // NOTE : This should match the lines below in the Vulkan case.