Merge pull request #22020 from hrydgard/sdl-window-rework

SDL GL/Vulkan init rework
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-08-03 18:13:16 +02:00
commit 698fb7e39d
7 files changed
+191 -142

No files matched your search

+42
View File
@@ -0,0 +1,42 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch PPSSPPSDL (WSL)",
"type": "cppdbg",
"request": "launch",
"preLaunchTask": "Build PPSSPP (WSL debug)",
"program": "/home/hrydg/ppsspp/build/PPSSPPSDL",
"osx": {
"program": "${workspaceFolder}/build/PPSSPPSDL.app/Contents/MacOS/PPSSPPSDL"
},
"linux": {
"program": "/home/hrydg/ppsspp/build/PPSSPPSDL"
},
"args": [],
"stopAtEntry": false,
"cwd": "/home/hrydg/ppsspp",
"sourceFileMap": {
"/home/hrydg/ppsspp": "${workspaceFolder}"
},
"environment": [],
"externalConsole": false,
"internalConsoleOptions": "openOnSessionStart",
"logging": {
"programOutput": true
},
"MIMode": "gdb",
"pipeTransport": {
"pipeProgram": "wsl.exe",
"pipeArgs": [
"-d",
"Ubuntu",
"--"
],
"pipeCwd": "C:/",
"quoteArgs": false,
"debuggerPath": "/usr/bin/gdb"
}
}
]
}
+24
View File
@@ -0,0 +1,24 @@
{
"comment": "Copy this to launch.json if you want to, or edit as desired first",
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "",
"osx": {
"program": "${workspaceFolder}/build/PPSSPPSDL.app/Contents/MacOS/PPSSPPSDL"
},
"linux": {
"program": "${workspaceRoot}/build/PPSSPPSDL"
},
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb"
}
]
}
+2
View File
@@ -3,6 +3,7 @@
#include "Common/System/Display.h"
#include "Common/Math/math_util.h"
#include "Common/GPU/MiscTypes.h"
#include "Common/Log.h"
DisplayProperties g_display;
@@ -70,6 +71,7 @@ DisplayProperties::DisplayProperties() {
}
bool DisplayProperties::Recalculate(int new_pixel_xres, int new_pixel_yres, float new_scale_x, float new_scale_y, float customScale) {
INFO_LOG(Log::G3D, "recalculate: %dx%d, %f, %f, %f", new_pixel_xres, new_pixel_yres, new_scale_x, new_scale_y, customScale);
bool px_changed = false;
if (new_pixel_xres > 0 && pixel_xres != new_pixel_xres) {
pixel_xres = new_pixel_xres;
+1 -1
View File
@@ -255,7 +255,7 @@ void ScreenManager::deviceRestored(Draw::DrawContext *draw) {
}
void ScreenManager::resized() {
INFO_LOG(Log::UI, "ScreenManager::resized(dp: %dx%d)", g_display.dp_xres, g_display.dp_yres);
INFO_LOG(Log::UI, "ScreenManager::resized(g_display.dp_xres/dp_yres: %dx%d)", g_display.dp_xres, g_display.dp_yres);
// Have to notify the whole stack, otherwise there will be problems when going back
// to non-top screens.
for (auto &layer : stack_) {
+33 -45
View File
@@ -286,10 +286,15 @@ void EGL_Close() {
#endif // USING_EGL
// TODO: All this stuff doesn't really belong here.
bool SDLGLGraphicsContext::InitSurface(WindowSystem winsys, void *data1, void *data2, std::string *error_message) {
SDL_Window *window = *(SDL_Window **)data1;
int mode = (int)(uintptr_t)data2;
SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, int forceGLVersion, SDL_GLContext *glContextOut) {
// We start hidden because we have to try several windows.
// On Mac, full screen animates so each attempt is slow.
mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN;
SDL_Window *window = SDL_CreateWindow("Initializing graphics...", w, h, (SDL_WindowFlags)mode);
if (!window) {
fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError());
exit(1);
}
struct GLVersionPair {
int major;
int minor;
@@ -303,24 +308,14 @@ bool SDLGLGraphicsContext::InitSurface(WindowSystem winsys, void *data1, void *d
#endif
};
// We start hidden because we have to try several windows.
// On Mac, full screen animates so each attempt is slow.
mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN;
int x;
int y;
int w;
int h;
SDL_GetWindowPosition(window, &x, &y);
SDL_GetWindowSize(window, &w, &h);
glContext_ = nullptr;
SDL_GLContext glContext{};
for (size_t i = 0; i < ARRAY_SIZE(attemptVersions); ++i) {
const auto &ver = attemptVersions[i];
// If we force a specific OpenGL version, skip the ones
// that do not match, which may be all of them - e.g.
// requesting nonsensical "--graphics=opengl0" reliably
// skips straight to fallback code below.
if (force_gl_version_ >= 0 && 10 * ver.major + ver.minor != force_gl_version_)
if (forceGLVersion >= 0 && 10 * ver.major + ver.minor != forceGLVersion)
continue;
// Make sure to request a somewhat modern GL context at least - the
// latest supported by MacOS X (really, really sad...)
@@ -343,12 +338,8 @@ bool SDLGLGraphicsContext::InitSurface(WindowSystem winsys, void *data1, void *d
continue;
}
if (x != SDL_WINDOWPOS_UNDEFINED && y != SDL_WINDOWPOS_UNDEFINED) {
SDL_SetWindowPosition(window, x, y);
}
glContext_ = SDL_GL_CreateContext(window);
if (glContext_ != nullptr) {
glContext = SDL_GL_CreateContext(window);
if (glContext != nullptr) {
// Victory, got one.
break;
}
@@ -358,7 +349,7 @@ bool SDLGLGraphicsContext::InitSurface(WindowSystem winsys, void *data1, void *d
SDL_DestroyWindow(window);
}
if (glContext_ == nullptr) {
if (glContext == nullptr) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
@@ -366,28 +357,22 @@ bool SDLGLGraphicsContext::InitSurface(WindowSystem winsys, void *data1, void *d
window = SDL_CreateWindow("PPSSPP", w, h, (SDL_WindowFlags)mode);
if (window == nullptr) {
NativeShutdown();
fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError());
SDL_Quit();
return false;
return nullptr;
}
if (x != SDL_WINDOWPOS_UNDEFINED && y != SDL_WINDOWPOS_UNDEFINED) {
SDL_SetWindowPosition(window, x, y);
}
glContext_ = SDL_GL_CreateContext(window);
if (glContext_ == nullptr) {
glContext = SDL_GL_CreateContext(window);
if (glContext == nullptr) {
// OK, now we really have tried everything.
NativeShutdown();
fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError());
SDL_Quit();
return false;
return nullptr;
}
}
// At this point, we have a window that we can show finally.
SDL_ShowWindow(window);
// For some reason we have to set the position here, can't wait until after the window is shown (??).
if (x != SDL_WINDOWPOS_UNDEFINED && y != SDL_WINDOWPOS_UNDEFINED) {
SDL_SetWindowPosition(window, x, y);
}
#ifdef USING_EGL
if (EGL_Open(window) != 0) {
@@ -409,7 +394,7 @@ bool SDLGLGraphicsContext::InitSurface(WindowSystem winsys, void *data1, void *d
// glx is not required, igore.
if (glew_err != GLEW_OK && glew_err != GLEW_ERROR_NO_GLX_DISPLAY) {
fprintf(stderr, "Failed to initialize glew!\n");
return false;
return nullptr;
}
// Unfortunately, glew will generate an invalid enum error, ignore.
if (gl_extensions.IsCoreContext)
@@ -419,9 +404,17 @@ bool SDLGLGraphicsContext::InitSurface(WindowSystem winsys, void *data1, void *d
fprintf(stderr, "OpenGL 2.0 or higher.\n");
} else {
fprintf(stderr, "Sorry, this program requires OpenGL 2.0.\n");
return false;
return nullptr;
}
#endif
*glContextOut = glContext;
return window;
}
bool SDLGLGraphicsContext::InitSurface(WindowSystem winsys, void *data1, void *data2, std::string *error_message) {
SDL_Window *window = (SDL_Window *)data1;
SDL_GLContext glContext = (SDL_GLContext)data2;
glContext_ = glContext;
// Finally we can do the regular initialization.
CheckGLExtensions();
@@ -441,17 +434,12 @@ bool SDLGLGraphicsContext::InitSurface(WindowSystem winsys, void *data1, void *d
SDL_GL_SwapWindow(window_);
#endif
});
renderManager_->SetSwapIntervalFunction([&](int interval) {
INFO_LOG(Log::G3D, "SDL SwapInterval: %d", interval);
SDL_GL_SetSwapInterval(interval);
});
window_ = window;
// HACK: Ensure that the swap interval is set after context creation (needed for kmsdrm)
SDL_GL_SetSwapInterval(1);
return true;
}
@@ -461,7 +449,7 @@ void SDLGLGraphicsContext::ShutdownSurface() {
renderManager_ = nullptr;
}
bool SDLGLGraphicsContext::InitAPI(void *wnd, std::string *deviceName, std::string *errorMessage) {
bool SDLGLGraphicsContext::InitAPI(void *ctx, std::string *deviceName, std::string *errorMessage) {
return true;
}
+4 -3
View File
@@ -9,13 +9,13 @@
class SDLGLGraphicsContext : public GraphicsContext {
public:
SDLGLGraphicsContext(int force_gl_version) : force_gl_version_(force_gl_version) {}
SDLGLGraphicsContext() {}
bool InitAPI(void *wnd, std::string *deviceName, std::string *errorMessage) override;
void ShutdownAPI() override;
// Returns 0 on success.
// data1 should be a *pointer* to the SDL_Window pointer, data2 is the SDL_WindowFlags.
// data1 should be the SDL_Window pointer, data2 is the SDL_WindowFlags.
bool InitSurface(WindowSystem winsys, void *data1, void *data2, std::string *error_message) override;
void ShutdownSurface() override;
@@ -43,6 +43,7 @@ private:
Draw::DrawContext *draw_ = nullptr;
SDL_Window *window_ = nullptr;
SDL_GLContext glContext_ = nullptr;
int force_gl_version_ = 0;
GLRenderManager *renderManager_ = nullptr;
};
SDL_Window *CreateSDLGLWindowAndContext(int x, int y, int w, int h, int mode, int forceGLVersion, SDL_GLContext *glContextOut);
+85 -93
View File
@@ -96,8 +96,6 @@ static float g_ForcedDPI = 0.0f; // if this is 0.0f, use g_DesktopDPI
static float g_RefreshRate = 60.f;
static int g_sampleRate = 44100;
static bool g_rebootEmuThread = false;
static SDL_AudioSpec g_retFmt;
static int g_audioFramesPerBuffer = 0;
@@ -1334,6 +1332,7 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
#if !defined(MOBILE_DEVICE)
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
{
INFO_LOG(Log::UI, "SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: %d x %d", event.window.data1, event.window.data2);
int new_width = event.window.data1;
int new_height = event.window.data2;
@@ -1342,6 +1341,7 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
Uint64 window_flags = SDL_GetWindowFlags(window);
bool fullscreen = (window_flags & SDL_WINDOW_FULLSCREEN) != 0;
// !!! This is the wrong thread!
// This one calls NativeResized if the size changed.
Native_UpdateScreenScale(new_width, new_height, UIScaleFactorToMultiplier(g_Config.iUIScaleFactor));
@@ -1408,7 +1408,9 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
#endif
case SDL_EVENT_KEY_DOWN:
{
if (event.key.repeat > 0) { break;}
if (event.key.repeat > 0) {
break;
}
int k = event.key.key;
KeyInput key;
key.flags = KeyInputFlags::DOWN;
@@ -1420,15 +1422,7 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
key.deviceId = DEVICE_ID_KEYBOARD;
NativeKey(key);
#ifdef _DEBUG
if (k == SDLK_F7) {
fprintf(stderr, "f7 pressed - rebooting emuthread\n");
g_rebootEmuThread = true;
}
#endif
// Convenience subset of what
// "Enable standard shortcut keys"
// does on Windows.
// Convenience subset of what "Enable standard shortcut keys" does on Windows.
if (g_Config.bSystemControls) {
bool ctrl = bool(event.key.mod & SDL_KMOD_CTRL);
if (ctrl && (k == SDLK_W))
@@ -1539,6 +1533,7 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
switch (event.button.button) {
case SDL_BUTTON_LEFT:
{
INFO_LOG(Log::UI, "SDL_EVENT_MOUSE_BUTTON_DOWN: %f x %f", event.button.x, event.button.y);
// We have to juggle around 3 kinds of "DPI spaces" if a logical DPI is
// provided (through --dpi, it is equal to system DPI if unspecified):
// - SDL gives us motion events in "system DPI" points
@@ -1749,6 +1744,7 @@ void UpdateSDLCursor() {
}
bool DetermineVulkanWindowSystem(SDL_Window *window, WindowSystem *windowSystem, void **data1, void **data2) {
_dbg_assert_(window);
SDL_PropertiesID windowProps = SDL_GetWindowProperties(window);
void *x11Display = SDL_GetPointerProperty(windowProps, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, nullptr);
if (x11Display != nullptr) {
@@ -2035,88 +2031,101 @@ int main(int argc, char *argv[]) {
h = g_Config.iWindowHeight;
}
GraphicsContext *graphicsContext = nullptr;
SDL_Window *window = nullptr;
// Switch away from Vulkan if not available.
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN && !vulkanMayBeAvailable) {
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
int fallbackGPUBackend = -1;
switch ((GPUBackend)g_Config.iGPUBackend) {
case GPUBackend::VULKAN:
if (!vulkanMayBeAvailable) {
fprintf(stderr, "Vulkan is not available, switching to OpenGL.\n");
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
} else {
fallbackGPUBackend = (int)GPUBackend::OPENGL;
}
break;
case GPUBackend::OPENGL:
fallbackGPUBackend = (int)GPUBackend::VULKAN;
break;
default:
fprintf(stderr, "Unknown GPU backend %d, switching to Vulkan.\n", g_Config.iGPUBackend);
g_Config.iGPUBackend = (int)GPUBackend::VULKAN;
fallbackGPUBackend = (int)GPUBackend::OPENGL;
break;
}
window = SDL_CreateWindow("Initializing graphics...", w, h, (SDL_WindowFlags)mode);
SDL_Window *window = nullptr;
auto initializeBackend = [&](GPUBackend backend, GraphicsContext **graphicsContext, std::string *errorMessage) -> bool {
// Surface init params.
WindowSystem windowSystem = WINDOWSYSTEM_NONE;
void *data1 = nullptr;
void *data2 = nullptr;
// Surface init params. These are set up for OpenGL by default.
WindowSystem windowSystem = WINDOWSYSTEM_NONE;
void *data1 = &window;
void *data2 = nullptr;
GraphicsContext *ctx = nullptr;
if (backend == GPUBackend::OPENGL) {
SDL_GLContext glContext = nullptr;
window = CreateSDLGLWindowAndContext(x, y, w, h, mode, cmdLineOptions.force_gl_version, &glContext);
std::string error_message;
if (g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
SDLGLGraphicsContext *glctx = new SDLGLGraphicsContext(cmdLineOptions.force_gl_version);
if (!window) {
fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError());
exit(1);
}
if (x != SDL_WINDOWPOS_UNDEFINED && y != SDL_WINDOWPOS_UNDEFINED) {
SDL_SetWindowPosition(window, x, y);
}
data1 = (void *)window;
data2 = (void *)glContext;
glctx->InitAPI(nullptr, nullptr, &error_message);
if (!glctx->InitSurface(WINDOWSYSTEM_NONE, &window, (void *)(uintptr_t)mode, &error_message)) {
// Let's try the fallback once per process run.
fprintf(stderr, "GL init error '%s' - falling back to Vulkan\n", error_message.c_str());
g_Config.iGPUBackend = (int)GPUBackend::VULKAN;
SetGPUBackend((GPUBackend)g_Config.iGPUBackend);
delete glctx;
ctx = new SDLGLGraphicsContext();
} else {
mode |= SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN;
window = SDL_CreateWindow("Initializing graphics...", w, h, (SDL_WindowFlags)mode);
if (!window) {
fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError());
exit(1);
}
if (x != SDL_WINDOWPOS_UNDEFINED && y != SDL_WINDOWPOS_UNDEFINED) {
SDL_SetWindowPosition(window, x, y);
}
// Overwrite the surface init params with what we need for Vulkan..
if (!DetermineVulkanWindowSystem(window, &windowSystem, &data1, &data2)) {
return 1;
return false;
}
// NOTE : This should match the lines below in the Vulkan case.
VulkanGraphicsContext *vkctx = new VulkanGraphicsContext();
vkctx->InitAPI(nullptr, &g_Config.sVulkanDevice, &error_message);
ctx = new VulkanGraphicsContext();
}
if (!vkctx->InitSurface(windowSystem, data1, data2, &error_message)) {
fprintf(stderr, "Vulkan fallback failed: %s\n", error_message.c_str());
if (!ctx->InitAPI(nullptr, &g_Config.sVulkanDevice, errorMessage)) {
fprintf(stderr, "Graphics initialization failed: %s\n", errorMessage->c_str());
return false;
}
if (!ctx->InitSurface(windowSystem, data1, data2, errorMessage)) {
fprintf(stderr, "Surface creation failed: %s\n", errorMessage->c_str());
return false;
}
*graphicsContext = ctx;
return true;
};
GraphicsContext *graphicsContext = nullptr;
std::string error_message;
if (!initializeBackend((GPUBackend)g_Config.iGPUBackend, &graphicsContext, &error_message)) {
fprintf(stderr, "Failed to initialize graphics backend: %s\n", error_message.c_str());
if (fallbackGPUBackend != -1) {
fprintf(stderr, "Attempting to fall back to %s...\n", fallbackGPUBackend == (int)GPUBackend::OPENGL ? "OpenGL" : "Vulkan");
g_Config.iGPUBackend = fallbackGPUBackend;
error_message.clear();
if (!initializeBackend((GPUBackend)g_Config.iGPUBackend, &graphicsContext, &error_message)) {
fprintf(stderr, "Fallback failed: %s\n", error_message.c_str());
SDL_Quit();
return 1;
}
graphicsContext = vkctx;
} else {
graphicsContext = glctx;
}
#if !PPSSPP_PLATFORM(SWITCH)
} else if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
// Overwrite the surface init params with what we need for Vulkan..
if (!DetermineVulkanWindowSystem(window, &windowSystem, &data1, &data2)) {
fprintf(stderr, "No fallback GPU backend available. Exiting.\n");
SDL_Quit();
return 1;
}
VulkanGraphicsContext *vkctx = new VulkanGraphicsContext();
vkctx->InitAPI(nullptr, &g_Config.sVulkanDevice, &error_message);
if (!vkctx->InitSurface(windowSystem, data1, data2, &error_message)) {
// Let's try the fallback once per process run.
fprintf(stderr, "Vulkan init error '%s' - falling back to GL\n", error_message.c_str());
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
SetGPUBackend((GPUBackend)g_Config.iGPUBackend);
delete vkctx;
// NOTE : This should match the three lines above in the OpenGL case.
SDLGLGraphicsContext *glctx = new SDLGLGraphicsContext(cmdLineOptions.force_gl_version);
glctx->InitAPI(nullptr, nullptr, &error_message);
if (!glctx->InitSurface(windowSystem, data1, data2, &error_message)) {
fprintf(stderr, "GL fallback failed: %s\n", error_message.c_str());
return 1;
}
graphicsContext = glctx;
} else {
graphicsContext = vkctx;
}
#endif
}
// At this point, we have a window that we can show finally.
SDL_ShowWindow(window);
if (x != SDL_WINDOWPOS_UNDEFINED && y != SDL_WINDOWPOS_UNDEFINED) {
SDL_SetWindowPosition(window, x, y);
}
UpdateScreenDPI(window);
float dpi_scale = 1.0f / (g_ForcedDPI == 0.0f ? g_DesktopDPI : g_ForcedDPI);
@@ -2175,6 +2184,7 @@ int main(int argc, char *argv[]) {
EnableFZ();
// We use the emuthread both for OpenGL and Vulkan, but in OpenGL mode we also render from the main thread.
_dbg_assert_(graphicsContext);
std::thread emuThread = EmuThread_Start(graphicsContext, new NativeApplication(), nullptr);
InputStateTracker inputTracker{};
@@ -2251,24 +2261,6 @@ int main(int argc, char *argv[]) {
UpdateWindowState(window);
}
}
if (g_rebootEmuThread) {
fprintf(stderr, "rebooting emu thread");
g_rebootEmuThread = false;
EmuThread_Join(graphicsContext, emuThread);
graphicsContext->ShutdownSurface();
fprintf(stderr, "OK, shutdown complete. starting up graphics again.\n");
if (g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
SDLGLGraphicsContext *ctx = (SDLGLGraphicsContext *)graphicsContext;
if (!ctx->InitSurface(windowSystem,data1, data2, &error_message)) {
fprintf(stderr, "Failed to reinit graphics.\n");
}
}
emuThread = EmuThread_Start(graphicsContext, new NativeApplication(), nullptr);
}
}
EmuThread_Join(graphicsContext, emuThread);