diff options
31 files changed, 184 insertions, 98 deletions
| diff --git a/externals/find-modules/FindOpus.cmake b/externals/find-modules/FindOpus.cmake index 2ba515352..25a44fd87 100644 --- a/externals/find-modules/FindOpus.cmake +++ b/externals/find-modules/FindOpus.cmake @@ -2,9 +2,7 @@  # SPDX-License-Identifier: GPL-2.0-or-later  find_package(PkgConfig QUIET) -if (PKG_CONFIG_FOUND) -    pkg_search_module(OPUS QUIET IMPORTED_TARGET opus) -endif() +pkg_search_module(OPUS QUIET IMPORTED_TARGET opus)  include(FindPackageHandleStandardArgs)  find_package_handle_standard_args(Opus diff --git a/externals/find-modules/Findenet.cmake b/externals/find-modules/Findenet.cmake index 6dae76f4c..859a6f386 100644 --- a/externals/find-modules/Findenet.cmake +++ b/externals/find-modules/Findenet.cmake @@ -3,9 +3,7 @@  # SPDX-License-Identifier: GPL-3.0-or-later  find_package(PkgConfig QUIET) -if (PKG_CONFIG_FOUND) -    pkg_search_module(ENET QUIET IMPORTED_TARGET libenet) -endif() +pkg_search_module(ENET QUIET IMPORTED_TARGET libenet)  include(FindPackageHandleStandardArgs)  find_package_handle_standard_args(enet diff --git a/externals/find-modules/Findhttplib.cmake b/externals/find-modules/Findhttplib.cmake index b72bad076..4d17cb393 100644 --- a/externals/find-modules/Findhttplib.cmake +++ b/externals/find-modules/Findhttplib.cmake @@ -9,9 +9,7 @@ if (httplib_FOUND)      find_package_handle_standard_args(httplib CONFIG_MODE)  else()      find_package(PkgConfig QUIET) -    if (PKG_CONFIG_FOUND) -        pkg_search_module(HTTPLIB QUIET IMPORTED_TARGET cpp-httplib) -    endif() +    pkg_search_module(HTTPLIB QUIET IMPORTED_TARGET cpp-httplib)      find_package_handle_standard_args(httplib          REQUIRED_VARS HTTPLIB_INCLUDEDIR          VERSION_VAR HTTPLIB_VERSION diff --git a/externals/find-modules/Findinih.cmake b/externals/find-modules/Findinih.cmake index 8d1a07243..b8d38dcff 100644 --- a/externals/find-modules/Findinih.cmake +++ b/externals/find-modules/Findinih.cmake @@ -3,9 +3,7 @@  # SPDX-License-Identifier: GPL-3.0-or-later  find_package(PkgConfig QUIET) -if (PKG_CONFIG_FOUND) -    pkg_search_module(INIREADER QUIET IMPORTED_TARGET INIReader) -endif() +pkg_search_module(INIREADER QUIET IMPORTED_TARGET INIReader)  include(FindPackageHandleStandardArgs)  find_package_handle_standard_args(inih diff --git a/externals/find-modules/Findlibusb.cmake b/externals/find-modules/Findlibusb.cmake index 66f61001c..0eadce957 100644 --- a/externals/find-modules/Findlibusb.cmake +++ b/externals/find-modules/Findlibusb.cmake @@ -3,9 +3,7 @@  # SPDX-License-Identifier: GPL-3.0-or-later  find_package(PkgConfig QUIET) -if (PKG_CONFIG_FOUND) -    pkg_search_module(LIBUSB QUIET IMPORTED_TARGET libusb-1.0) -endif() +pkg_search_module(LIBUSB QUIET IMPORTED_TARGET libusb-1.0)  include(FindPackageHandleStandardArgs)  find_package_handle_standard_args(libusb diff --git a/externals/find-modules/Findlz4.cmake b/externals/find-modules/Findlz4.cmake index f4c7005ba..c82405c59 100644 --- a/externals/find-modules/Findlz4.cmake +++ b/externals/find-modules/Findlz4.cmake @@ -8,9 +8,7 @@ if (lz4_FOUND)      find_package_handle_standard_args(lz4 CONFIG_MODE)  else()      find_package(PkgConfig QUIET) -    if (PKG_CONFIG_FOUND) -        pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4) -    endif() +    pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4)      find_package_handle_standard_args(lz4          REQUIRED_VARS LZ4_LINK_LIBRARIES          VERSION_VAR LZ4_VERSION diff --git a/externals/find-modules/Findzstd.cmake b/externals/find-modules/Findzstd.cmake index 1aacc41d0..f6eb9643a 100644 --- a/externals/find-modules/Findzstd.cmake +++ b/externals/find-modules/Findzstd.cmake @@ -8,9 +8,7 @@ if (zstd_FOUND)      find_package_handle_standard_args(zstd CONFIG_MODE)  else()      find_package(PkgConfig QUIET) -    if (PKG_CONFIG_FOUND) -        pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd) -    endif() +    pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd)      find_package_handle_standard_args(zstd          REQUIRED_VARS ZSTD_LINK_LIBRARIES          VERSION_VAR ZSTD_VERSION diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 95363b645..cf85ba29e 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -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. diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index 26dec7147..053e8f9dd 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp @@ -203,8 +203,9 @@ private:  };  AudInU::AudInU(Core::System& system_) -    : ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"}, -      impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} { +    : ServiceFramework{system_, "audin:u", ServiceThreadType::CreateNew}, +      service_context{system_, "AudInU"}, impl{std::make_unique<AudioCore::AudioIn::Manager>( +                                              system_)} {      // clang-format off      static const FunctionInfo functions[] = {          {0, &AudInU::ListAudioIns, "ListAudioIns"}, diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 991e30ba1..29751f075 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -26,8 +26,9 @@ public:      explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,                         size_t session_id, const std::string& device_name,                         const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id) -        : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, -          event{service_context.CreateEvent("AudioOutEvent")}, +        : ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew}, +          service_context{system_, "IAudioOut"}, event{service_context.CreateEvent( +                                                     "AudioOutEvent")},            impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {          // clang-format off @@ -220,8 +221,9 @@ private:  };  AudOutU::AudOutU(Core::System& system_) -    : ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"}, -      impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} { +    : ServiceFramework{system_, "audout:u", ServiceThreadType::CreateNew}, +      service_context{system_, "AudOutU"}, impl{std::make_unique<AudioCore::AudioOut::Manager>( +                                               system_)} {      // clang-format off      static const FunctionInfo functions[] = {          {0, &AudOutU::ListAudioOuts, "ListAudioOuts"}, diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index ead16c321..3a1c231b6 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -35,9 +35,10 @@ public:                              AudioCore::AudioRendererParameterInternal& params,                              Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,                              u32 process_handle, u64 applet_resource_user_id, s32 session_id) -        : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"}, -          rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_}, -          impl{std::make_unique<Renderer>(system_, manager, rendered_event)} { +        : ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew}, +          service_context{system_, "IAudioRenderer"}, rendered_event{service_context.CreateEvent( +                                                          "IAudioRendererEvent")}, +          manager{manager_}, impl{std::make_unique<Renderer>(system_, manager, rendered_event)} {          // clang-format off          static const FunctionInfo functions[] = {              {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, @@ -242,8 +243,10 @@ class IAudioDevice final : public ServiceFramework<IAudioDevice> {  public:      explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,                            u32 device_num) -        : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"}, -          impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)}, +        : ServiceFramework{system_, "IAudioDevice", ServiceThreadType::CreateNew}, +          service_context{system_, "IAudioDevice"}, impl{std::make_unique<AudioDevice>( +                                                        system_, applet_resource_user_id, +                                                        revision)},            event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {          static const FunctionInfo functions[] = {              {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, @@ -418,7 +421,7 @@ private:  };  AudRenU::AudRenU(Core::System& system_) -    : ServiceFramework{system_, "audren:u"}, +    : ServiceFramework{system_, "audren:u", ServiceThreadType::CreateNew},        service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {      // clang-format off      static const FunctionInfo functions[] = { diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 8e3e40cd5..41dc6d031 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -1345,8 +1345,10 @@ void EmitContext::DefineInputs(const IR::Program& program) {      if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||          (profile.warp_size_potentially_larger_than_guest &&           (info.uses_subgroup_vote || info.uses_subgroup_mask))) { +        AddCapability(spv::Capability::GroupNonUniform);          subgroup_local_invocation_id =              DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId); +        Decorate(subgroup_local_invocation_id, spv::Decoration::Flat);      }      if (info.uses_fswzadd) {          const Id f32_one{Const(1.0f)}; diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 28b38273e..c6d54be63 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -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();      } diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index e2e3dac34..cee5c3247 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -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); diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index 5ef51ebcf..2a72d84be 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -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;  }; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index a59d0d24e..fff55d585 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -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(); diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 53ffea904..f82420592 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -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{}; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 5b5e178ad..bc75680f0 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -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); diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 18be54729..f502a7d09 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -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) { diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 558b8db56..84d36fea6 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -285,6 +285,9 @@ void BufferCacheRuntime::BindQuadArrayIndexBuffer(u32 first, u32 count) {  void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size,                                            u32 stride) { +    if (index >= device.GetMaxVertexInputBindings()) { +        return; +    }      if (device.IsExtExtendedDynamicStateSupported()) {          scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {              const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 006128638..4b10fe7bc 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -529,7 +529,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {      static_vector<VkVertexInputBindingDivisorDescriptionEXT, 32> vertex_binding_divisors;      static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes;      if (key.state.dynamic_vertex_input) { -        for (size_t index = 0; index < key.state.attributes.size(); ++index) { +        const size_t num_vertex_arrays = std::min( +            key.state.attributes.size(), static_cast<size_t>(device.GetMaxVertexInputBindings())); +        for (size_t index = 0; index < num_vertex_arrays; ++index) {              const u32 type = key.state.DynamicAttributeType(index);              if (!stage_infos[0].loads.Generic(index) || type == 0) {                  continue; @@ -551,7 +553,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {              });          }      } else { -        for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { +        const size_t num_vertex_arrays = std::min( +            Maxwell::NumVertexArrays, static_cast<size_t>(device.GetMaxVertexInputBindings())); +        for (size_t index = 0; index < num_vertex_arrays; ++index) {              const bool instanced = key.state.binding_divisors[index] != 0;              const auto rate =                  instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; @@ -580,6 +584,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {              });          }      } +    ASSERT(vertex_attributes.size() <= device.GetMaxVertexInputAttributes()); +      VkPipelineVertexInputStateCreateInfo vertex_input_ci{          .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,          .pNext = nullptr, diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 81f5f3e11..86fdde014 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -341,6 +341,15 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device          .support_snorm_render_buffer = true,          .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(),      }; + +    if (device.GetMaxVertexInputAttributes() < Maxwell::NumVertexAttributes) { +        LOG_WARNING(Render_Vulkan, "maxVertexInputAttributes is too low: {} < {}", +                    device.GetMaxVertexInputAttributes(), Maxwell::NumVertexAttributes); +    } +    if (device.GetMaxVertexInputBindings() < Maxwell::NumVertexArrays) { +        LOG_WARNING(Render_Vulkan, "maxVertexInputBindings is too low: {} < {}", +                    device.GetMaxVertexInputBindings(), Maxwell::NumVertexArrays); +    }  }  PipelineCache::~PipelineCache() = default; diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index d7be417f5..b6810eef9 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -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)}; diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index 111b3902d..caf1ff32b 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h @@ -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{}; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 6a2ad4b1d..f45030311 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -421,7 +421,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR      VkPhysicalDevice8BitStorageFeatures bit8_storage{          .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES,          .pNext = nullptr, -        .storageBuffer8BitAccess = false, +        .storageBuffer8BitAccess = true,          .uniformAndStorageBuffer8BitAccess = true,          .storagePushConstant8 = false,      }; @@ -1044,6 +1044,7 @@ void Device::CheckSuitability(bool requires_swapchain) const {          std::make_pair(bit16_storage.storageBuffer16BitAccess, "storageBuffer16BitAccess"),          std::make_pair(bit16_storage.uniformAndStorageBuffer16BitAccess,                         "uniformAndStorageBuffer16BitAccess"), +        std::make_pair(bit8_storage.storageBuffer8BitAccess, "storageBuffer8BitAccess"),          std::make_pair(bit8_storage.uniformAndStorageBuffer8BitAccess,                         "uniformAndStorageBuffer8BitAccess"),          std::make_pair(host_query_reset.hostQueryReset, "hostQueryReset"), @@ -1380,6 +1381,10 @@ void Device::SetupFeatures() {      is_shader_storage_image_multisample = features.shaderStorageImageMultisample;      is_blit_depth_stencil_supported = TestDepthStencilBlits();      is_optimal_astc_supported = IsOptimalAstcSupported(features); + +    const VkPhysicalDeviceLimits& limits{properties.limits}; +    max_vertex_input_attributes = limits.maxVertexInputAttributes; +    max_vertex_input_bindings = limits.maxVertexInputBindings;  }  void Device::SetupProperties() { diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index db802437c..391b7604c 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -368,6 +368,14 @@ public:          return must_emulate_bgr565;      } +    u32 GetMaxVertexInputAttributes() const { +        return max_vertex_input_attributes; +    } + +    u32 GetMaxVertexInputBindings() const { +        return max_vertex_input_bindings; +    } +  private:      /// Checks if the physical device is suitable.      void CheckSuitability(bool requires_swapchain) const; @@ -467,6 +475,8 @@ private:      bool supports_d24_depth{};              ///< Supports D24 depth buffers.      bool cant_blit_msaa{};                  ///< Does not support MSAA<->MSAA blitting.      bool must_emulate_bgr565{};             ///< Emulates BGR565 by swizzling RGB565 format. +    u32 max_vertex_input_attributes{};      ///< Max vertex input attributes in pipeline +    u32 max_vertex_input_bindings{};        ///< Max vertex input buffers in pipeline      // Telemetry parameters      std::string vendor_name;                       ///< Device's driver name. diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 5b5b6fed8..1a47fb9c9 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -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); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d9e8b751b..df7166d4b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3064,9 +3064,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;          } @@ -3094,7 +3099,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 { @@ -3108,7 +3113,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 { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index a0f7aa77d..1047ba276 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -323,6 +323,7 @@ private slots:      void OnDisplayTitleBars(bool);      void InitializeHotkeys();      void ToggleFullscreen(); +    bool UsingExclusiveFullscreen();      void ShowFullscreen();      void HideFullscreen();      void ToggleWindowMode(); diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 37dd1747c..31f28a507 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -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);  } diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp index 9b660c13c..ddcb048d6 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp @@ -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) { | 
