Ports: Support "restarts" in SDL2

SDL2 applications are prone to reinitializing the SDL components when,
for example, changing the display resolution. This would lead to
crashes since we were doing things in the wrong order.

* We now decouple `GLContext` from `SDL_Window` a bit more, allowing
  the window to be destroyed before the GLContext.
* Do not quit the `GUI::Application`, let our event loop handle exiting

These changes allow changing the display resolution in the Quake3 port.
This commit is contained in:
Jelle Raaijmakers 2022-08-31 12:21:08 +02:00 committed by Linus Groh
parent 7d544344ca
commit 14ece2ac90
Notes: sideshowbarker 2024-07-17 07:36:40 +09:00

View file

@ -34,8 +34,8 @@ Co-Authored-By: circl <circl.lastname@gmail.com>
src/video/serenity/SDL_serenitymessagebox.h | 38 ++ src/video/serenity/SDL_serenitymessagebox.h | 38 ++
src/video/serenity/SDL_serenitymouse.cpp | 142 +++++ src/video/serenity/SDL_serenitymouse.cpp | 142 +++++
src/video/serenity/SDL_serenitymouse.h | 39 ++ src/video/serenity/SDL_serenitymouse.h | 39 ++
src/video/serenity/SDL_serenityvideo.cpp | 600 ++++++++++++++++++ src/video/serenity/SDL_serenityvideo.cpp | 597 ++++++++++++++++++
src/video/serenity/SDL_serenityvideo.h | 98 +++ src/video/serenity/SDL_serenityvideo.h | 101 +++
20 files changed, 1292 insertions(+), 25 deletions(-) 20 files changed, 1292 insertions(+), 25 deletions(-)
create mode 100644 src/audio/serenity/SDL_serenityaudio.cpp create mode 100644 src/audio/serenity/SDL_serenityaudio.cpp
create mode 100644 src/audio/serenity/SDL_serenityaudio.h create mode 100644 src/audio/serenity/SDL_serenityaudio.h
@ -862,10 +862,10 @@ index 0000000..039f036
+/* vi: set ts=4 sw=4 expandtab: */ +/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/serenity/SDL_serenityvideo.cpp b/src/video/serenity/SDL_serenityvideo.cpp diff --git a/src/video/serenity/SDL_serenityvideo.cpp b/src/video/serenity/SDL_serenityvideo.cpp
new file mode 100644 new file mode 100644
index 0000000..85e69ef index 0000000..e222405
--- /dev/null --- /dev/null
+++ b/src/video/serenity/SDL_serenityvideo.cpp +++ b/src/video/serenity/SDL_serenityvideo.cpp
@@ -0,0 +1,600 @@ @@ -0,0 +1,597 @@
+/* +/*
+ Simple DirectMedia Layer + Simple DirectMedia Layer
+ Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org> + Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
@ -904,14 +904,14 @@ index 0000000..85e69ef
+# include "SDL_serenitymouse.h" +# include "SDL_serenitymouse.h"
+# include "SDL_serenityvideo.h" +# include "SDL_serenityvideo.h"
+ +
+# include <dlfcn.h>
+# include <LibCore/EventLoop.h> +# include <LibCore/EventLoop.h>
+# include <LibGfx/Bitmap.h>
+# include <LibGUI/Application.h> +# include <LibGUI/Application.h>
+# include <LibGUI/Desktop.h> +# include <LibGUI/Desktop.h>
+# include <LibGUI/Painter.h> +# include <LibGUI/Painter.h>
+# include <LibGUI/Widget.h> +# include <LibGUI/Widget.h>
+# include <LibGUI/Window.h> +# include <LibGUI/Window.h>
+# include <LibGfx/Bitmap.h>
+# include <dlfcn.h>
+ +
+static SDL_Scancode scancode_map[] = { +static SDL_Scancode scancode_map[] = {
+ SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN,
@ -1112,11 +1112,12 @@ index 0000000..85e69ef
+ +
+int SERENITY_VideoInit(_THIS) +int SERENITY_VideoInit(_THIS)
+{ +{
+ VERIFY(!g_app); + dbgln("{}: Initialising SDL application", __FUNCTION__);
+ g_app = GUI::Application::construct(0, nullptr);
+ g_app->set_quit_when_last_window_deleted(false);
+ +
+ dbgln("SDL2: Initialising SDL application"); + if (!g_app) {
+ g_app = GUI::Application::construct(0, nullptr);
+ g_app->set_quit_when_last_window_deleted(false);
+ }
+ +
+ SERENITY_InitMouse(_this); + SERENITY_InitMouse(_this);
+ +
@ -1131,9 +1132,8 @@ index 0000000..85e69ef
+ mode.refresh_rate = 60; + mode.refresh_rate = 60;
+ mode.driverdata = nullptr; + mode.driverdata = nullptr;
+ +
+ if (SDL_AddBasicVideoDisplay(&mode) < 0) { + if (SDL_AddBasicVideoDisplay(&mode) < 0)
+ return -1; + return -1;
+ }
+ +
+ SDL_AddDisplayMode(&_this->displays[0], &mode); + SDL_AddDisplayMode(&_this->displays[0], &mode);
+ +
@ -1152,13 +1152,11 @@ index 0000000..85e69ef
+{ +{
+ dbgln("SERENITY_VideoQuit"); + dbgln("SERENITY_VideoQuit");
+ SERENITY_QuitMouse(_this); + SERENITY_QuitMouse(_this);
+ g_app->quit();
+} +}
+ +
+SerenitySDLWidget::SerenitySDLWidget(SDL_Window* window) +SerenitySDLWidget::SerenitySDLWidget(SDL_Window* sdl_window)
+ : m_sdl_window(window) + : m_sdl_window(sdl_window)
+{ +{
+ update();
+} +}
+ +
+void SerenitySDLWidget::paint_event(GUI::PaintEvent& event) +void SerenitySDLWidget::paint_event(GUI::PaintEvent& event)
@ -1248,7 +1246,8 @@ index 0000000..85e69ef
+ +
+int Serenity_CreateWindow(_THIS, SDL_Window* window) +int Serenity_CreateWindow(_THIS, SDL_Window* window)
+{ +{
+ dbgln("SDL2: Creating new window of size {}x{}", window->w, window->h); + dbgln("{}: Creating new window of size {}x{}", __FUNCTION__, window->w, window->h);
+
+ auto w = new SerenityPlatformWindow(window); + auto w = new SerenityPlatformWindow(window);
+ window->driverdata = w; + window->driverdata = w;
+ w->window()->set_double_buffering_enabled(false); + w->window()->set_double_buffering_enabled(false);
@ -1357,7 +1356,7 @@ index 0000000..85e69ef
+int Serenity_CreateWindowFramebuffer(_THIS, SDL_Window* window, Uint32* format, +int Serenity_CreateWindowFramebuffer(_THIS, SDL_Window* window, Uint32* format,
+ void** pixels, int* pitch) + void** pixels, int* pitch)
+{ +{
+ dbgln("SDL2: Creating a new framebuffer of size {}x{}", window->w, window->h); + dbgln("{}: Creating a new framebuffer of size {}x{}", __FUNCTION__, window->w, window->h);
+ auto win = SerenityPlatformWindow::from_sdl_window(window); + auto win = SerenityPlatformWindow::from_sdl_window(window);
+ *format = SDL_PIXELFORMAT_RGB888; + *format = SDL_PIXELFORMAT_RGB888;
+ auto bitmap_or_error = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRx8888, {window->w, window->h}); + auto bitmap_or_error = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRx8888, {window->w, window->h});
@ -1366,7 +1365,6 @@ index 0000000..85e69ef
+ win->widget()->m_buffer = bitmap_or_error.release_value(); + win->widget()->m_buffer = bitmap_or_error.release_value();
+ *pitch = win->widget()->m_buffer->pitch(); + *pitch = win->widget()->m_buffer->pitch();
+ *pixels = win->widget()->m_buffer->scanline(0); + *pixels = win->widget()->m_buffer->scanline(0);
+ dbgln("Created framebuffer {}x{}", win->widget()->width(), win->widget()->height());
+ return 0; + return 0;
+} +}
+ +
@ -1385,32 +1383,29 @@ index 0000000..85e69ef
+void Serenity_DestroyWindowFramebuffer(_THIS, SDL_Window* window) +void Serenity_DestroyWindowFramebuffer(_THIS, SDL_Window* window)
+{ +{
+ auto widget = SerenityPlatformWindow::from_sdl_window(window)->widget(); + auto widget = SerenityPlatformWindow::from_sdl_window(window)->widget();
+ dbgln("SDL2: Destroy framebuffer {}", widget->m_buffer->size()); + dbgln("{}: Destroy framebuffer {}", __FUNCTION__, widget->m_buffer->size());
+ widget->m_buffer = nullptr; + widget->m_buffer = nullptr;
+} +}
+ +
+SDL_GLContext Serenity_GL_CreateContext(_THIS, SDL_Window* window) +SDL_GLContext Serenity_GL_CreateContext(_THIS, SDL_Window* window)
+{ +{
+ auto win = SerenityPlatformWindow::from_sdl_window(window); + auto platform_window = SerenityPlatformWindow::from_sdl_window(window);
+ +
+ Uint32 format; + Uint32 format;
+ void* pixels; + void* pixels;
+ int pitch; + int pitch;
+ Serenity_CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch); + Serenity_CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch);
+ +
+ win->widget()->m_gl_context = GL::create_context(*win->widget()->m_buffer); + auto gl_context = GL::create_context(*platform_window->widget()->m_buffer);
+ GL::make_context_current(win->widget()->m_gl_context); + auto serenity_gl_context = new SerenityGLContext(move(gl_context));
+ + platform_window->set_serenity_gl_context(serenity_gl_context);
+ return new SerenityGLContext(*window); + GL::make_context_current(&serenity_gl_context->gl_context());
+ return serenity_gl_context;
+} +}
+ +
+void Serenity_GL_DeleteContext(_THIS, SDL_GLContext context) +void Serenity_GL_DeleteContext(_THIS, SDL_GLContext context)
+{ +{
+ auto platform_context = static_cast<SerenityGLContext*>(context); + auto platform_context = static_cast<SerenityGLContext*>(context);
+ auto sdl_window = platform_context->sdl_window();
+ auto platform_window = SerenityPlatformWindow::from_sdl_window(&sdl_window);
+
+ platform_window->widget()->m_gl_context = nullptr;
+ delete platform_context; + delete platform_context;
+} +}
+ +
@ -1449,17 +1444,19 @@ index 0000000..85e69ef
+ return 0; + return 0;
+ +
+ auto platform_window = SerenityPlatformWindow::from_sdl_window(window); + auto platform_window = SerenityPlatformWindow::from_sdl_window(window);
+ GL::make_context_current(platform_window->widget()->m_gl_context); + auto serenity_gl_context = static_cast<SerenityGLContext*>(context);
+ platform_window->set_serenity_gl_context(serenity_gl_context);
+ GL::make_context_current(&serenity_gl_context->gl_context());
+ return 0; + return 0;
+} +}
+ +
+int Serenity_GL_SwapWindow(_THIS, SDL_Window* window) +int Serenity_GL_SwapWindow(_THIS, SDL_Window* window)
+{ +{
+ auto win = SerenityPlatformWindow::from_sdl_window(window); + auto platform_window = SerenityPlatformWindow::from_sdl_window(window);
+ if (win->widget()->m_gl_context) + if (platform_window->serenity_gl_context())
+ GL::present_context(win->widget()->m_gl_context); + GL::present_context(&platform_window->serenity_gl_context()->gl_context());
+ +
+ win->widget()->repaint(); + platform_window->widget()->repaint();
+ return 0; + return 0;
+} +}
+ +
@ -1468,10 +1465,10 @@ index 0000000..85e69ef
+/* vi: set ts=4 sw=4 expandtab: */ +/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/serenity/SDL_serenityvideo.h b/src/video/serenity/SDL_serenityvideo.h diff --git a/src/video/serenity/SDL_serenityvideo.h b/src/video/serenity/SDL_serenityvideo.h
new file mode 100644 new file mode 100644
index 0000000..b5c6759 index 0000000..f74e1bd
--- /dev/null --- /dev/null
+++ b/src/video/serenity/SDL_serenityvideo.h +++ b/src/video/serenity/SDL_serenityvideo.h
@@ -0,0 +1,98 @@ @@ -0,0 +1,101 @@
+/* +/*
+ Simple DirectMedia Layer + Simple DirectMedia Layer
+ Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org> + Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
@ -1508,7 +1505,6 @@ index 0000000..b5c6759
+public: +public:
+ explicit SerenitySDLWidget(SDL_Window*); + explicit SerenitySDLWidget(SDL_Window*);
+ RefPtr<Gfx::Bitmap> m_buffer; + RefPtr<Gfx::Bitmap> m_buffer;
+ OwnPtr<GL::GLContext> m_gl_context;
+ +
+protected: +protected:
+ void paint_event(GUI::PaintEvent&) override; + void paint_event(GUI::PaintEvent&) override;
@ -1531,11 +1527,24 @@ index 0000000..b5c6759
+ SDL_Window* m_sdl_window = nullptr; + SDL_Window* m_sdl_window = nullptr;
+}; +};
+ +
+class SerenityGLContext final {
+public:
+ explicit SerenityGLContext(NonnullOwnPtr<GL::GLContext> gl_context)
+ : m_gl_context(move(gl_context))
+ {
+ }
+
+ GL::GLContext& gl_context() { return *m_gl_context; }
+
+private:
+ NonnullOwnPtr<GL::GLContext> m_gl_context;
+};
+
+class SerenityPlatformWindow final { +class SerenityPlatformWindow final {
+public: +public:
+ SerenityPlatformWindow(SDL_Window* sdl_window) + explicit SerenityPlatformWindow(SDL_Window* sdl_window)
+ : m_window(GUI::Window::construct()) + : m_window(MUST(GUI::Window::try_create()))
+ , m_widget(SerenitySDLWidget::construct(sdl_window)) + , m_widget(MUST(SerenitySDLWidget::try_create(sdl_window)))
+ { + {
+ m_window->resize(sdl_window->w, sdl_window->h); + m_window->resize(sdl_window->w, sdl_window->h);
+ m_window->set_resizable(false); + m_window->set_resizable(false);
@ -1546,27 +1555,18 @@ index 0000000..b5c6759
+ return static_cast<SerenityPlatformWindow*>(window->driverdata); + return static_cast<SerenityPlatformWindow*>(window->driverdata);
+ } + }
+ +
+ SerenityGLContext* serenity_gl_context() { return m_serenity_gl_context; }
+ void set_serenity_gl_context(SerenityGLContext* serenity_gl_context) { m_serenity_gl_context = serenity_gl_context; }
+
+ NonnullRefPtr<GUI::Window> window() { return m_window; } + NonnullRefPtr<GUI::Window> window() { return m_window; }
+ NonnullRefPtr<SerenitySDLWidget> widget() { return m_widget; } + NonnullRefPtr<SerenitySDLWidget> widget() { return m_widget; }
+ +
+private: +private:
+ SerenityGLContext* m_serenity_gl_context;
+ NonnullRefPtr<GUI::Window> m_window; + NonnullRefPtr<GUI::Window> m_window;
+ NonnullRefPtr<SerenitySDLWidget> m_widget; + NonnullRefPtr<SerenitySDLWidget> m_widget;
+}; +};
+ +
+class SerenityGLContext final {
+public:
+ explicit SerenityGLContext(SDL_Window& sdl_window)
+ : m_sdl_window(sdl_window)
+ {
+ }
+
+ SDL_Window& sdl_window() const { return m_sdl_window; }
+
+private:
+ SDL_Window& m_sdl_window;
+};
+
+#endif /* SDL_serenityvideo_h_ */ +#endif /* SDL_serenityvideo_h_ */
+ +
+/* vi: set ts=4 sw=4 expandtab: */ +/* vi: set ts=4 sw=4 expandtab: */