diff options
-rw-r--r-- | CMakeLists.txt | 10 | ||||
-rw-r--r-- | CMakeModules/CopyYuzuQt5Deps.cmake | 1 | ||||
-rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/core/core.cpp | 13 | ||||
-rw-r--r-- | src/core/core.h | 12 | ||||
-rw-r--r-- | src/core/hle/kernel/k_process.cpp | 54 | ||||
-rw-r--r-- | src/core/hle/kernel/k_process.h | 4 | ||||
-rw-r--r-- | src/core/hle/kernel/k_shared_memory_info.h | 46 | ||||
-rw-r--r-- | src/core/hle/kernel/kernel.h | 4 | ||||
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 14 | ||||
-rw-r--r-- | src/core/hle/service/am/am.cpp | 4 | ||||
-rw-r--r-- | src/core/memory.cpp | 6 | ||||
-rw-r--r-- | src/core/network/network.cpp | 2 | ||||
-rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 18 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 11 | ||||
-rw-r--r-- | src/yuzu/bootmanager.cpp | 5 | ||||
-rw-r--r-- | src/yuzu/bootmanager.h | 4 | ||||
-rw-r--r-- | src/yuzu/main.cpp | 16 | ||||
-rw-r--r-- | src/yuzu/main.h | 1 |
19 files changed, 202 insertions, 24 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index bd0f6b978..123a3082a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,7 +237,7 @@ yuzu_find_packages() # Qt5 requires that we find components, so it doesn't fit our pretty little find package function if(ENABLE_QT) - set(QT_VERSION 5.12) + set(QT_VERSION 5.15) # We want to load the generated conan qt config so that we get the QT_ROOT var so that we can use the official # Qt5Config inside the root folder instead of the conan generated one. if(EXISTS ${CMAKE_BINARY_DIR}/qtConfig.cmake) @@ -339,8 +339,8 @@ if(ENABLE_QT) set(QT_PREFIX_HINT) if(YUZU_USE_BUNDLED_QT) - if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64) - set(QT_BUILD qt-5.12.8-msvc2017_64) + if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) + set(QT_BUILD qt-5.15.2-msvc2019_64) elseif ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND NOT MINGW AND ARCHITECTURE_x86_64) set(QT_BUILD qt5_5_15_2) else() @@ -369,7 +369,7 @@ endif() if (ENABLE_SDL2) if (YUZU_USE_BUNDLED_SDL2) # Detect toolchain and platform - if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64) + if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) set(SDL2_VER "SDL2-2.0.16") else() message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") @@ -462,7 +462,7 @@ if (CONAN_REQUIRED_LIBS) if(ENABLE_QT) list(APPEND CMAKE_MODULE_PATH "${CONAN_QT_ROOT_RELEASE}") list(APPEND CMAKE_PREFIX_PATH "${CONAN_QT_ROOT_RELEASE}") - find_package(Qt5 5.12 REQUIRED COMPONENTS Widgets) + find_package(Qt5 5.15 REQUIRED COMPONENTS Widgets) if (YUZU_USE_QT_WEB_ENGINE) find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets) endif() diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake index 4a6aeebbb..dd97f5b2b 100644 --- a/CMakeModules/CopyYuzuQt5Deps.cmake +++ b/CMakeModules/CopyYuzuQt5Deps.cmake @@ -33,6 +33,7 @@ function(copy_yuzu_Qt5_deps target_dir) Qt5Positioning$<$<CONFIG:Debug>:d>.* Qt5PrintSupport$<$<CONFIG:Debug>:d>.* Qt5Qml$<$<CONFIG:Debug>:d>.* + Qt5QmlModels$<$<CONFIG:Debug>:d>.* Qt5Quick$<$<CONFIG:Debug>:d>.* Qt5QuickWidgets$<$<CONFIG:Debug>:d>.* Qt5WebChannel$<$<CONFIG:Debug>:d>.* diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index aa3b26628..9f0fbba2d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -216,6 +216,7 @@ add_library(core STATIC hle/kernel/k_session.h hle/kernel/k_shared_memory.cpp hle/kernel/k_shared_memory.h + hle/kernel/k_shared_memory_info.h hle/kernel/k_slab_heap.h hle/kernel/k_spin_lock.cpp hle/kernel/k_spin_lock.h diff --git a/src/core/core.cpp b/src/core/core.cpp index 50d5dab4b..bb268a319 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -421,6 +421,7 @@ struct System::Impl { bool is_async_gpu{}; ExecuteProgramCallback execute_program_callback; + ExitCallback exit_callback; std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{}; @@ -798,6 +799,18 @@ void System::ExecuteProgram(std::size_t program_index) { } } +void System::RegisterExitCallback(ExitCallback&& callback) { + impl->exit_callback = std::move(callback); +} + +void System::Exit() { + if (impl->exit_callback) { + impl->exit_callback(); + } else { + LOG_CRITICAL(Core, "exit_callback must be initialized by the frontend"); + } +} + void System::ApplySettings() { if (IsPoweredOn()) { Renderer().RefreshBaseSettings(); diff --git a/src/core/core.h b/src/core/core.h index 715ab88e7..a796472b2 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -387,6 +387,18 @@ public: */ void ExecuteProgram(std::size_t program_index); + /// Type used for the frontend to designate a callback for System to exit the application. + using ExitCallback = std::function<void()>; + + /** + * Registers a callback from the frontend for System to exit the application. + * @param callback Callback from the frontend to exit the application. + */ + void RegisterExitCallback(ExitCallback&& callback); + + /// Instructs the frontend to exit the application. + void Exit(); + /// Applies any changes to settings to this core instance. void ApplySettings(); diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 8ead1a769..211157ccc 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -23,6 +23,7 @@ #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/k_shared_memory_info.h" #include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" @@ -254,10 +255,26 @@ ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAdd // Lock ourselves, to prevent concurrent access. KScopedLightLock lk(state_lock); - // TODO(bunnei): Manage KSharedMemoryInfo list here. + // Try to find an existing info for the memory. + KSharedMemoryInfo* shemen_info = nullptr; + const auto iter = std::find_if( + shared_memory_list.begin(), shared_memory_list.end(), + [shmem](const KSharedMemoryInfo* info) { return info->GetSharedMemory() == shmem; }); + if (iter != shared_memory_list.end()) { + shemen_info = *iter; + } + + if (shemen_info == nullptr) { + shemen_info = KSharedMemoryInfo::Allocate(kernel); + R_UNLESS(shemen_info != nullptr, ResultOutOfMemory); + + shemen_info->Initialize(shmem); + shared_memory_list.push_back(shemen_info); + } - // Open a reference to the shared memory. + // Open a reference to the shared memory and its info. shmem->Open(); + shemen_info->Open(); return ResultSuccess; } @@ -267,7 +284,20 @@ void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr a // Lock ourselves, to prevent concurrent access. KScopedLightLock lk(state_lock); - // TODO(bunnei): Manage KSharedMemoryInfo list here. + KSharedMemoryInfo* shemen_info = nullptr; + const auto iter = std::find_if( + shared_memory_list.begin(), shared_memory_list.end(), + [shmem](const KSharedMemoryInfo* info) { return info->GetSharedMemory() == shmem; }); + if (iter != shared_memory_list.end()) { + shemen_info = *iter; + } + + ASSERT(shemen_info != nullptr); + + if (shemen_info->Close()) { + shared_memory_list.erase(iter); + KSharedMemoryInfo::Free(kernel, shemen_info); + } // Close a reference to the shared memory. shmem->Close(); @@ -412,6 +442,24 @@ void KProcess::Finalize() { // Finalize the handle table and close any open handles. handle_table.Finalize(); + // Free all shared memory infos. + { + auto it = shared_memory_list.begin(); + while (it != shared_memory_list.end()) { + KSharedMemoryInfo* info = *it; + KSharedMemory* shmem = info->GetSharedMemory(); + + while (!info->Close()) { + shmem->Close(); + } + + shmem->Close(); + + it = shared_memory_list.erase(it); + KSharedMemoryInfo::Free(kernel, info); + } + } + // Perform inherited finalization. KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize(); } diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index a03c074fb..1a53e2be7 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -34,6 +34,7 @@ class KernelCore; class KPageTable; class KResourceLimit; class KThread; +class KSharedMemoryInfo; class TLSPage; struct CodeSet; @@ -448,6 +449,9 @@ private: /// List of threads that are running with this process as their owner. std::list<const KThread*> thread_list; + /// List of shared memory that are running with this process as their owner. + std::list<KSharedMemoryInfo*> shared_memory_list; + /// Address of the top of the main thread's stack VAddr main_thread_stack_top{}; diff --git a/src/core/hle/kernel/k_shared_memory_info.h b/src/core/hle/kernel/k_shared_memory_info.h new file mode 100644 index 000000000..bf97a0184 --- /dev/null +++ b/src/core/hle/kernel/k_shared_memory_info.h @@ -0,0 +1,46 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <string> + +#include <boost/intrusive/list.hpp> + +#include "common/assert.h" +#include "core/hle/kernel/slab_helpers.h" + +namespace Kernel { + +class KSharedMemory; + +class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>, + public boost::intrusive::list_base_hook<> { + +public: + explicit KSharedMemoryInfo() = default; + + constexpr void Initialize(KSharedMemory* shmem) { + shared_memory = shmem; + } + + constexpr KSharedMemory* GetSharedMemory() const { + return shared_memory; + } + + constexpr void Open() { + ++reference_count; + } + + constexpr bool Close() { + return (--reference_count) == 0; + } + +private: + KSharedMemory* shared_memory{}; + size_t reference_count{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 901d43da9..b6658b437 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -49,6 +49,7 @@ class KScheduler; class KServerSession; class KSession; class KSharedMemory; +class KSharedMemoryInfo; class KThread; class KTransferMemory; class KWritableEvent; @@ -309,6 +310,8 @@ public: return slab_heap_container->session; } else if constexpr (std::is_same_v<T, KSharedMemory>) { return slab_heap_container->shared_memory; + } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) { + return slab_heap_container->shared_memory_info; } else if constexpr (std::is_same_v<T, KThread>) { return slab_heap_container->thread; } else if constexpr (std::is_same_v<T, KTransferMemory>) { @@ -362,6 +365,7 @@ private: KSlabHeap<KResourceLimit> resource_limit; KSlabHeap<KSession> session; KSlabHeap<KSharedMemory> shared_memory; + KSlabHeap<KSharedMemoryInfo> shared_memory_info; KSlabHeap<KThread> thread; KSlabHeap<KTransferMemory> transfer_memory; KSlabHeap<KWritableEvent> writeable_event; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 62fb06c45..f98f24a60 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -320,17 +320,19 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { auto& kernel = system.Kernel(); - KScopedAutoObject session = - kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); - R_UNLESS(session.IsNotNull(), ResultInvalidHandle); - LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); - auto thread = kernel.CurrentScheduler()->GetCurrentThread(); { KScopedSchedulerLock lock(kernel); thread->SetState(ThreadState::Waiting); thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); - session->SendSyncRequest(thread, system.Memory(), system.CoreTiming()); + + { + KScopedAutoObject session = + kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); + R_UNLESS(session.IsNotNull(), ResultInvalidHandle); + LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); + session->SendSyncRequest(thread, system.Memory(), system.CoreTiming()); + } } KSynchronizationObject* dummy{}; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 02de585e4..eccdcc20d 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -331,10 +331,10 @@ ISelfController::~ISelfController() { void ISelfController::Exit(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - system.Shutdown(); - IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); + + system.Exit(); } void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 51c4dea26..88d6ec908 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -587,7 +587,11 @@ void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { bool Memory::IsValidVirtualAddress(const VAddr vaddr) const { const Kernel::KProcess& process = *system.CurrentProcess(); const auto& page_table = process.PageTable().PageTableImpl(); - const auto [pointer, type] = page_table.pointers[vaddr >> PAGE_BITS].PointerType(); + const size_t page = vaddr >> PAGE_BITS; + if (page >= page_table.pointers.size()) { + return false; + } + const auto [pointer, type] = page_table.pointers[page].PointerType(); return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory; } diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 72eea52f0..a3e0664b9 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp @@ -366,8 +366,6 @@ std::optional<IPv4Address> GetHostIPv4Address() { if (res != network_interfaces.end()) { char ip_addr[16] = {}; ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr); - LOG_INFO(Network, "IP address: {}", ip_addr); - return TranslateIPv4(res->ip_address); } else { LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface); diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 03888b7cb..ab6211b29 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp @@ -254,11 +254,25 @@ public: } bool IsJoyconLeft() const { - return std::strstr(GetControllerName().c_str(), "Joy-Con Left") != nullptr; + const std::string controller_name = GetControllerName(); + if (std::strstr(controller_name.c_str(), "Joy-Con Left") != nullptr) { + return true; + } + if (std::strstr(controller_name.c_str(), "Joy-Con (L)") != nullptr) { + return true; + } + return false; } bool IsJoyconRight() const { - return std::strstr(GetControllerName().c_str(), "Joy-Con Right") != nullptr; + const std::string controller_name = GetControllerName(); + if (std::strstr(controller_name.c_str(), "Joy-Con Right") != nullptr) { + return true; + } + if (std::strstr(controller_name.c_str(), "Joy-Con (R)") != nullptr) { + return true; + } + return false; } std::string GetControllerName() const { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 11cd41ad7..8634c3316 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -568,12 +568,21 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { if (!vertex_binding_divisors.empty()) { vertex_input_ci.pNext = &input_divisor_ci; } + const bool has_tess_stages = spv_modules[1] || spv_modules[2]; auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, key.state.topology); if (input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) { - if (!spv_modules[1] && !spv_modules[2]) { + if (!has_tess_stages) { LOG_WARNING(Render_Vulkan, "Patch topology used without tessellation, using points"); input_assembly_topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; } + } else { + if (has_tess_stages) { + // The Vulkan spec requires patch list IA topology be used with tessellation + // shader stages. Forcing it fixes a crash on some drivers + LOG_WARNING(Render_Vulkan, + "Patch topology not used with tessellation, using patch list"); + input_assembly_topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; + } } const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 1519a46ed..8b9e186b0 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -302,12 +302,17 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, Qt::QueuedConnection); + connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection); } void GRenderWindow::ExecuteProgram(std::size_t program_index) { emit ExecuteProgramSignal(program_index); } +void GRenderWindow::Exit() { + emit ExitSignal(); +} + GRenderWindow::~GRenderWindow() { input_subsystem->Shutdown(); } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 402dd2ee1..54c4e2142 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -181,6 +181,9 @@ public: */ void ExecuteProgram(std::size_t program_index); + /// Instructs the window to exit the application. + void Exit(); + public slots: void OnEmulationStarting(EmuThread* emu_thread); void OnEmulationStopping(); @@ -191,6 +194,7 @@ signals: void Closed(); void FirstFrameDisplayed(); void ExecuteProgramSignal(std::size_t program_index); + void ExitSignal(); void MouseActivity(); private: diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 3c2824362..552c2cc63 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1384,6 +1384,9 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t system.RegisterExecuteProgramCallback( [this](std::size_t program_index) { render_window->ExecuteProgram(program_index); }); + // Register an Exit callback such that Core can exit the currently running application. + system.RegisterExitCallback([this]() { render_window->Exit(); }); + connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity); // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views @@ -2469,6 +2472,10 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) { BootGame(last_filename_booted, 0, program_index); } +void GMainWindow::OnExit() { + OnStopGame(); +} + void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { OverlayDialog dialog(render_window, Core::System::GetInstance(), error_code, error_text, QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); @@ -2913,8 +2920,13 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie if (title_name.empty()) { setWindowTitle(QString::fromStdString(window_title)); } else { - const auto run_title = - fmt::format("{} | {} | {} | {}", window_title, title_name, title_version, gpu_vendor); + const auto run_title = [window_title, title_name, title_version, gpu_vendor]() { + if (title_version.empty()) { + return fmt::format("{} | {} | {}", window_title, title_name, gpu_vendor); + } + return fmt::format("{} | {} | {} | {}", window_title, title_name, title_version, + gpu_vendor); + }(); setWindowTitle(QString::fromStdString(run_title)); } } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 36eed6103..60ce01471 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -153,6 +153,7 @@ signals: public slots: void OnLoadComplete(); void OnExecuteProgram(std::size_t program_index); + void OnExit(); void ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters); void SoftwareKeyboardInitialize( |