@@ -131,6 +131,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.
 | 
			
		||||
@@ -207,6 +211,8 @@ protected:
 | 
			
		||||
 | 
			
		||||
    WindowSystemInfo window_info;
 | 
			
		||||
 | 
			
		||||
    bool strict_context_required = false;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    /**
 | 
			
		||||
     * Handler called when the minimal client area was requested to be changed via SetConfig.
 | 
			
		||||
 
 | 
			
		||||
@@ -223,8 +223,6 @@ struct GPU::Impl {
 | 
			
		||||
    /// core timing events.
 | 
			
		||||
    void Start() {
 | 
			
		||||
        gpu_thread.StartThread(*renderer, renderer->Context(), *scheduler);
 | 
			
		||||
        cpu_context = renderer->GetRenderWindow().CreateSharedContext();
 | 
			
		||||
        cpu_context->MakeCurrent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void NotifyShutdown() {
 | 
			
		||||
@@ -235,6 +233,9 @@ struct GPU::Impl {
 | 
			
		||||
 | 
			
		||||
    /// Obtain the CPU Context
 | 
			
		||||
    void ObtainContext() {
 | 
			
		||||
        if (!cpu_context) {
 | 
			
		||||
            cpu_context = renderer->GetRenderWindow().CreateSharedContext();
 | 
			
		||||
        }
 | 
			
		||||
        cpu_context->MakeCurrent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -112,7 +112,7 @@ bool IsASTCSupported() {
 | 
			
		||||
}
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
 | 
			
		||||
Device::Device() {
 | 
			
		||||
Device::Device(Core::Frontend::EmuWindow& emu_window) {
 | 
			
		||||
    if (!GLAD_GL_VERSION_4_6) {
 | 
			
		||||
        LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available");
 | 
			
		||||
        throw std::runtime_error{"Insufficient version"};
 | 
			
		||||
@@ -126,9 +126,9 @@ Device::Device() {
 | 
			
		||||
    const bool is_intel = vendor_name == "Intel";
 | 
			
		||||
 | 
			
		||||
#ifdef __unix__
 | 
			
		||||
    const bool is_linux = true;
 | 
			
		||||
    constexpr bool is_linux = true;
 | 
			
		||||
#else
 | 
			
		||||
    const bool is_linux = false;
 | 
			
		||||
    constexpr bool is_linux = false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    bool disable_fast_buffer_sub_data = false;
 | 
			
		||||
@@ -193,9 +193,11 @@ Device::Device() {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    strict_context_required = emu_window.StrictContextRequired();
 | 
			
		||||
    // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation.
 | 
			
		||||
    // Blocks EGL on Wayland from using asynchronous shader compilation.
 | 
			
		||||
    use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() &&
 | 
			
		||||
                               !(is_amd || (is_intel && !is_linux));
 | 
			
		||||
                               !(is_amd || (is_intel && !is_linux)) && !strict_context_required;
 | 
			
		||||
    use_driver_cache = is_nvidia;
 | 
			
		||||
 | 
			
		||||
    LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/frontend/emu_window.h"
 | 
			
		||||
#include "shader_recompiler/stage.h"
 | 
			
		||||
 | 
			
		||||
namespace Settings {
 | 
			
		||||
@@ -15,7 +16,7 @@ namespace OpenGL {
 | 
			
		||||
 | 
			
		||||
class Device {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Device();
 | 
			
		||||
    explicit Device(Core::Frontend::EmuWindow& emu_window);
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] std::string GetVendorName() const;
 | 
			
		||||
 | 
			
		||||
@@ -173,6 +174,10 @@ public:
 | 
			
		||||
        return can_report_memory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool StrictContextRequired() const {
 | 
			
		||||
        return strict_context_required;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static bool TestVariableAoffi();
 | 
			
		||||
    static bool TestPreciseBug();
 | 
			
		||||
@@ -216,6 +221,7 @@ private:
 | 
			
		||||
    bool has_cbuf_ftou_bug{};
 | 
			
		||||
    bool has_bool_ref_bug{};
 | 
			
		||||
    bool can_report_memory{};
 | 
			
		||||
    bool strict_context_required{};
 | 
			
		||||
 | 
			
		||||
    std::string vendor_name;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -174,6 +174,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo
 | 
			
		||||
      texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_},
 | 
			
		||||
      state_tracker{state_tracker_}, shader_notify{shader_notify_},
 | 
			
		||||
      use_asynchronous_shaders{device.UseAsynchronousShaders()},
 | 
			
		||||
      strict_context_required{device.StrictContextRequired()},
 | 
			
		||||
      profile{
 | 
			
		||||
          .supported_spirv = 0x00010000,
 | 
			
		||||
 | 
			
		||||
@@ -255,9 +256,14 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
 | 
			
		||||
    }
 | 
			
		||||
    shader_cache_filename = base_dir / "opengl.bin";
 | 
			
		||||
 | 
			
		||||
    if (!workers) {
 | 
			
		||||
    if (!workers && !strict_context_required) {
 | 
			
		||||
        workers = CreateWorkers();
 | 
			
		||||
    }
 | 
			
		||||
    std::optional<Context> strict_context;
 | 
			
		||||
    if (strict_context_required) {
 | 
			
		||||
        strict_context.emplace(emu_window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
        std::mutex mutex;
 | 
			
		||||
        size_t total{};
 | 
			
		||||
@@ -265,44 +271,49 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
 | 
			
		||||
        bool has_loaded{};
 | 
			
		||||
    } state;
 | 
			
		||||
 | 
			
		||||
    const auto queue_work{[&](Common::UniqueFunction<void, Context*>&& work) {
 | 
			
		||||
        if (strict_context_required) {
 | 
			
		||||
            work(&strict_context.value());
 | 
			
		||||
        } else {
 | 
			
		||||
            workers->QueueWork(std::move(work));
 | 
			
		||||
        }
 | 
			
		||||
    }};
 | 
			
		||||
    const auto load_compute{[&](std::ifstream& file, FileEnvironment env) {
 | 
			
		||||
        ComputePipelineKey key;
 | 
			
		||||
        file.read(reinterpret_cast<char*>(&key), sizeof(key));
 | 
			
		||||
        workers->QueueWork(
 | 
			
		||||
            [this, key, env = std::move(env), &state, &callback](Context* ctx) mutable {
 | 
			
		||||
                ctx->pools.ReleaseContents();
 | 
			
		||||
                auto pipeline{CreateComputePipeline(ctx->pools, key, env)};
 | 
			
		||||
                std::scoped_lock lock{state.mutex};
 | 
			
		||||
                if (pipeline) {
 | 
			
		||||
                    compute_cache.emplace(key, std::move(pipeline));
 | 
			
		||||
                }
 | 
			
		||||
                ++state.built;
 | 
			
		||||
                if (state.has_loaded) {
 | 
			
		||||
                    callback(VideoCore::LoadCallbackStage::Build, state.built, state.total);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        queue_work([this, key, env = std::move(env), &state, &callback](Context* ctx) mutable {
 | 
			
		||||
            ctx->pools.ReleaseContents();
 | 
			
		||||
            auto pipeline{CreateComputePipeline(ctx->pools, key, env)};
 | 
			
		||||
            std::scoped_lock lock{state.mutex};
 | 
			
		||||
            if (pipeline) {
 | 
			
		||||
                compute_cache.emplace(key, std::move(pipeline));
 | 
			
		||||
            }
 | 
			
		||||
            ++state.built;
 | 
			
		||||
            if (state.has_loaded) {
 | 
			
		||||
                callback(VideoCore::LoadCallbackStage::Build, state.built, state.total);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        ++state.total;
 | 
			
		||||
    }};
 | 
			
		||||
    const auto load_graphics{[&](std::ifstream& file, std::vector<FileEnvironment> envs) {
 | 
			
		||||
        GraphicsPipelineKey key;
 | 
			
		||||
        file.read(reinterpret_cast<char*>(&key), sizeof(key));
 | 
			
		||||
        workers->QueueWork(
 | 
			
		||||
            [this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable {
 | 
			
		||||
                boost::container::static_vector<Shader::Environment*, 5> env_ptrs;
 | 
			
		||||
                for (auto& env : envs) {
 | 
			
		||||
                    env_ptrs.push_back(&env);
 | 
			
		||||
                }
 | 
			
		||||
                ctx->pools.ReleaseContents();
 | 
			
		||||
                auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)};
 | 
			
		||||
                std::scoped_lock lock{state.mutex};
 | 
			
		||||
                if (pipeline) {
 | 
			
		||||
                    graphics_cache.emplace(key, std::move(pipeline));
 | 
			
		||||
                }
 | 
			
		||||
                ++state.built;
 | 
			
		||||
                if (state.has_loaded) {
 | 
			
		||||
                    callback(VideoCore::LoadCallbackStage::Build, state.built, state.total);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        queue_work([this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable {
 | 
			
		||||
            boost::container::static_vector<Shader::Environment*, 5> env_ptrs;
 | 
			
		||||
            for (auto& env : envs) {
 | 
			
		||||
                env_ptrs.push_back(&env);
 | 
			
		||||
            }
 | 
			
		||||
            ctx->pools.ReleaseContents();
 | 
			
		||||
            auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)};
 | 
			
		||||
            std::scoped_lock lock{state.mutex};
 | 
			
		||||
            if (pipeline) {
 | 
			
		||||
                graphics_cache.emplace(key, std::move(pipeline));
 | 
			
		||||
            }
 | 
			
		||||
            ++state.built;
 | 
			
		||||
            if (state.has_loaded) {
 | 
			
		||||
                callback(VideoCore::LoadCallbackStage::Build, state.built, state.total);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        ++state.total;
 | 
			
		||||
    }};
 | 
			
		||||
    LoadPipelines(stop_loading, shader_cache_filename, CACHE_VERSION, load_compute, load_graphics);
 | 
			
		||||
@@ -314,6 +325,9 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
 | 
			
		||||
    state.has_loaded = true;
 | 
			
		||||
    lock.unlock();
 | 
			
		||||
 | 
			
		||||
    if (strict_context_required) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    workers->WaitForRequests(stop_loading);
 | 
			
		||||
    if (!use_asynchronous_shaders) {
 | 
			
		||||
        workers.reset();
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,7 @@ private:
 | 
			
		||||
    StateTracker& state_tracker;
 | 
			
		||||
    VideoCore::ShaderNotify& shader_notify;
 | 
			
		||||
    const bool use_asynchronous_shaders;
 | 
			
		||||
    const bool strict_context_required;
 | 
			
		||||
 | 
			
		||||
    GraphicsPipelineKey graphics_key{};
 | 
			
		||||
    GraphicsPipeline* current_pipeline{};
 | 
			
		||||
 
 | 
			
		||||
@@ -140,8 +140,8 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
 | 
			
		||||
                               Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
 | 
			
		||||
                               std::unique_ptr<Core::Frontend::GraphicsContext> context_)
 | 
			
		||||
    : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_},
 | 
			
		||||
      emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, state_tracker{},
 | 
			
		||||
      program_manager{device},
 | 
			
		||||
      emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, device{emu_window_},
 | 
			
		||||
      state_tracker{}, program_manager{device},
 | 
			
		||||
      rasterizer(emu_window, gpu, cpu_memory, device, screen_info, program_manager, state_tracker) {
 | 
			
		||||
    if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) {
 | 
			
		||||
        glEnable(GL_DEBUG_OUTPUT);
 | 
			
		||||
 
 | 
			
		||||
@@ -139,23 +139,25 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
 | 
			
		||||
    RenderScreenshot(*framebuffer, use_accelerated);
 | 
			
		||||
 | 
			
		||||
    bool has_been_recreated = false;
 | 
			
		||||
    const auto recreate_swapchain = [&] {
 | 
			
		||||
    const auto recreate_swapchain = [&](u32 width, u32 height) {
 | 
			
		||||
        if (!has_been_recreated) {
 | 
			
		||||
            has_been_recreated = true;
 | 
			
		||||
            scheduler.Finish();
 | 
			
		||||
        }
 | 
			
		||||
        const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
 | 
			
		||||
        swapchain.Create(layout.width, layout.height, is_srgb);
 | 
			
		||||
        swapchain.Create(width, height, is_srgb);
 | 
			
		||||
    };
 | 
			
		||||
    if (swapchain.NeedsRecreation(is_srgb)) {
 | 
			
		||||
        recreate_swapchain();
 | 
			
		||||
 | 
			
		||||
    const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
 | 
			
		||||
    if (swapchain.NeedsRecreation(is_srgb) || swapchain.GetWidth() != layout.width ||
 | 
			
		||||
        swapchain.GetHeight() != layout.height) {
 | 
			
		||||
        recreate_swapchain(layout.width, layout.height);
 | 
			
		||||
    }
 | 
			
		||||
    bool is_outdated;
 | 
			
		||||
    do {
 | 
			
		||||
        swapchain.AcquireNextImage();
 | 
			
		||||
        is_outdated = swapchain.IsOutDated();
 | 
			
		||||
        if (is_outdated) {
 | 
			
		||||
            recreate_swapchain();
 | 
			
		||||
            recreate_swapchain(layout.width, layout.height);
 | 
			
		||||
        }
 | 
			
		||||
    } while (is_outdated);
 | 
			
		||||
    if (has_been_recreated) {
 | 
			
		||||
 
 | 
			
		||||
@@ -67,17 +67,19 @@ VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 wi
 | 
			
		||||
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
 | 
			
		||||
Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, u32 width,
 | 
			
		||||
                     u32 height, bool srgb)
 | 
			
		||||
Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_,
 | 
			
		||||
                     u32 width_, u32 height_, bool srgb)
 | 
			
		||||
    : surface{surface_}, device{device_}, scheduler{scheduler_} {
 | 
			
		||||
    Create(width, height, srgb);
 | 
			
		||||
    Create(width_, height_, srgb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Swapchain::~Swapchain() = default;
 | 
			
		||||
 | 
			
		||||
void Swapchain::Create(u32 width, u32 height, bool srgb) {
 | 
			
		||||
void Swapchain::Create(u32 width_, u32 height_, bool srgb) {
 | 
			
		||||
    is_outdated = false;
 | 
			
		||||
    is_suboptimal = false;
 | 
			
		||||
    width = width_;
 | 
			
		||||
    height = height_;
 | 
			
		||||
 | 
			
		||||
    const auto physical_device = device.GetPhysical();
 | 
			
		||||
    const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)};
 | 
			
		||||
@@ -88,7 +90,7 @@ void Swapchain::Create(u32 width, u32 height, bool srgb) {
 | 
			
		||||
    device.GetLogical().WaitIdle();
 | 
			
		||||
    Destroy();
 | 
			
		||||
 | 
			
		||||
    CreateSwapchain(capabilities, width, height, srgb);
 | 
			
		||||
    CreateSwapchain(capabilities, srgb);
 | 
			
		||||
    CreateSemaphores();
 | 
			
		||||
    CreateImageViews();
 | 
			
		||||
 | 
			
		||||
@@ -148,8 +150,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height,
 | 
			
		||||
                                bool srgb) {
 | 
			
		||||
void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) {
 | 
			
		||||
    const auto physical_device{device.GetPhysical()};
 | 
			
		||||
    const auto formats{physical_device.GetSurfaceFormatsKHR(surface)};
 | 
			
		||||
    const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)};
 | 
			
		||||
 
 | 
			
		||||
@@ -80,9 +80,16 @@ public:
 | 
			
		||||
        return *present_semaphores[frame_index];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    u32 GetWidth() const {
 | 
			
		||||
        return width;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    u32 GetHeight() const {
 | 
			
		||||
        return height;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height,
 | 
			
		||||
                         bool srgb);
 | 
			
		||||
    void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb);
 | 
			
		||||
    void CreateSemaphores();
 | 
			
		||||
    void CreateImageViews();
 | 
			
		||||
 | 
			
		||||
@@ -105,6 +112,9 @@ private:
 | 
			
		||||
    std::vector<u64> resource_ticks;
 | 
			
		||||
    std::vector<vk::Semaphore> present_semaphores;
 | 
			
		||||
 | 
			
		||||
    u32 width;
 | 
			
		||||
    u32 height;
 | 
			
		||||
 | 
			
		||||
    u32 image_index{};
 | 
			
		||||
    u32 frame_index{};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -61,8 +61,6 @@ void EmuThread::run() {
 | 
			
		||||
 | 
			
		||||
    // Main process has been loaded. Make the context current to this thread and begin GPU and CPU
 | 
			
		||||
    // execution.
 | 
			
		||||
    gpu.Start();
 | 
			
		||||
 | 
			
		||||
    gpu.ObtainContext();
 | 
			
		||||
 | 
			
		||||
    emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
 | 
			
		||||
@@ -77,6 +75,7 @@ void EmuThread::run() {
 | 
			
		||||
    emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
 | 
			
		||||
 | 
			
		||||
    gpu.ReleaseContext();
 | 
			
		||||
    gpu.Start();
 | 
			
		||||
 | 
			
		||||
    system.GetCpuManager().OnGpuReady();
 | 
			
		||||
 | 
			
		||||
@@ -224,6 +223,7 @@ class RenderWidget : public QWidget {
 | 
			
		||||
public:
 | 
			
		||||
    explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) {
 | 
			
		||||
        setAttribute(Qt::WA_NativeWindow);
 | 
			
		||||
        setAttribute(Qt::WA_DontCreateNativeAncestors);
 | 
			
		||||
        setAttribute(Qt::WA_PaintOnScreen);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -314,6 +314,8 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
 | 
			
		||||
    input_subsystem->Initialize();
 | 
			
		||||
    this->setMouseTracking(true);
 | 
			
		||||
 | 
			
		||||
    strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland");
 | 
			
		||||
 | 
			
		||||
    connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
 | 
			
		||||
    connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram,
 | 
			
		||||
            Qt::QueuedConnection);
 | 
			
		||||
@@ -952,6 +954,12 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> 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);
 | 
			
		||||
 
 | 
			
		||||
@@ -2915,9 +2915,14 @@ static QScreen* GuessCurrentScreen(QWidget* window) {
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GMainWindow::UsingExclusiveFullscreen() {
 | 
			
		||||
    return Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive ||
 | 
			
		||||
           QGuiApplication::platformName() == QStringLiteral("wayland");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::ShowFullscreen() {
 | 
			
		||||
    const auto show_fullscreen = [](QWidget* window) {
 | 
			
		||||
        if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
 | 
			
		||||
    const auto show_fullscreen = [this](QWidget* window) {
 | 
			
		||||
        if (UsingExclusiveFullscreen()) {
 | 
			
		||||
            window->showFullScreen();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -2945,7 +2950,7 @@ void GMainWindow::ShowFullscreen() {
 | 
			
		||||
 | 
			
		||||
void GMainWindow::HideFullscreen() {
 | 
			
		||||
    if (ui->action_Single_Window_Mode->isChecked()) {
 | 
			
		||||
        if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
 | 
			
		||||
        if (UsingExclusiveFullscreen()) {
 | 
			
		||||
            showNormal();
 | 
			
		||||
            restoreGeometry(UISettings::values.geometry);
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -2959,7 +2964,7 @@ void GMainWindow::HideFullscreen() {
 | 
			
		||||
        statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
 | 
			
		||||
        ui->menubar->show();
 | 
			
		||||
    } else {
 | 
			
		||||
        if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
 | 
			
		||||
        if (UsingExclusiveFullscreen()) {
 | 
			
		||||
            render_window->showNormal();
 | 
			
		||||
            render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
 | 
			
		||||
        } else {
 | 
			
		||||
 
 | 
			
		||||
@@ -320,6 +320,7 @@ private slots:
 | 
			
		||||
    void OnDisplayTitleBars(bool);
 | 
			
		||||
    void InitializeHotkeys();
 | 
			
		||||
    void ToggleFullscreen();
 | 
			
		||||
    bool UsingExclusiveFullscreen();
 | 
			
		||||
    void ShowFullscreen();
 | 
			
		||||
    void HideFullscreen();
 | 
			
		||||
    void ToggleWindowMode();
 | 
			
		||||
 
 | 
			
		||||
@@ -115,7 +115,7 @@ bool EmuWindow_SDL2::IsShown() const {
 | 
			
		||||
 | 
			
		||||
void EmuWindow_SDL2::OnResize() {
 | 
			
		||||
    int width, height;
 | 
			
		||||
    SDL_GetWindowSize(render_window, &width, &height);
 | 
			
		||||
    SDL_GL_GetDrawableSize(render_window, &width, &height);
 | 
			
		||||
    UpdateCurrentFramebufferLayout(width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -104,6 +104,8 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    strict_context_required = strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0;
 | 
			
		||||
 | 
			
		||||
    SetWindowIcon();
 | 
			
		||||
 | 
			
		||||
    if (fullscreen) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user