diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp index c7d2513b5..f8fe7135d 100644 --- a/src/citra/emu_window/emu_window_sdl2.cpp +++ b/src/citra/emu_window/emu_window_sdl2.cpp @@ -84,7 +84,7 @@ void EmuWindow_SDL2::RequestClose() { void EmuWindow_SDL2::OnResize() { int width, height; - SDL_GetWindowSize(render_window, &width, &height); + SDL_GL_GetDrawableSize(render_window, &width, &height); UpdateCurrentFramebufferLayout(width, height); } diff --git a/src/citra/emu_window/emu_window_sdl2_gl.cpp b/src/citra/emu_window/emu_window_sdl2_gl.cpp index 46098a7e7..f0256fc1e 100644 --- a/src/citra/emu_window/emu_window_sdl2_gl.cpp +++ b/src/citra/emu_window/emu_window_sdl2_gl.cpp @@ -82,6 +82,8 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(bool fullscreen, bool is_secondary) exit(1); } + strict_context_required = std::strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0; + dummy_window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 5b3238b42..e99f898ab 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -40,6 +40,8 @@ #include #endif +static Frontend::WindowSystemType GetWindowSystemType(); + EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(core_context) {} EmuThread::~EmuThread() = default; @@ -242,6 +244,9 @@ public: : RenderWidget(parent), is_secondary(is_secondary) { setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_PaintOnScreen); + if (GetWindowSystemType() == Frontend::WindowSystemType::Wayland) { + setAttribute(Qt::WA_DontCreateNativeAncestors); + } windowHandle()->setSurfaceType(QWindow::OpenGLSurface); } @@ -401,6 +406,7 @@ GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread, bool is_se setLayout(layout); this->setMouseTracking(true); + strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland"); GMainWindow* parent = GetMainWindow(); connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); @@ -660,6 +666,12 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair minimal bool GRenderWindow::InitializeOpenGL() { #ifdef HAS_OPENGL + if (!QOpenGLContext::supportsThreadedOpenGL()) { + QMessageBox::warning(this, tr("OpenGL not available!"), + tr("OpenGL shared contexts are not supported.")); + return false; + } + // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, // WA_DontShowOnScreen, WA_DeleteOnClose auto child = new OpenGLRenderWidget(this, is_secondary); diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 61846a8a5..a82b8559c 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -203,6 +203,10 @@ public: return active_config; } + bool StrictContextRequired() const { + return strict_context_required; + } + /** * Requests the internal configuration to be replaced by the specified argument at some point in * the future. @@ -268,6 +272,7 @@ protected: } bool is_secondary{}; + bool strict_context_required{}; WindowSystemInfo window_info; private: diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index c3ad18b57..ab1c20b1d 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "common/scope_exit.h" #include "video_core/renderer_opengl/gl_driver.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_disk_cache.h" @@ -367,7 +368,9 @@ public: ShaderProgramManager::ShaderProgramManager(Frontend::EmuWindow& emu_window_, const Driver& driver_, bool separable) - : impl(std::make_unique(separable)), emu_window{emu_window_}, driver{driver_} {} + : emu_window{emu_window_}, driver{driver_}, + strict_context_required{emu_window.StrictContextRequired()}, impl{std::make_unique( + separable)} {} ShaderProgramManager::~ShaderProgramManager() = default; @@ -622,8 +625,8 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, compilation_failed = false; std::size_t built_shaders = 0; // It doesn't have be atomic since it's used behind a mutex - const auto LoadRawSepareble = [&](Frontend::GraphicsContext* context, std::size_t begin, - std::size_t end) { + const auto LoadRawSepareble = [&](std::size_t begin, std::size_t end, + Frontend::GraphicsContext* context = nullptr) { const auto scope = context->Acquire(); for (std::size_t i = begin; i < end; ++i) { if (stop_loading || compilation_failed) { @@ -683,27 +686,32 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, } }; - const std::size_t num_workers{std::max(1U, std::thread::hardware_concurrency())}; - const std::size_t bucket_size{load_raws_size / num_workers}; - std::vector> contexts(num_workers); - std::vector threads(num_workers); + if (!strict_context_required) { + const std::size_t num_workers{std::max(1U, std::thread::hardware_concurrency())}; + const std::size_t bucket_size{load_raws_size / num_workers}; + std::vector> contexts(num_workers); + std::vector threads(num_workers); - emu_window.SaveContext(); - for (std::size_t i = 0; i < num_workers; ++i) { - const bool is_last_worker = i + 1 == num_workers; - const std::size_t start{bucket_size * i}; - const std::size_t end{is_last_worker ? load_raws_size : start + bucket_size}; + emu_window.SaveContext(); + for (std::size_t i = 0; i < num_workers; ++i) { + const bool is_last_worker = i + 1 == num_workers; + const std::size_t start{bucket_size * i}; + const std::size_t end{is_last_worker ? load_raws_size : start + bucket_size}; - // On some platforms the shared context has to be created from the GUI thread - contexts[i] = emu_window.CreateSharedContext(); - // Release the context, so it can be immediately used by the spawned thread - contexts[i]->DoneCurrent(); - threads[i] = std::thread(LoadRawSepareble, contexts[i].get(), start, end); + // On some platforms the shared context has to be created from the GUI thread + contexts[i] = emu_window.CreateSharedContext(); + // Release the context, so it can be immediately used by the spawned thread + contexts[i]->DoneCurrent(); + threads[i] = std::thread(LoadRawSepareble, start, end, contexts[i].get()); + } + for (auto& thread : threads) { + thread.join(); + } + emu_window.RestoreContext(); + } else { + const auto dummy_context{std::make_unique()}; + LoadRawSepareble(0, load_raws_size, dummy_context.get()); } - for (auto& thread : threads) { - thread.join(); - } - emu_window.RestoreContext(); if (compilation_failed) { disk_cache.InvalidateAll(); diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 561046aa7..d0b59754b 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -46,10 +46,10 @@ public: void ApplyTo(OpenGLState& state); private: - class Impl; - std::unique_ptr impl; - Frontend::EmuWindow& emu_window; const Driver& driver; + bool strict_context_required; + class Impl; + std::unique_ptr impl; }; } // namespace OpenGL