diff --git a/src/citra/emu_window/emu_window_sdl2_gl.cpp b/src/citra/emu_window/emu_window_sdl2_gl.cpp
index ec86f301a..956dd6acf 100644
--- a/src/citra/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/citra/emu_window/emu_window_sdl2_gl.cpp
@@ -42,10 +42,8 @@ private:
     SDL_GLContext context;
 };
 
-EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system_, bool fullscreen, bool is_secondary)
-    : EmuWindow_SDL2{system_, is_secondary} {
-    // Initialize the window
-    if (Settings::values.use_gles) {
+static SDL_Window* CreateGLWindow(const std::string& window_title, bool gles) {
+    if (gles) {
         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
@@ -54,7 +52,16 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system_, bool fullscreen, boo
         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
     }
+    return SDL_CreateWindow(window_title.c_str(),
+                            SDL_WINDOWPOS_UNDEFINED, // x position
+                            SDL_WINDOWPOS_UNDEFINED, // y position
+                            Core::kScreenTopWidth,
+                            Core::kScreenTopHeight + Core::kScreenBottomHeight,
+                            SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
+}
 
+EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system_, bool fullscreen, bool is_secondary)
+    : EmuWindow_SDL2{system_, is_secondary} {
     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
     SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
@@ -71,16 +78,16 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system_, bool fullscreen, boo
 
     std::string window_title = fmt::format("Citra {} | {}-{}", Common::g_build_fullname,
                                            Common::g_scm_branch, Common::g_scm_desc);
-    render_window =
-        SDL_CreateWindow(window_title.c_str(),
-                         SDL_WINDOWPOS_UNDEFINED, // x position
-                         SDL_WINDOWPOS_UNDEFINED, // y position
-                         Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight,
-                         SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
 
+    // First, try to create a context with the requested type.
+    render_window = CreateGLWindow(window_title, Settings::values.use_gles.GetValue());
     if (render_window == nullptr) {
-        LOG_CRITICAL(Frontend, "Failed to create SDL2 window: {}", SDL_GetError());
-        exit(1);
+        // On failure, fall back to context with flipped type.
+        render_window = CreateGLWindow(window_title, !Settings::values.use_gles.GetValue());
+        if (render_window == nullptr) {
+            LOG_CRITICAL(Frontend, "Failed to create SDL2 window: {}", SDL_GetError());
+            exit(1);
+        }
     }
 
     strict_context_required = std::strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0;
@@ -106,7 +113,11 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system_, bool fullscreen, boo
     }
 
     render_window_id = SDL_GetWindowID(render_window);
-    auto gl_load_func = Settings::values.use_gles ? gladLoadGLES2Loader : gladLoadGLLoader;
+
+    int profile_mask = 0;
+    SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
+    auto gl_load_func =
+        profile_mask == SDL_GL_CONTEXT_PROFILE_ES ? gladLoadGLES2Loader : gladLoadGLLoader;
 
     if (!gl_load_func(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
         LOG_CRITICAL(Frontend, "Failed to initialize GL functions: {}", SDL_GetError());
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 9323667c5..ca2289b79 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -138,37 +138,50 @@ void EmuThread::run() {
 }
 
 #ifdef HAS_OPENGL
+static std::unique_ptr<QOpenGLContext> CreateQOpenGLContext(bool gles) {
+    QSurfaceFormat format;
+    if (gles) {
+        format.setRenderableType(QSurfaceFormat::RenderableType::OpenGLES);
+        format.setVersion(3, 2);
+    } else {
+        format.setRenderableType(QSurfaceFormat::RenderableType::OpenGL);
+        format.setVersion(4, 3);
+    }
+    format.setProfile(QSurfaceFormat::CoreProfile);
+
+    if (Settings::values.renderer_debug) {
+        format.setOption(QSurfaceFormat::FormatOption::DebugContext);
+    }
+
+    // TODO: expose a setting for buffer value (ie default/single/double/triple)
+    format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
+    format.setSwapInterval(0);
+
+    auto context = std::make_unique<QOpenGLContext>();
+    context->setFormat(format);
+    if (!context->create()) {
+        LOG_ERROR(Frontend, "Unable to create OpenGL context with GLES = {}", gles);
+        return nullptr;
+    }
+    return context;
+}
+
 class OpenGLSharedContext : public Frontend::GraphicsContext {
 public:
     /// Create the original context that should be shared from
     explicit OpenGLSharedContext() {
-        QSurfaceFormat format;
-
-        if (Settings::values.use_gles) {
-            format.setRenderableType(QSurfaceFormat::RenderableType::OpenGLES);
-            format.setVersion(3, 2);
-        } else {
-            format.setRenderableType(QSurfaceFormat::RenderableType::OpenGL);
-            format.setVersion(4, 3);
-        }
-        format.setProfile(QSurfaceFormat::CoreProfile);
-
-        if (Settings::values.renderer_debug) {
-            format.setOption(QSurfaceFormat::FormatOption::DebugContext);
-        }
-
-        // TODO: expose a setting for buffer value (ie default/single/double/triple)
-        format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
-        format.setSwapInterval(0);
-
-        context = std::make_unique<QOpenGLContext>();
-        context->setFormat(format);
-        if (!context->create()) {
-            LOG_ERROR(Frontend, "Unable to create main openGL context");
+        // First, try to create a context with the requested type.
+        context = CreateQOpenGLContext(Settings::values.use_gles.GetValue());
+        if (context == nullptr) {
+            // On failure, fall back to context with flipped type.
+            context = CreateQOpenGLContext(!Settings::values.use_gles.GetValue());
+            if (context == nullptr) {
+                LOG_ERROR(Frontend, "Unable to create any OpenGL context.");
+            }
         }
 
         offscreen_surface = std::make_unique<QOffscreenSurface>(nullptr);
-        offscreen_surface->setFormat(format);
+        offscreen_surface->setFormat(context->format());
         offscreen_surface->create();
         surface = offscreen_surface.get();
     }
@@ -184,7 +197,7 @@ public:
         context->setShareContext(share_context);
         context->setFormat(format);
         if (!context->create()) {
-            LOG_ERROR(Frontend, "Unable to create shared openGL context");
+            LOG_ERROR(Frontend, "Unable to create shared OpenGL context");
         }
 
         surface = main_surface;
@@ -194,6 +207,10 @@ public:
         OpenGLSharedContext::DoneCurrent();
     }
 
+    bool IsGLES() override {
+        return context->format().renderableType() == QSurfaceFormat::RenderableType::OpenGLES;
+    }
+
     void SwapBuffers() override {
         context->swapBuffers(surface);
     }
@@ -739,8 +756,9 @@ bool GRenderWindow::LoadOpenGL() {
 #ifdef HAS_OPENGL
     auto context = CreateSharedContext();
     auto scope = context->Acquire();
+    const auto gles = context->IsGLES();
 
-    auto gl_load_func = Settings::values.use_gles ? gladLoadGLES2Loader : gladLoadGLLoader;
+    auto gl_load_func = gles ? gladLoadGLES2Loader : gladLoadGLLoader;
     if (!gl_load_func(GetProcAddressGL)) {
         QMessageBox::warning(
             this, tr("Error while initializing OpenGL!"),
@@ -751,14 +769,14 @@ bool GRenderWindow::LoadOpenGL() {
     const QString renderer =
         QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
 
-    if (!Settings::values.use_gles && !GLAD_GL_VERSION_4_3) {
+    if (!gles && !GLAD_GL_VERSION_4_3) {
         LOG_ERROR(Frontend, "GPU does not support OpenGL 4.3: {}", renderer.toStdString());
         QMessageBox::warning(this, tr("Error while initializing OpenGL 4.3!"),
                              tr("Your GPU may not support OpenGL 4.3, or you do not have the "
                                 "latest graphics driver.<br><br>GL Renderer:<br>%1")
                                  .arg(renderer));
         return false;
-    } else if (Settings::values.use_gles && !GLAD_GL_ES_VERSION_3_2) {
+    } else if (gles && !GLAD_GL_ES_VERSION_3_2) {
         LOG_ERROR(Frontend, "GPU does not support OpenGL ES 3.2: {}", renderer.toStdString());
         QMessageBox::warning(this, tr("Error while initializing OpenGL ES 3.2!"),
                              tr("Your GPU may not support OpenGL ES 3.2, or you do not have the "
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 766449110..2135ff2e8 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -77,6 +77,11 @@ class GraphicsContext {
 public:
     virtual ~GraphicsContext();
 
+    /// Checks whether this context uses OpenGL ES.
+    virtual bool IsGLES() {
+        return false;
+    }
+
     /// Inform the driver to swap the front/back buffers and present the current image
     virtual void SwapBuffers(){};