diff options
Diffstat (limited to 'src')
49 files changed, 569 insertions, 193 deletions
diff --git a/src/audio_core/device/audio_buffers.h b/src/audio_core/device/audio_buffers.h index 3dae1a3b7..15082f6c6 100644 --- a/src/audio_core/device/audio_buffers.h +++ b/src/audio_core/device/audio_buffers.h | |||
| @@ -91,9 +91,10 @@ public: | |||
| 91 | * @param core_timing - The CoreTiming instance | 91 | * @param core_timing - The CoreTiming instance |
| 92 | * @param session - The device session | 92 | * @param session - The device session |
| 93 | * | 93 | * |
| 94 | * @return Is the buffer was released. | 94 | * @return If any buffer was released. |
| 95 | */ | 95 | */ |
| 96 | bool ReleaseBuffers(const Core::Timing::CoreTiming& core_timing, const DeviceSession& session) { | 96 | bool ReleaseBuffers(const Core::Timing::CoreTiming& core_timing, const DeviceSession& session, |
| 97 | bool force) { | ||
| 97 | std::scoped_lock l{lock}; | 98 | std::scoped_lock l{lock}; |
| 98 | bool buffer_released{false}; | 99 | bool buffer_released{false}; |
| 99 | while (registered_count > 0) { | 100 | while (registered_count > 0) { |
| @@ -103,7 +104,8 @@ public: | |||
| 103 | } | 104 | } |
| 104 | 105 | ||
| 105 | // Check with the backend if this buffer can be released yet. | 106 | // Check with the backend if this buffer can be released yet. |
| 106 | if (!session.IsBufferConsumed(buffers[index])) { | 107 | // If we're shutting down, we don't care if it's been played or not. |
| 108 | if (!force && !session.IsBufferConsumed(buffers[index])) { | ||
| 107 | break; | 109 | break; |
| 108 | } | 110 | } |
| 109 | 111 | ||
diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp index 995060414..5a327a606 100644 --- a/src/audio_core/device/device_session.cpp +++ b/src/audio_core/device/device_session.cpp | |||
| @@ -73,6 +73,12 @@ void DeviceSession::Stop() { | |||
| 73 | } | 73 | } |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | void DeviceSession::ClearBuffers() { | ||
| 77 | if (stream) { | ||
| 78 | stream->ClearQueue(); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 76 | void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const { | 82 | void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const { |
| 77 | for (const auto& buffer : buffers) { | 83 | for (const auto& buffer : buffers) { |
| 78 | Sink::SinkBuffer new_buffer{ | 84 | Sink::SinkBuffer new_buffer{ |
diff --git a/src/audio_core/device/device_session.h b/src/audio_core/device/device_session.h index 74f4dc085..75f766c68 100644 --- a/src/audio_core/device/device_session.h +++ b/src/audio_core/device/device_session.h | |||
| @@ -91,6 +91,11 @@ public: | |||
| 91 | void Stop(); | 91 | void Stop(); |
| 92 | 92 | ||
| 93 | /** | 93 | /** |
| 94 | * Clear out the underlying audio buffers in the backend stream. | ||
| 95 | */ | ||
| 96 | void ClearBuffers(); | ||
| 97 | |||
| 98 | /** | ||
| 94 | * Set this device session's volume. | 99 | * Set this device session's volume. |
| 95 | * | 100 | * |
| 96 | * @param volume - New volume for this session. | 101 | * @param volume - New volume for this session. |
diff --git a/src/audio_core/in/audio_in_system.cpp b/src/audio_core/in/audio_in_system.cpp index 4324cafd8..934ef8c1c 100644 --- a/src/audio_core/in/audio_in_system.cpp +++ b/src/audio_core/in/audio_in_system.cpp | |||
| @@ -23,7 +23,6 @@ System::~System() { | |||
| 23 | void System::Finalize() { | 23 | void System::Finalize() { |
| 24 | Stop(); | 24 | Stop(); |
| 25 | session->Finalize(); | 25 | session->Finalize(); |
| 26 | buffer_event->Signal(); | ||
| 27 | } | 26 | } |
| 28 | 27 | ||
| 29 | void System::StartSession() { | 28 | void System::StartSession() { |
| @@ -102,6 +101,10 @@ Result System::Stop() { | |||
| 102 | if (state == State::Started) { | 101 | if (state == State::Started) { |
| 103 | session->Stop(); | 102 | session->Stop(); |
| 104 | session->SetVolume(0.0f); | 103 | session->SetVolume(0.0f); |
| 104 | session->ClearBuffers(); | ||
| 105 | if (buffers.ReleaseBuffers(system.CoreTiming(), *session, true)) { | ||
| 106 | buffer_event->Signal(); | ||
| 107 | } | ||
| 105 | state = State::Stopped; | 108 | state = State::Stopped; |
| 106 | } | 109 | } |
| 107 | 110 | ||
| @@ -138,7 +141,7 @@ void System::RegisterBuffers() { | |||
| 138 | } | 141 | } |
| 139 | 142 | ||
| 140 | void System::ReleaseBuffers() { | 143 | void System::ReleaseBuffers() { |
| 141 | bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session)}; | 144 | bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session, false)}; |
| 142 | 145 | ||
| 143 | if (signal) { | 146 | if (signal) { |
| 144 | // Signal if any buffer was released, or if none are registered, we need more. | 147 | // Signal if any buffer was released, or if none are registered, we need more. |
diff --git a/src/audio_core/out/audio_out_system.cpp b/src/audio_core/out/audio_out_system.cpp index a66208ed9..e096a1dac 100644 --- a/src/audio_core/out/audio_out_system.cpp +++ b/src/audio_core/out/audio_out_system.cpp | |||
| @@ -24,7 +24,6 @@ System::~System() { | |||
| 24 | void System::Finalize() { | 24 | void System::Finalize() { |
| 25 | Stop(); | 25 | Stop(); |
| 26 | session->Finalize(); | 26 | session->Finalize(); |
| 27 | buffer_event->Signal(); | ||
| 28 | } | 27 | } |
| 29 | 28 | ||
| 30 | std::string_view System::GetDefaultOutputDeviceName() const { | 29 | std::string_view System::GetDefaultOutputDeviceName() const { |
| @@ -102,6 +101,10 @@ Result System::Stop() { | |||
| 102 | if (state == State::Started) { | 101 | if (state == State::Started) { |
| 103 | session->Stop(); | 102 | session->Stop(); |
| 104 | session->SetVolume(0.0f); | 103 | session->SetVolume(0.0f); |
| 104 | session->ClearBuffers(); | ||
| 105 | if (buffers.ReleaseBuffers(system.CoreTiming(), *session, true)) { | ||
| 106 | buffer_event->Signal(); | ||
| 107 | } | ||
| 105 | state = State::Stopped; | 108 | state = State::Stopped; |
| 106 | } | 109 | } |
| 107 | 110 | ||
| @@ -138,7 +141,7 @@ void System::RegisterBuffers() { | |||
| 138 | } | 141 | } |
| 139 | 142 | ||
| 140 | void System::ReleaseBuffers() { | 143 | void System::ReleaseBuffers() { |
| 141 | bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session)}; | 144 | bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session, false)}; |
| 142 | if (signal) { | 145 | if (signal) { |
| 143 | // Signal if any buffer was released, or if none are registered, we need more. | 146 | // Signal if any buffer was released, or if none are registered, we need more. |
| 144 | buffer_event->Signal(); | 147 | buffer_event->Signal(); |
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index d8ffe34c3..149e621f9 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp | |||
| @@ -40,6 +40,7 @@ void LogSettings() { | |||
| 40 | LOG_INFO(Config, "yuzu Configuration:"); | 40 | LOG_INFO(Config, "yuzu Configuration:"); |
| 41 | log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue()); | 41 | log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue()); |
| 42 | log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0)); | 42 | log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0)); |
| 43 | log_setting("System_DeviceName", values.device_name.GetValue()); | ||
| 43 | log_setting("System_CurrentUser", values.current_user.GetValue()); | 44 | log_setting("System_CurrentUser", values.current_user.GetValue()); |
| 44 | log_setting("System_LanguageIndex", values.language_index.GetValue()); | 45 | log_setting("System_LanguageIndex", values.language_index.GetValue()); |
| 45 | log_setting("System_RegionIndex", values.region_index.GetValue()); | 46 | log_setting("System_RegionIndex", values.region_index.GetValue()); |
diff --git a/src/common/settings.h b/src/common/settings.h index 7ce9ea23c..6b199af93 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -458,6 +458,7 @@ struct Values { | |||
| 458 | 458 | ||
| 459 | // System | 459 | // System |
| 460 | SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"}; | 460 | SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"}; |
| 461 | Setting<std::string> device_name{"Yuzu", "device_name"}; | ||
| 461 | // Measured in seconds since epoch | 462 | // Measured in seconds since epoch |
| 462 | std::optional<s64> custom_rtc; | 463 | std::optional<s64> custom_rtc; |
| 463 | // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` | 464 | // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` |
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: | |||
| 131 | return active_config; | 131 | return active_config; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | bool StrictContextRequired() const { | ||
| 135 | return strict_context_required; | ||
| 136 | } | ||
| 137 | |||
| 134 | /** | 138 | /** |
| 135 | * Requests the internal configuration to be replaced by the specified argument at some point in | 139 | * Requests the internal configuration to be replaced by the specified argument at some point in |
| 136 | * the future. | 140 | * the future. |
| @@ -207,6 +211,8 @@ protected: | |||
| 207 | 211 | ||
| 208 | WindowSystemInfo window_info; | 212 | WindowSystemInfo window_info; |
| 209 | 213 | ||
| 214 | bool strict_context_required = false; | ||
| 215 | |||
| 210 | private: | 216 | private: |
| 211 | /** | 217 | /** |
| 212 | * Handler called when the minimal client area was requested to be changed via SetConfig. | 218 | * Handler called when the minimal client area was requested to be changed via SetConfig. |
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 06010b8d1..738b6d0f1 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -167,6 +167,9 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 | |||
| 167 | } | 167 | } |
| 168 | if (incoming) { | 168 | if (incoming) { |
| 169 | // Populate the object lists with the data in the IPC request. | 169 | // Populate the object lists with the data in the IPC request. |
| 170 | incoming_copy_handles.reserve(handle_descriptor_header->num_handles_to_copy); | ||
| 171 | incoming_move_handles.reserve(handle_descriptor_header->num_handles_to_move); | ||
| 172 | |||
| 170 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { | 173 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { |
| 171 | incoming_copy_handles.push_back(rp.Pop<Handle>()); | 174 | incoming_copy_handles.push_back(rp.Pop<Handle>()); |
| 172 | } | 175 | } |
| @@ -181,6 +184,11 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 | |||
| 181 | } | 184 | } |
| 182 | } | 185 | } |
| 183 | 186 | ||
| 187 | buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors); | ||
| 188 | buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors); | ||
| 189 | buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors); | ||
| 190 | buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors); | ||
| 191 | |||
| 184 | for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { | 192 | for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { |
| 185 | buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); | 193 | buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); |
| 186 | } | 194 | } |
| @@ -318,25 +326,23 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa | |||
| 318 | } | 326 | } |
| 319 | 327 | ||
| 320 | std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { | 328 | std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { |
| 321 | std::vector<u8> buffer{}; | ||
| 322 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && | 329 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && |
| 323 | BufferDescriptorA()[buffer_index].Size()}; | 330 | BufferDescriptorA()[buffer_index].Size()}; |
| 324 | |||
| 325 | if (is_buffer_a) { | 331 | if (is_buffer_a) { |
| 326 | ASSERT_OR_EXECUTE_MSG( | 332 | ASSERT_OR_EXECUTE_MSG( |
| 327 | BufferDescriptorA().size() > buffer_index, { return buffer; }, | 333 | BufferDescriptorA().size() > buffer_index, { return {}; }, |
| 328 | "BufferDescriptorA invalid buffer_index {}", buffer_index); | 334 | "BufferDescriptorA invalid buffer_index {}", buffer_index); |
| 329 | buffer.resize(BufferDescriptorA()[buffer_index].Size()); | 335 | std::vector<u8> buffer(BufferDescriptorA()[buffer_index].Size()); |
| 330 | memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); | 336 | memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); |
| 337 | return buffer; | ||
| 331 | } else { | 338 | } else { |
| 332 | ASSERT_OR_EXECUTE_MSG( | 339 | ASSERT_OR_EXECUTE_MSG( |
| 333 | BufferDescriptorX().size() > buffer_index, { return buffer; }, | 340 | BufferDescriptorX().size() > buffer_index, { return {}; }, |
| 334 | "BufferDescriptorX invalid buffer_index {}", buffer_index); | 341 | "BufferDescriptorX invalid buffer_index {}", buffer_index); |
| 335 | buffer.resize(BufferDescriptorX()[buffer_index].Size()); | 342 | std::vector<u8> buffer(BufferDescriptorX()[buffer_index].Size()); |
| 336 | memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); | 343 | memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); |
| 344 | return buffer; | ||
| 337 | } | 345 | } |
| 338 | |||
| 339 | return buffer; | ||
| 340 | } | 346 | } |
| 341 | 347 | ||
| 342 | std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, | 348 | std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index d1dc62401..a1abf5d68 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -285,6 +285,17 @@ void KProcess::UnregisterThread(KThread* thread) { | |||
| 285 | thread_list.remove(thread); | 285 | thread_list.remove(thread); |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | u64 KProcess::GetFreeThreadCount() const { | ||
| 289 | if (resource_limit != nullptr) { | ||
| 290 | const auto current_value = | ||
| 291 | resource_limit->GetCurrentValue(LimitableResource::ThreadCountMax); | ||
| 292 | const auto limit_value = resource_limit->GetLimitValue(LimitableResource::ThreadCountMax); | ||
| 293 | return limit_value - current_value; | ||
| 294 | } else { | ||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 288 | Result KProcess::Reset() { | 299 | Result KProcess::Reset() { |
| 289 | // Lock the process and the scheduler. | 300 | // Lock the process and the scheduler. |
| 290 | KScopedLightLock lk(state_lock); | 301 | KScopedLightLock lk(state_lock); |
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 2e0cc3d0b..09bf2f1d0 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h | |||
| @@ -304,6 +304,9 @@ public: | |||
| 304 | /// from this process' thread list. | 304 | /// from this process' thread list. |
| 305 | void UnregisterThread(KThread* thread); | 305 | void UnregisterThread(KThread* thread); |
| 306 | 306 | ||
| 307 | /// Retrieves the number of available threads for this process. | ||
| 308 | u64 GetFreeThreadCount() const; | ||
| 309 | |||
| 307 | /// Clears the signaled state of the process if and only if it's signaled. | 310 | /// Clears the signaled state of the process if and only if it's signaled. |
| 308 | /// | 311 | /// |
| 309 | /// @pre The process must not be already terminated. If this is called on a | 312 | /// @pre The process must not be already terminated. If this is called on a |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index e520cab47..788ee2160 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -784,63 +784,29 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han | |||
| 784 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, | 784 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, |
| 785 | info_sub_id, handle); | 785 | info_sub_id, handle); |
| 786 | 786 | ||
| 787 | enum class GetInfoType : u64 { | 787 | const auto info_id_type = static_cast<InfoType>(info_id); |
| 788 | // 1.0.0+ | ||
| 789 | AllowedCPUCoreMask = 0, | ||
| 790 | AllowedThreadPriorityMask = 1, | ||
| 791 | MapRegionBaseAddr = 2, | ||
| 792 | MapRegionSize = 3, | ||
| 793 | HeapRegionBaseAddr = 4, | ||
| 794 | HeapRegionSize = 5, | ||
| 795 | TotalPhysicalMemoryAvailable = 6, | ||
| 796 | TotalPhysicalMemoryUsed = 7, | ||
| 797 | IsCurrentProcessBeingDebugged = 8, | ||
| 798 | RegisterResourceLimit = 9, | ||
| 799 | IdleTickCount = 10, | ||
| 800 | RandomEntropy = 11, | ||
| 801 | ThreadTickCount = 0xF0000002, | ||
| 802 | // 2.0.0+ | ||
| 803 | ASLRRegionBaseAddr = 12, | ||
| 804 | ASLRRegionSize = 13, | ||
| 805 | StackRegionBaseAddr = 14, | ||
| 806 | StackRegionSize = 15, | ||
| 807 | // 3.0.0+ | ||
| 808 | SystemResourceSize = 16, | ||
| 809 | SystemResourceUsage = 17, | ||
| 810 | TitleId = 18, | ||
| 811 | // 4.0.0+ | ||
| 812 | PrivilegedProcessId = 19, | ||
| 813 | // 5.0.0+ | ||
| 814 | UserExceptionContextAddr = 20, | ||
| 815 | // 6.0.0+ | ||
| 816 | TotalPhysicalMemoryAvailableWithoutSystemResource = 21, | ||
| 817 | TotalPhysicalMemoryUsedWithoutSystemResource = 22, | ||
| 818 | |||
| 819 | // Homebrew only | ||
| 820 | MesosphereCurrentProcess = 65001, | ||
| 821 | }; | ||
| 822 | |||
| 823 | const auto info_id_type = static_cast<GetInfoType>(info_id); | ||
| 824 | 788 | ||
| 825 | switch (info_id_type) { | 789 | switch (info_id_type) { |
| 826 | case GetInfoType::AllowedCPUCoreMask: | 790 | case InfoType::CoreMask: |
| 827 | case GetInfoType::AllowedThreadPriorityMask: | 791 | case InfoType::PriorityMask: |
| 828 | case GetInfoType::MapRegionBaseAddr: | 792 | case InfoType::AliasRegionAddress: |
| 829 | case GetInfoType::MapRegionSize: | 793 | case InfoType::AliasRegionSize: |
| 830 | case GetInfoType::HeapRegionBaseAddr: | 794 | case InfoType::HeapRegionAddress: |
| 831 | case GetInfoType::HeapRegionSize: | 795 | case InfoType::HeapRegionSize: |
| 832 | case GetInfoType::ASLRRegionBaseAddr: | 796 | case InfoType::AslrRegionAddress: |
| 833 | case GetInfoType::ASLRRegionSize: | 797 | case InfoType::AslrRegionSize: |
| 834 | case GetInfoType::StackRegionBaseAddr: | 798 | case InfoType::StackRegionAddress: |
| 835 | case GetInfoType::StackRegionSize: | 799 | case InfoType::StackRegionSize: |
| 836 | case GetInfoType::TotalPhysicalMemoryAvailable: | 800 | case InfoType::TotalMemorySize: |
| 837 | case GetInfoType::TotalPhysicalMemoryUsed: | 801 | case InfoType::UsedMemorySize: |
| 838 | case GetInfoType::SystemResourceSize: | 802 | case InfoType::SystemResourceSizeTotal: |
| 839 | case GetInfoType::SystemResourceUsage: | 803 | case InfoType::SystemResourceSizeUsed: |
| 840 | case GetInfoType::TitleId: | 804 | case InfoType::ProgramId: |
| 841 | case GetInfoType::UserExceptionContextAddr: | 805 | case InfoType::UserExceptionContextAddress: |
| 842 | case GetInfoType::TotalPhysicalMemoryAvailableWithoutSystemResource: | 806 | case InfoType::TotalNonSystemMemorySize: |
| 843 | case GetInfoType::TotalPhysicalMemoryUsedWithoutSystemResource: { | 807 | case InfoType::UsedNonSystemMemorySize: |
| 808 | case InfoType::IsApplication: | ||
| 809 | case InfoType::FreeThreadCount: { | ||
| 844 | if (info_sub_id != 0) { | 810 | if (info_sub_id != 0) { |
| 845 | LOG_ERROR(Kernel_SVC, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id, | 811 | LOG_ERROR(Kernel_SVC, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id, |
| 846 | info_sub_id); | 812 | info_sub_id); |
| @@ -856,79 +822,83 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han | |||
| 856 | } | 822 | } |
| 857 | 823 | ||
| 858 | switch (info_id_type) { | 824 | switch (info_id_type) { |
| 859 | case GetInfoType::AllowedCPUCoreMask: | 825 | case InfoType::CoreMask: |
| 860 | *result = process->GetCoreMask(); | 826 | *result = process->GetCoreMask(); |
| 861 | return ResultSuccess; | 827 | return ResultSuccess; |
| 862 | 828 | ||
| 863 | case GetInfoType::AllowedThreadPriorityMask: | 829 | case InfoType::PriorityMask: |
| 864 | *result = process->GetPriorityMask(); | 830 | *result = process->GetPriorityMask(); |
| 865 | return ResultSuccess; | 831 | return ResultSuccess; |
| 866 | 832 | ||
| 867 | case GetInfoType::MapRegionBaseAddr: | 833 | case InfoType::AliasRegionAddress: |
| 868 | *result = process->PageTable().GetAliasRegionStart(); | 834 | *result = process->PageTable().GetAliasRegionStart(); |
| 869 | return ResultSuccess; | 835 | return ResultSuccess; |
| 870 | 836 | ||
| 871 | case GetInfoType::MapRegionSize: | 837 | case InfoType::AliasRegionSize: |
| 872 | *result = process->PageTable().GetAliasRegionSize(); | 838 | *result = process->PageTable().GetAliasRegionSize(); |
| 873 | return ResultSuccess; | 839 | return ResultSuccess; |
| 874 | 840 | ||
| 875 | case GetInfoType::HeapRegionBaseAddr: | 841 | case InfoType::HeapRegionAddress: |
| 876 | *result = process->PageTable().GetHeapRegionStart(); | 842 | *result = process->PageTable().GetHeapRegionStart(); |
| 877 | return ResultSuccess; | 843 | return ResultSuccess; |
| 878 | 844 | ||
| 879 | case GetInfoType::HeapRegionSize: | 845 | case InfoType::HeapRegionSize: |
| 880 | *result = process->PageTable().GetHeapRegionSize(); | 846 | *result = process->PageTable().GetHeapRegionSize(); |
| 881 | return ResultSuccess; | 847 | return ResultSuccess; |
| 882 | 848 | ||
| 883 | case GetInfoType::ASLRRegionBaseAddr: | 849 | case InfoType::AslrRegionAddress: |
| 884 | *result = process->PageTable().GetAliasCodeRegionStart(); | 850 | *result = process->PageTable().GetAliasCodeRegionStart(); |
| 885 | return ResultSuccess; | 851 | return ResultSuccess; |
| 886 | 852 | ||
| 887 | case GetInfoType::ASLRRegionSize: | 853 | case InfoType::AslrRegionSize: |
| 888 | *result = process->PageTable().GetAliasCodeRegionSize(); | 854 | *result = process->PageTable().GetAliasCodeRegionSize(); |
| 889 | return ResultSuccess; | 855 | return ResultSuccess; |
| 890 | 856 | ||
| 891 | case GetInfoType::StackRegionBaseAddr: | 857 | case InfoType::StackRegionAddress: |
| 892 | *result = process->PageTable().GetStackRegionStart(); | 858 | *result = process->PageTable().GetStackRegionStart(); |
| 893 | return ResultSuccess; | 859 | return ResultSuccess; |
| 894 | 860 | ||
| 895 | case GetInfoType::StackRegionSize: | 861 | case InfoType::StackRegionSize: |
| 896 | *result = process->PageTable().GetStackRegionSize(); | 862 | *result = process->PageTable().GetStackRegionSize(); |
| 897 | return ResultSuccess; | 863 | return ResultSuccess; |
| 898 | 864 | ||
| 899 | case GetInfoType::TotalPhysicalMemoryAvailable: | 865 | case InfoType::TotalMemorySize: |
| 900 | *result = process->GetTotalPhysicalMemoryAvailable(); | 866 | *result = process->GetTotalPhysicalMemoryAvailable(); |
| 901 | return ResultSuccess; | 867 | return ResultSuccess; |
| 902 | 868 | ||
| 903 | case GetInfoType::TotalPhysicalMemoryUsed: | 869 | case InfoType::UsedMemorySize: |
| 904 | *result = process->GetTotalPhysicalMemoryUsed(); | 870 | *result = process->GetTotalPhysicalMemoryUsed(); |
| 905 | return ResultSuccess; | 871 | return ResultSuccess; |
| 906 | 872 | ||
| 907 | case GetInfoType::SystemResourceSize: | 873 | case InfoType::SystemResourceSizeTotal: |
| 908 | *result = process->GetSystemResourceSize(); | 874 | *result = process->GetSystemResourceSize(); |
| 909 | return ResultSuccess; | 875 | return ResultSuccess; |
| 910 | 876 | ||
| 911 | case GetInfoType::SystemResourceUsage: | 877 | case InfoType::SystemResourceSizeUsed: |
| 912 | LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage"); | 878 | LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage"); |
| 913 | *result = process->GetSystemResourceUsage(); | 879 | *result = process->GetSystemResourceUsage(); |
| 914 | return ResultSuccess; | 880 | return ResultSuccess; |
| 915 | 881 | ||
| 916 | case GetInfoType::TitleId: | 882 | case InfoType::ProgramId: |
| 917 | *result = process->GetProgramID(); | 883 | *result = process->GetProgramID(); |
| 918 | return ResultSuccess; | 884 | return ResultSuccess; |
| 919 | 885 | ||
| 920 | case GetInfoType::UserExceptionContextAddr: | 886 | case InfoType::UserExceptionContextAddress: |
| 921 | *result = process->GetProcessLocalRegionAddress(); | 887 | *result = process->GetProcessLocalRegionAddress(); |
| 922 | return ResultSuccess; | 888 | return ResultSuccess; |
| 923 | 889 | ||
| 924 | case GetInfoType::TotalPhysicalMemoryAvailableWithoutSystemResource: | 890 | case InfoType::TotalNonSystemMemorySize: |
| 925 | *result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource(); | 891 | *result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource(); |
| 926 | return ResultSuccess; | 892 | return ResultSuccess; |
| 927 | 893 | ||
| 928 | case GetInfoType::TotalPhysicalMemoryUsedWithoutSystemResource: | 894 | case InfoType::UsedNonSystemMemorySize: |
| 929 | *result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource(); | 895 | *result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource(); |
| 930 | return ResultSuccess; | 896 | return ResultSuccess; |
| 931 | 897 | ||
| 898 | case InfoType::FreeThreadCount: | ||
| 899 | *result = process->GetFreeThreadCount(); | ||
| 900 | return ResultSuccess; | ||
| 901 | |||
| 932 | default: | 902 | default: |
| 933 | break; | 903 | break; |
| 934 | } | 904 | } |
| @@ -937,11 +907,11 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han | |||
| 937 | return ResultInvalidEnumValue; | 907 | return ResultInvalidEnumValue; |
| 938 | } | 908 | } |
| 939 | 909 | ||
| 940 | case GetInfoType::IsCurrentProcessBeingDebugged: | 910 | case InfoType::DebuggerAttached: |
| 941 | *result = 0; | 911 | *result = 0; |
| 942 | return ResultSuccess; | 912 | return ResultSuccess; |
| 943 | 913 | ||
| 944 | case GetInfoType::RegisterResourceLimit: { | 914 | case InfoType::ResourceLimit: { |
| 945 | if (handle != 0) { | 915 | if (handle != 0) { |
| 946 | LOG_ERROR(Kernel, "Handle is non zero! handle={:08X}", handle); | 916 | LOG_ERROR(Kernel, "Handle is non zero! handle={:08X}", handle); |
| 947 | return ResultInvalidHandle; | 917 | return ResultInvalidHandle; |
| @@ -969,7 +939,7 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han | |||
| 969 | return ResultSuccess; | 939 | return ResultSuccess; |
| 970 | } | 940 | } |
| 971 | 941 | ||
| 972 | case GetInfoType::RandomEntropy: | 942 | case InfoType::RandomEntropy: |
| 973 | if (handle != 0) { | 943 | if (handle != 0) { |
| 974 | LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}", | 944 | LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}", |
| 975 | handle); | 945 | handle); |
| @@ -985,13 +955,13 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han | |||
| 985 | *result = system.Kernel().CurrentProcess()->GetRandomEntropy(info_sub_id); | 955 | *result = system.Kernel().CurrentProcess()->GetRandomEntropy(info_sub_id); |
| 986 | return ResultSuccess; | 956 | return ResultSuccess; |
| 987 | 957 | ||
| 988 | case GetInfoType::PrivilegedProcessId: | 958 | case InfoType::InitialProcessIdRange: |
| 989 | LOG_WARNING(Kernel_SVC, | 959 | LOG_WARNING(Kernel_SVC, |
| 990 | "(STUBBED) Attempted to query privileged process id bounds, returned 0"); | 960 | "(STUBBED) Attempted to query privileged process id bounds, returned 0"); |
| 991 | *result = 0; | 961 | *result = 0; |
| 992 | return ResultSuccess; | 962 | return ResultSuccess; |
| 993 | 963 | ||
| 994 | case GetInfoType::ThreadTickCount: { | 964 | case InfoType::ThreadTickCount: { |
| 995 | constexpr u64 num_cpus = 4; | 965 | constexpr u64 num_cpus = 4; |
| 996 | if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { | 966 | if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { |
| 997 | LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus, | 967 | LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus, |
| @@ -1026,7 +996,7 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han | |||
| 1026 | *result = out_ticks; | 996 | *result = out_ticks; |
| 1027 | return ResultSuccess; | 997 | return ResultSuccess; |
| 1028 | } | 998 | } |
| 1029 | case GetInfoType::IdleTickCount: { | 999 | case InfoType::IdleTickCount: { |
| 1030 | // Verify the input handle is invalid. | 1000 | // Verify the input handle is invalid. |
| 1031 | R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); | 1001 | R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); |
| 1032 | 1002 | ||
| @@ -1040,7 +1010,7 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han | |||
| 1040 | *result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime(); | 1010 | *result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime(); |
| 1041 | return ResultSuccess; | 1011 | return ResultSuccess; |
| 1042 | } | 1012 | } |
| 1043 | case GetInfoType::MesosphereCurrentProcess: { | 1013 | case InfoType::MesosphereCurrentProcess: { |
| 1044 | // Verify the input handle is invalid. | 1014 | // Verify the input handle is invalid. |
| 1045 | R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); | 1015 | R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); |
| 1046 | 1016 | ||
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: | |||
| 203 | }; | 203 | }; |
| 204 | 204 | ||
| 205 | AudInU::AudInU(Core::System& system_) | 205 | AudInU::AudInU(Core::System& system_) |
| 206 | : ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"}, | 206 | : ServiceFramework{system_, "audin:u", ServiceThreadType::CreateNew}, |
| 207 | impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} { | 207 | service_context{system_, "AudInU"}, impl{std::make_unique<AudioCore::AudioIn::Manager>( |
| 208 | system_)} { | ||
| 208 | // clang-format off | 209 | // clang-format off |
| 209 | static const FunctionInfo functions[] = { | 210 | static const FunctionInfo functions[] = { |
| 210 | {0, &AudInU::ListAudioIns, "ListAudioIns"}, | 211 | {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: | |||
| 26 | explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, | 26 | explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, |
| 27 | size_t session_id, const std::string& device_name, | 27 | size_t session_id, const std::string& device_name, |
| 28 | const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id) | 28 | const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id) |
| 29 | : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, | 29 | : ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew}, |
| 30 | event{service_context.CreateEvent("AudioOutEvent")}, | 30 | service_context{system_, "IAudioOut"}, event{service_context.CreateEvent( |
| 31 | "AudioOutEvent")}, | ||
| 31 | impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { | 32 | impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { |
| 32 | 33 | ||
| 33 | // clang-format off | 34 | // clang-format off |
| @@ -220,8 +221,9 @@ private: | |||
| 220 | }; | 221 | }; |
| 221 | 222 | ||
| 222 | AudOutU::AudOutU(Core::System& system_) | 223 | AudOutU::AudOutU(Core::System& system_) |
| 223 | : ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"}, | 224 | : ServiceFramework{system_, "audout:u", ServiceThreadType::CreateNew}, |
| 224 | impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} { | 225 | service_context{system_, "AudOutU"}, impl{std::make_unique<AudioCore::AudioOut::Manager>( |
| 226 | system_)} { | ||
| 225 | // clang-format off | 227 | // clang-format off |
| 226 | static const FunctionInfo functions[] = { | 228 | static const FunctionInfo functions[] = { |
| 227 | {0, &AudOutU::ListAudioOuts, "ListAudioOuts"}, | 229 | {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: | |||
| 35 | AudioCore::AudioRendererParameterInternal& params, | 35 | AudioCore::AudioRendererParameterInternal& params, |
| 36 | Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, | 36 | Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, |
| 37 | u32 process_handle, u64 applet_resource_user_id, s32 session_id) | 37 | u32 process_handle, u64 applet_resource_user_id, s32 session_id) |
| 38 | : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"}, | 38 | : ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew}, |
| 39 | rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_}, | 39 | service_context{system_, "IAudioRenderer"}, rendered_event{service_context.CreateEvent( |
| 40 | impl{std::make_unique<Renderer>(system_, manager, rendered_event)} { | 40 | "IAudioRendererEvent")}, |
| 41 | manager{manager_}, impl{std::make_unique<Renderer>(system_, manager, rendered_event)} { | ||
| 41 | // clang-format off | 42 | // clang-format off |
| 42 | static const FunctionInfo functions[] = { | 43 | static const FunctionInfo functions[] = { |
| 43 | {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, | 44 | {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, |
| @@ -242,8 +243,10 @@ class IAudioDevice final : public ServiceFramework<IAudioDevice> { | |||
| 242 | public: | 243 | public: |
| 243 | explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision, | 244 | explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision, |
| 244 | u32 device_num) | 245 | u32 device_num) |
| 245 | : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"}, | 246 | : ServiceFramework{system_, "IAudioDevice", ServiceThreadType::CreateNew}, |
| 246 | impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)}, | 247 | service_context{system_, "IAudioDevice"}, impl{std::make_unique<AudioDevice>( |
| 248 | system_, applet_resource_user_id, | ||
| 249 | revision)}, | ||
| 247 | event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} { | 250 | event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} { |
| 248 | static const FunctionInfo functions[] = { | 251 | static const FunctionInfo functions[] = { |
| 249 | {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, | 252 | {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, |
| @@ -418,7 +421,7 @@ private: | |||
| 418 | }; | 421 | }; |
| 419 | 422 | ||
| 420 | AudRenU::AudRenU(Core::System& system_) | 423 | AudRenU::AudRenU(Core::System& system_) |
| 421 | : ServiceFramework{system_, "audren:u"}, | 424 | : ServiceFramework{system_, "audren:u", ServiceThreadType::CreateNew}, |
| 422 | service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} { | 425 | service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} { |
| 423 | // clang-format off | 426 | // clang-format off |
| 424 | static const FunctionInfo functions[] = { | 427 | static const FunctionInfo functions[] = { |
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 4f1a8d6b7..16c5eaf75 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp | |||
| @@ -191,6 +191,13 @@ void SET::GetKeyCodeMap2(Kernel::HLERequestContext& ctx) { | |||
| 191 | GetKeyCodeMapImpl(ctx); | 191 | GetKeyCodeMapImpl(ctx); |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | void SET::GetDeviceNickName(Kernel::HLERequestContext& ctx) { | ||
| 195 | LOG_DEBUG(Service_SET, "called"); | ||
| 196 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 197 | rb.Push(ResultSuccess); | ||
| 198 | ctx.WriteBuffer(Settings::values.device_name.GetValue()); | ||
| 199 | } | ||
| 200 | |||
| 194 | SET::SET(Core::System& system_) : ServiceFramework{system_, "set"} { | 201 | SET::SET(Core::System& system_) : ServiceFramework{system_, "set"} { |
| 195 | // clang-format off | 202 | // clang-format off |
| 196 | static const FunctionInfo functions[] = { | 203 | static const FunctionInfo functions[] = { |
| @@ -205,7 +212,7 @@ SET::SET(Core::System& system_) : ServiceFramework{system_, "set"} { | |||
| 205 | {8, &SET::GetQuestFlag, "GetQuestFlag"}, | 212 | {8, &SET::GetQuestFlag, "GetQuestFlag"}, |
| 206 | {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"}, | 213 | {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"}, |
| 207 | {10, nullptr, "GetFirmwareVersionForDebug"}, | 214 | {10, nullptr, "GetFirmwareVersionForDebug"}, |
| 208 | {11, nullptr, "GetDeviceNickName"}, | 215 | {11, &SET::GetDeviceNickName, "GetDeviceNickName"}, |
| 209 | }; | 216 | }; |
| 210 | // clang-format on | 217 | // clang-format on |
| 211 | 218 | ||
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 60cad3e6f..375975711 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h | |||
| @@ -50,6 +50,7 @@ private: | |||
| 50 | void GetRegionCode(Kernel::HLERequestContext& ctx); | 50 | void GetRegionCode(Kernel::HLERequestContext& ctx); |
| 51 | void GetKeyCodeMap(Kernel::HLERequestContext& ctx); | 51 | void GetKeyCodeMap(Kernel::HLERequestContext& ctx); |
| 52 | void GetKeyCodeMap2(Kernel::HLERequestContext& ctx); | 52 | void GetKeyCodeMap2(Kernel::HLERequestContext& ctx); |
| 53 | void GetDeviceNickName(Kernel::HLERequestContext& ctx); | ||
| 53 | }; | 54 | }; |
| 54 | 55 | ||
| 55 | } // namespace Service::Set | 56 | } // namespace Service::Set |
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index d7cea6aac..94c20edda 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include "common/assert.h" | 4 | #include "common/assert.h" |
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "common/settings.h" | ||
| 6 | #include "core/file_sys/errors.h" | 7 | #include "core/file_sys/errors.h" |
| 7 | #include "core/file_sys/system_archive/system_version.h" | 8 | #include "core/file_sys/system_archive/system_version.h" |
| 8 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| @@ -176,6 +177,13 @@ void SET_SYS::GetSettingsItemValue(Kernel::HLERequestContext& ctx) { | |||
| 176 | rb.Push(response); | 177 | rb.Push(response); |
| 177 | } | 178 | } |
| 178 | 179 | ||
| 180 | void SET_SYS::GetDeviceNickName(Kernel::HLERequestContext& ctx) { | ||
| 181 | LOG_DEBUG(Service_SET, "called"); | ||
| 182 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 183 | rb.Push(ResultSuccess); | ||
| 184 | ctx.WriteBuffer(::Settings::values.device_name.GetValue()); | ||
| 185 | } | ||
| 186 | |||
| 179 | SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { | 187 | SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { |
| 180 | // clang-format off | 188 | // clang-format off |
| 181 | static const FunctionInfo functions[] = { | 189 | static const FunctionInfo functions[] = { |
| @@ -253,7 +261,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { | |||
| 253 | {74, nullptr, "SetWirelessLanEnableFlag"}, | 261 | {74, nullptr, "SetWirelessLanEnableFlag"}, |
| 254 | {75, nullptr, "GetInitialLaunchSettings"}, | 262 | {75, nullptr, "GetInitialLaunchSettings"}, |
| 255 | {76, nullptr, "SetInitialLaunchSettings"}, | 263 | {76, nullptr, "SetInitialLaunchSettings"}, |
| 256 | {77, nullptr, "GetDeviceNickName"}, | 264 | {77, &SET_SYS::GetDeviceNickName, "GetDeviceNickName"}, |
| 257 | {78, nullptr, "SetDeviceNickName"}, | 265 | {78, nullptr, "SetDeviceNickName"}, |
| 258 | {79, nullptr, "GetProductModel"}, | 266 | {79, nullptr, "GetProductModel"}, |
| 259 | {80, nullptr, "GetLdnChannel"}, | 267 | {80, nullptr, "GetLdnChannel"}, |
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h index 258ef8c57..464ac3da1 100644 --- a/src/core/hle/service/set/set_sys.h +++ b/src/core/hle/service/set/set_sys.h | |||
| @@ -29,6 +29,7 @@ private: | |||
| 29 | void GetFirmwareVersion2(Kernel::HLERequestContext& ctx); | 29 | void GetFirmwareVersion2(Kernel::HLERequestContext& ctx); |
| 30 | void GetColorSetId(Kernel::HLERequestContext& ctx); | 30 | void GetColorSetId(Kernel::HLERequestContext& ctx); |
| 31 | void SetColorSetId(Kernel::HLERequestContext& ctx); | 31 | void SetColorSetId(Kernel::HLERequestContext& ctx); |
| 32 | void GetDeviceNickName(Kernel::HLERequestContext& ctx); | ||
| 32 | 33 | ||
| 33 | ColorSet color_set = ColorSet::BasicWhite; | 34 | ColorSet color_set = ColorSet::BasicWhite; |
| 34 | }; | 35 | }; |
diff --git a/src/input_common/drivers/camera.cpp b/src/input_common/drivers/camera.cpp index dceea67e0..fad9177dc 100644 --- a/src/input_common/drivers/camera.cpp +++ b/src/input_common/drivers/camera.cpp | |||
| @@ -17,7 +17,7 @@ Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_) | |||
| 17 | PreSetController(identifier); | 17 | PreSetController(identifier); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | void Camera::SetCameraData(std::size_t width, std::size_t height, std::vector<u32> data) { | 20 | void Camera::SetCameraData(std::size_t width, std::size_t height, std::span<const u32> data) { |
| 21 | const std::size_t desired_width = getImageWidth(); | 21 | const std::size_t desired_width = getImageWidth(); |
| 22 | const std::size_t desired_height = getImageHeight(); | 22 | const std::size_t desired_height = getImageHeight(); |
| 23 | status.data.resize(desired_width * desired_height); | 23 | status.data.resize(desired_width * desired_height); |
diff --git a/src/input_common/drivers/camera.h b/src/input_common/drivers/camera.h index b8a7c75e5..38fb1ae4c 100644 --- a/src/input_common/drivers/camera.h +++ b/src/input_common/drivers/camera.h | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <span> | ||
| 7 | |||
| 6 | #include "input_common/input_engine.h" | 8 | #include "input_common/input_engine.h" |
| 7 | 9 | ||
| 8 | namespace InputCommon { | 10 | namespace InputCommon { |
| @@ -15,7 +17,7 @@ class Camera final : public InputEngine { | |||
| 15 | public: | 17 | public: |
| 16 | explicit Camera(std::string input_engine_); | 18 | explicit Camera(std::string input_engine_); |
| 17 | 19 | ||
| 18 | void SetCameraData(std::size_t width, std::size_t height, std::vector<u32> data); | 20 | void SetCameraData(std::size_t width, std::size_t height, std::span<const u32> data); |
| 19 | 21 | ||
| 20 | std::size_t getImageWidth() const; | 22 | std::size_t getImageWidth() const; |
| 21 | std::size_t getImageHeight() const; | 23 | std::size_t getImageHeight() const; |
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) { | |||
| 1345 | if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles || | 1345 | if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles || |
| 1346 | (profile.warp_size_potentially_larger_than_guest && | 1346 | (profile.warp_size_potentially_larger_than_guest && |
| 1347 | (info.uses_subgroup_vote || info.uses_subgroup_mask))) { | 1347 | (info.uses_subgroup_vote || info.uses_subgroup_mask))) { |
| 1348 | AddCapability(spv::Capability::GroupNonUniform); | ||
| 1348 | subgroup_local_invocation_id = | 1349 | subgroup_local_invocation_id = |
| 1349 | DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId); | 1350 | DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId); |
| 1351 | Decorate(subgroup_local_invocation_id, spv::Decoration::Flat); | ||
| 1350 | } | 1352 | } |
| 1351 | if (info.uses_fswzadd) { | 1353 | if (info.uses_fswzadd) { |
| 1352 | const Id f32_one{Const(1.0f)}; | 1354 | 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 { | |||
| 223 | /// core timing events. | 223 | /// core timing events. |
| 224 | void Start() { | 224 | void Start() { |
| 225 | gpu_thread.StartThread(*renderer, renderer->Context(), *scheduler); | 225 | gpu_thread.StartThread(*renderer, renderer->Context(), *scheduler); |
| 226 | cpu_context = renderer->GetRenderWindow().CreateSharedContext(); | ||
| 227 | cpu_context->MakeCurrent(); | ||
| 228 | } | 226 | } |
| 229 | 227 | ||
| 230 | void NotifyShutdown() { | 228 | void NotifyShutdown() { |
| @@ -235,6 +233,9 @@ struct GPU::Impl { | |||
| 235 | 233 | ||
| 236 | /// Obtain the CPU Context | 234 | /// Obtain the CPU Context |
| 237 | void ObtainContext() { | 235 | void ObtainContext() { |
| 236 | if (!cpu_context) { | ||
| 237 | cpu_context = renderer->GetRenderWindow().CreateSharedContext(); | ||
| 238 | } | ||
| 238 | cpu_context->MakeCurrent(); | 239 | cpu_context->MakeCurrent(); |
| 239 | } | 240 | } |
| 240 | 241 | ||
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() { | |||
| 112 | } | 112 | } |
| 113 | } // Anonymous namespace | 113 | } // Anonymous namespace |
| 114 | 114 | ||
| 115 | Device::Device() { | 115 | Device::Device(Core::Frontend::EmuWindow& emu_window) { |
| 116 | if (!GLAD_GL_VERSION_4_6) { | 116 | if (!GLAD_GL_VERSION_4_6) { |
| 117 | LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available"); | 117 | LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available"); |
| 118 | throw std::runtime_error{"Insufficient version"}; | 118 | throw std::runtime_error{"Insufficient version"}; |
| @@ -126,9 +126,9 @@ Device::Device() { | |||
| 126 | const bool is_intel = vendor_name == "Intel"; | 126 | const bool is_intel = vendor_name == "Intel"; |
| 127 | 127 | ||
| 128 | #ifdef __unix__ | 128 | #ifdef __unix__ |
| 129 | const bool is_linux = true; | 129 | constexpr bool is_linux = true; |
| 130 | #else | 130 | #else |
| 131 | const bool is_linux = false; | 131 | constexpr bool is_linux = false; |
| 132 | #endif | 132 | #endif |
| 133 | 133 | ||
| 134 | bool disable_fast_buffer_sub_data = false; | 134 | bool disable_fast_buffer_sub_data = false; |
| @@ -193,9 +193,11 @@ Device::Device() { | |||
| 193 | } | 193 | } |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | strict_context_required = emu_window.StrictContextRequired(); | ||
| 196 | // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation. | 197 | // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation. |
| 198 | // Blocks EGL on Wayland from using asynchronous shader compilation. | ||
| 197 | use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() && | 199 | use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() && |
| 198 | !(is_amd || (is_intel && !is_linux)); | 200 | !(is_amd || (is_intel && !is_linux)) && !strict_context_required; |
| 199 | use_driver_cache = is_nvidia; | 201 | use_driver_cache = is_nvidia; |
| 200 | 202 | ||
| 201 | LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); | 203 | 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 @@ | |||
| 5 | 5 | ||
| 6 | #include <cstddef> | 6 | #include <cstddef> |
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "core/frontend/emu_window.h" | ||
| 8 | #include "shader_recompiler/stage.h" | 9 | #include "shader_recompiler/stage.h" |
| 9 | 10 | ||
| 10 | namespace Settings { | 11 | namespace Settings { |
| @@ -15,7 +16,7 @@ namespace OpenGL { | |||
| 15 | 16 | ||
| 16 | class Device { | 17 | class Device { |
| 17 | public: | 18 | public: |
| 18 | explicit Device(); | 19 | explicit Device(Core::Frontend::EmuWindow& emu_window); |
| 19 | 20 | ||
| 20 | [[nodiscard]] std::string GetVendorName() const; | 21 | [[nodiscard]] std::string GetVendorName() const; |
| 21 | 22 | ||
| @@ -173,6 +174,10 @@ public: | |||
| 173 | return can_report_memory; | 174 | return can_report_memory; |
| 174 | } | 175 | } |
| 175 | 176 | ||
| 177 | bool StrictContextRequired() const { | ||
| 178 | return strict_context_required; | ||
| 179 | } | ||
| 180 | |||
| 176 | private: | 181 | private: |
| 177 | static bool TestVariableAoffi(); | 182 | static bool TestVariableAoffi(); |
| 178 | static bool TestPreciseBug(); | 183 | static bool TestPreciseBug(); |
| @@ -216,6 +221,7 @@ private: | |||
| 216 | bool has_cbuf_ftou_bug{}; | 221 | bool has_cbuf_ftou_bug{}; |
| 217 | bool has_bool_ref_bug{}; | 222 | bool has_bool_ref_bug{}; |
| 218 | bool can_report_memory{}; | 223 | bool can_report_memory{}; |
| 224 | bool strict_context_required{}; | ||
| 219 | 225 | ||
| 220 | std::string vendor_name; | 226 | std::string vendor_name; |
| 221 | }; | 227 | }; |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index b12ecd478..f8868a012 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 | |||
| 174 | texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_}, | 174 | texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_}, |
| 175 | state_tracker{state_tracker_}, shader_notify{shader_notify_}, | 175 | state_tracker{state_tracker_}, shader_notify{shader_notify_}, |
| 176 | use_asynchronous_shaders{device.UseAsynchronousShaders()}, | 176 | use_asynchronous_shaders{device.UseAsynchronousShaders()}, |
| 177 | strict_context_required{device.StrictContextRequired()}, | ||
| 177 | profile{ | 178 | profile{ |
| 178 | .supported_spirv = 0x00010000, | 179 | .supported_spirv = 0x00010000, |
| 179 | 180 | ||
| @@ -256,9 +257,14 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | |||
| 256 | } | 257 | } |
| 257 | shader_cache_filename = base_dir / "opengl.bin"; | 258 | shader_cache_filename = base_dir / "opengl.bin"; |
| 258 | 259 | ||
| 259 | if (!workers) { | 260 | if (!workers && !strict_context_required) { |
| 260 | workers = CreateWorkers(); | 261 | workers = CreateWorkers(); |
| 261 | } | 262 | } |
| 263 | std::optional<Context> strict_context; | ||
| 264 | if (strict_context_required) { | ||
| 265 | strict_context.emplace(emu_window); | ||
| 266 | } | ||
| 267 | |||
| 262 | struct { | 268 | struct { |
| 263 | std::mutex mutex; | 269 | std::mutex mutex; |
| 264 | size_t total{}; | 270 | size_t total{}; |
| @@ -266,44 +272,49 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | |||
| 266 | bool has_loaded{}; | 272 | bool has_loaded{}; |
| 267 | } state; | 273 | } state; |
| 268 | 274 | ||
| 275 | const auto queue_work{[&](Common::UniqueFunction<void, Context*>&& work) { | ||
| 276 | if (strict_context_required) { | ||
| 277 | work(&strict_context.value()); | ||
| 278 | } else { | ||
| 279 | workers->QueueWork(std::move(work)); | ||
| 280 | } | ||
| 281 | }}; | ||
| 269 | const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { | 282 | const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { |
| 270 | ComputePipelineKey key; | 283 | ComputePipelineKey key; |
| 271 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); | 284 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); |
| 272 | workers->QueueWork( | 285 | queue_work([this, key, env = std::move(env), &state, &callback](Context* ctx) mutable { |
| 273 | [this, key, env = std::move(env), &state, &callback](Context* ctx) mutable { | 286 | ctx->pools.ReleaseContents(); |
| 274 | ctx->pools.ReleaseContents(); | 287 | auto pipeline{CreateComputePipeline(ctx->pools, key, env)}; |
| 275 | auto pipeline{CreateComputePipeline(ctx->pools, key, env)}; | 288 | std::scoped_lock lock{state.mutex}; |
| 276 | std::scoped_lock lock{state.mutex}; | 289 | if (pipeline) { |
| 277 | if (pipeline) { | 290 | compute_cache.emplace(key, std::move(pipeline)); |
| 278 | compute_cache.emplace(key, std::move(pipeline)); | 291 | } |
| 279 | } | 292 | ++state.built; |
| 280 | ++state.built; | 293 | if (state.has_loaded) { |
| 281 | if (state.has_loaded) { | 294 | callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); |
| 282 | callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); | 295 | } |
| 283 | } | 296 | }); |
| 284 | }); | ||
| 285 | ++state.total; | 297 | ++state.total; |
| 286 | }}; | 298 | }}; |
| 287 | const auto load_graphics{[&](std::ifstream& file, std::vector<FileEnvironment> envs) { | 299 | const auto load_graphics{[&](std::ifstream& file, std::vector<FileEnvironment> envs) { |
| 288 | GraphicsPipelineKey key; | 300 | GraphicsPipelineKey key; |
| 289 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); | 301 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); |
| 290 | workers->QueueWork( | 302 | queue_work([this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable { |
| 291 | [this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable { | 303 | boost::container::static_vector<Shader::Environment*, 5> env_ptrs; |
| 292 | boost::container::static_vector<Shader::Environment*, 5> env_ptrs; | 304 | for (auto& env : envs) { |
| 293 | for (auto& env : envs) { | 305 | env_ptrs.push_back(&env); |
| 294 | env_ptrs.push_back(&env); | 306 | } |
| 295 | } | 307 | ctx->pools.ReleaseContents(); |
| 296 | ctx->pools.ReleaseContents(); | 308 | auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)}; |
| 297 | auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)}; | 309 | std::scoped_lock lock{state.mutex}; |
| 298 | std::scoped_lock lock{state.mutex}; | 310 | if (pipeline) { |
| 299 | if (pipeline) { | 311 | graphics_cache.emplace(key, std::move(pipeline)); |
| 300 | graphics_cache.emplace(key, std::move(pipeline)); | 312 | } |
| 301 | } | 313 | ++state.built; |
| 302 | ++state.built; | 314 | if (state.has_loaded) { |
| 303 | if (state.has_loaded) { | 315 | callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); |
| 304 | callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); | 316 | } |
| 305 | } | 317 | }); |
| 306 | }); | ||
| 307 | ++state.total; | 318 | ++state.total; |
| 308 | }}; | 319 | }}; |
| 309 | LoadPipelines(stop_loading, shader_cache_filename, CACHE_VERSION, load_compute, load_graphics); | 320 | LoadPipelines(stop_loading, shader_cache_filename, CACHE_VERSION, load_compute, load_graphics); |
| @@ -315,6 +326,9 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | |||
| 315 | state.has_loaded = true; | 326 | state.has_loaded = true; |
| 316 | lock.unlock(); | 327 | lock.unlock(); |
| 317 | 328 | ||
| 329 | if (strict_context_required) { | ||
| 330 | return; | ||
| 331 | } | ||
| 318 | workers->WaitForRequests(stop_loading); | 332 | workers->WaitForRequests(stop_loading); |
| 319 | if (!use_asynchronous_shaders) { | 333 | if (!use_asynchronous_shaders) { |
| 320 | workers.reset(); | 334 | 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: | |||
| 69 | StateTracker& state_tracker; | 69 | StateTracker& state_tracker; |
| 70 | VideoCore::ShaderNotify& shader_notify; | 70 | VideoCore::ShaderNotify& shader_notify; |
| 71 | const bool use_asynchronous_shaders; | 71 | const bool use_asynchronous_shaders; |
| 72 | const bool strict_context_required; | ||
| 72 | 73 | ||
| 73 | GraphicsPipelineKey graphics_key{}; | 74 | GraphicsPipelineKey graphics_key{}; |
| 74 | GraphicsPipeline* current_pipeline{}; | 75 | 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_, | |||
| 140 | Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, | 140 | Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, |
| 141 | std::unique_ptr<Core::Frontend::GraphicsContext> context_) | 141 | std::unique_ptr<Core::Frontend::GraphicsContext> context_) |
| 142 | : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_}, | 142 | : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_}, |
| 143 | emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, state_tracker{}, | 143 | emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, device{emu_window_}, |
| 144 | program_manager{device}, | 144 | state_tracker{}, program_manager{device}, |
| 145 | rasterizer(emu_window, gpu, cpu_memory, device, screen_info, program_manager, state_tracker) { | 145 | rasterizer(emu_window, gpu, cpu_memory, device, screen_info, program_manager, state_tracker) { |
| 146 | if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) { | 146 | if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) { |
| 147 | glEnable(GL_DEBUG_OUTPUT); | 147 | 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) { | |||
| 139 | RenderScreenshot(*framebuffer, use_accelerated); | 139 | RenderScreenshot(*framebuffer, use_accelerated); |
| 140 | 140 | ||
| 141 | bool has_been_recreated = false; | 141 | bool has_been_recreated = false; |
| 142 | const auto recreate_swapchain = [&] { | 142 | const auto recreate_swapchain = [&](u32 width, u32 height) { |
| 143 | if (!has_been_recreated) { | 143 | if (!has_been_recreated) { |
| 144 | has_been_recreated = true; | 144 | has_been_recreated = true; |
| 145 | scheduler.Finish(); | 145 | scheduler.Finish(); |
| 146 | } | 146 | } |
| 147 | const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); | 147 | swapchain.Create(width, height, is_srgb); |
| 148 | swapchain.Create(layout.width, layout.height, is_srgb); | ||
| 149 | }; | 148 | }; |
| 150 | if (swapchain.NeedsRecreation(is_srgb)) { | 149 | |
| 151 | recreate_swapchain(); | 150 | const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); |
| 151 | if (swapchain.NeedsRecreation(is_srgb) || swapchain.GetWidth() != layout.width || | ||
| 152 | swapchain.GetHeight() != layout.height) { | ||
| 153 | recreate_swapchain(layout.width, layout.height); | ||
| 152 | } | 154 | } |
| 153 | bool is_outdated; | 155 | bool is_outdated; |
| 154 | do { | 156 | do { |
| 155 | swapchain.AcquireNextImage(); | 157 | swapchain.AcquireNextImage(); |
| 156 | is_outdated = swapchain.IsOutDated(); | 158 | is_outdated = swapchain.IsOutDated(); |
| 157 | if (is_outdated) { | 159 | if (is_outdated) { |
| 158 | recreate_swapchain(); | 160 | recreate_swapchain(layout.width, layout.height); |
| 159 | } | 161 | } |
| 160 | } while (is_outdated); | 162 | } while (is_outdated); |
| 161 | if (has_been_recreated) { | 163 | 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) { | |||
| 285 | 285 | ||
| 286 | void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, | 286 | void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, |
| 287 | u32 stride) { | 287 | u32 stride) { |
| 288 | if (index >= device.GetMaxVertexInputBindings()) { | ||
| 289 | return; | ||
| 290 | } | ||
| 288 | if (device.IsExtExtendedDynamicStateSupported()) { | 291 | if (device.IsExtExtendedDynamicStateSupported()) { |
| 289 | scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) { | 292 | scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) { |
| 290 | const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0; | 293 | 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 00d7dbeea..515d8d869 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) { | |||
| 529 | static_vector<VkVertexInputBindingDivisorDescriptionEXT, 32> vertex_binding_divisors; | 529 | static_vector<VkVertexInputBindingDivisorDescriptionEXT, 32> vertex_binding_divisors; |
| 530 | static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes; | 530 | static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes; |
| 531 | if (key.state.dynamic_vertex_input) { | 531 | if (key.state.dynamic_vertex_input) { |
| 532 | for (size_t index = 0; index < key.state.attributes.size(); ++index) { | 532 | const size_t num_vertex_arrays = std::min( |
| 533 | key.state.attributes.size(), static_cast<size_t>(device.GetMaxVertexInputBindings())); | ||
| 534 | for (size_t index = 0; index < num_vertex_arrays; ++index) { | ||
| 533 | const u32 type = key.state.DynamicAttributeType(index); | 535 | const u32 type = key.state.DynamicAttributeType(index); |
| 534 | if (!stage_infos[0].loads.Generic(index) || type == 0) { | 536 | if (!stage_infos[0].loads.Generic(index) || type == 0) { |
| 535 | continue; | 537 | continue; |
| @@ -551,7 +553,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 551 | }); | 553 | }); |
| 552 | } | 554 | } |
| 553 | } else { | 555 | } else { |
| 554 | for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 556 | const size_t num_vertex_arrays = std::min( |
| 557 | Maxwell::NumVertexArrays, static_cast<size_t>(device.GetMaxVertexInputBindings())); | ||
| 558 | for (size_t index = 0; index < num_vertex_arrays; ++index) { | ||
| 555 | const bool instanced = key.state.binding_divisors[index] != 0; | 559 | const bool instanced = key.state.binding_divisors[index] != 0; |
| 556 | const auto rate = | 560 | const auto rate = |
| 557 | instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; | 561 | instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; |
| @@ -580,6 +584,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 580 | }); | 584 | }); |
| 581 | } | 585 | } |
| 582 | } | 586 | } |
| 587 | ASSERT(vertex_attributes.size() <= device.GetMaxVertexInputAttributes()); | ||
| 588 | |||
| 583 | VkPipelineVertexInputStateCreateInfo vertex_input_ci{ | 589 | VkPipelineVertexInputStateCreateInfo vertex_input_ci{ |
| 584 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | 590 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, |
| 585 | .pNext = nullptr, | 591 | .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 66c9f959a..e7262420c 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -342,6 +342,15 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | |||
| 342 | .support_snorm_render_buffer = true, | 342 | .support_snorm_render_buffer = true, |
| 343 | .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(), | 343 | .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(), |
| 344 | }; | 344 | }; |
| 345 | |||
| 346 | if (device.GetMaxVertexInputAttributes() < Maxwell::NumVertexAttributes) { | ||
| 347 | LOG_WARNING(Render_Vulkan, "maxVertexInputAttributes is too low: {} < {}", | ||
| 348 | device.GetMaxVertexInputAttributes(), Maxwell::NumVertexAttributes); | ||
| 349 | } | ||
| 350 | if (device.GetMaxVertexInputBindings() < Maxwell::NumVertexArrays) { | ||
| 351 | LOG_WARNING(Render_Vulkan, "maxVertexInputBindings is too low: {} < {}", | ||
| 352 | device.GetMaxVertexInputBindings(), Maxwell::NumVertexArrays); | ||
| 353 | } | ||
| 345 | } | 354 | } |
| 346 | 355 | ||
| 347 | PipelineCache::~PipelineCache() = default; | 356 | PipelineCache::~PipelineCache() = default; |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index a8b82abae..4b7126c30 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -658,8 +658,7 @@ void RasterizerVulkan::BeginTransformFeedback() { | |||
| 658 | return; | 658 | return; |
| 659 | } | 659 | } |
| 660 | UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderType::TessellationInit) || | 660 | UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderType::TessellationInit) || |
| 661 | regs.IsShaderConfigEnabled(Maxwell::ShaderType::Tessellation) || | 661 | regs.IsShaderConfigEnabled(Maxwell::ShaderType::Tessellation)); |
| 662 | regs.IsShaderConfigEnabled(Maxwell::ShaderType::Geometry)); | ||
| 663 | scheduler.Record( | 662 | scheduler.Record( |
| 664 | [](vk::CommandBuffer cmdbuf) { cmdbuf.BeginTransformFeedbackEXT(0, 0, nullptr, nullptr); }); | 663 | [](vk::CommandBuffer cmdbuf) { cmdbuf.BeginTransformFeedbackEXT(0, 0, nullptr, nullptr); }); |
| 665 | } | 664 | } |
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 | |||
| 67 | 67 | ||
| 68 | } // Anonymous namespace | 68 | } // Anonymous namespace |
| 69 | 69 | ||
| 70 | Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, u32 width, | 70 | Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, |
| 71 | u32 height, bool srgb) | 71 | u32 width_, u32 height_, bool srgb) |
| 72 | : surface{surface_}, device{device_}, scheduler{scheduler_} { | 72 | : surface{surface_}, device{device_}, scheduler{scheduler_} { |
| 73 | Create(width, height, srgb); | 73 | Create(width_, height_, srgb); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | Swapchain::~Swapchain() = default; | 76 | Swapchain::~Swapchain() = default; |
| 77 | 77 | ||
| 78 | void Swapchain::Create(u32 width, u32 height, bool srgb) { | 78 | void Swapchain::Create(u32 width_, u32 height_, bool srgb) { |
| 79 | is_outdated = false; | 79 | is_outdated = false; |
| 80 | is_suboptimal = false; | 80 | is_suboptimal = false; |
| 81 | width = width_; | ||
| 82 | height = height_; | ||
| 81 | 83 | ||
| 82 | const auto physical_device = device.GetPhysical(); | 84 | const auto physical_device = device.GetPhysical(); |
| 83 | const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)}; | 85 | const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)}; |
| @@ -88,7 +90,7 @@ void Swapchain::Create(u32 width, u32 height, bool srgb) { | |||
| 88 | device.GetLogical().WaitIdle(); | 90 | device.GetLogical().WaitIdle(); |
| 89 | Destroy(); | 91 | Destroy(); |
| 90 | 92 | ||
| 91 | CreateSwapchain(capabilities, width, height, srgb); | 93 | CreateSwapchain(capabilities, srgb); |
| 92 | CreateSemaphores(); | 94 | CreateSemaphores(); |
| 93 | CreateImageViews(); | 95 | CreateImageViews(); |
| 94 | 96 | ||
| @@ -148,8 +150,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) { | |||
| 148 | } | 150 | } |
| 149 | } | 151 | } |
| 150 | 152 | ||
| 151 | void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height, | 153 | void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { |
| 152 | bool srgb) { | ||
| 153 | const auto physical_device{device.GetPhysical()}; | 154 | const auto physical_device{device.GetPhysical()}; |
| 154 | const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; | 155 | const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; |
| 155 | const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)}; | 156 | 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: | |||
| 80 | return *present_semaphores[frame_index]; | 80 | return *present_semaphores[frame_index]; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | u32 GetWidth() const { | ||
| 84 | return width; | ||
| 85 | } | ||
| 86 | |||
| 87 | u32 GetHeight() const { | ||
| 88 | return height; | ||
| 89 | } | ||
| 90 | |||
| 83 | private: | 91 | private: |
| 84 | void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height, | 92 | void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb); |
| 85 | bool srgb); | ||
| 86 | void CreateSemaphores(); | 93 | void CreateSemaphores(); |
| 87 | void CreateImageViews(); | 94 | void CreateImageViews(); |
| 88 | 95 | ||
| @@ -105,6 +112,9 @@ private: | |||
| 105 | std::vector<u64> resource_ticks; | 112 | std::vector<u64> resource_ticks; |
| 106 | std::vector<vk::Semaphore> present_semaphores; | 113 | std::vector<vk::Semaphore> present_semaphores; |
| 107 | 114 | ||
| 115 | u32 width; | ||
| 116 | u32 height; | ||
| 117 | |||
| 108 | u32 image_index{}; | 118 | u32 image_index{}; |
| 109 | u32 frame_index{}; | 119 | u32 frame_index{}; |
| 110 | 120 | ||
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 3604c83c1..c4d31681a 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 | |||
| 421 | VkPhysicalDevice8BitStorageFeatures bit8_storage{ | 421 | VkPhysicalDevice8BitStorageFeatures bit8_storage{ |
| 422 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, | 422 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, |
| 423 | .pNext = nullptr, | 423 | .pNext = nullptr, |
| 424 | .storageBuffer8BitAccess = false, | 424 | .storageBuffer8BitAccess = true, |
| 425 | .uniformAndStorageBuffer8BitAccess = true, | 425 | .uniformAndStorageBuffer8BitAccess = true, |
| 426 | .storagePushConstant8 = false, | 426 | .storagePushConstant8 = false, |
| 427 | }; | 427 | }; |
| @@ -1054,6 +1054,7 @@ void Device::CheckSuitability(bool requires_swapchain) const { | |||
| 1054 | std::make_pair(bit16_storage.storageBuffer16BitAccess, "storageBuffer16BitAccess"), | 1054 | std::make_pair(bit16_storage.storageBuffer16BitAccess, "storageBuffer16BitAccess"), |
| 1055 | std::make_pair(bit16_storage.uniformAndStorageBuffer16BitAccess, | 1055 | std::make_pair(bit16_storage.uniformAndStorageBuffer16BitAccess, |
| 1056 | "uniformAndStorageBuffer16BitAccess"), | 1056 | "uniformAndStorageBuffer16BitAccess"), |
| 1057 | std::make_pair(bit8_storage.storageBuffer8BitAccess, "storageBuffer8BitAccess"), | ||
| 1057 | std::make_pair(bit8_storage.uniformAndStorageBuffer8BitAccess, | 1058 | std::make_pair(bit8_storage.uniformAndStorageBuffer8BitAccess, |
| 1058 | "uniformAndStorageBuffer8BitAccess"), | 1059 | "uniformAndStorageBuffer8BitAccess"), |
| 1059 | std::make_pair(host_query_reset.hostQueryReset, "hostQueryReset"), | 1060 | std::make_pair(host_query_reset.hostQueryReset, "hostQueryReset"), |
| @@ -1405,6 +1406,10 @@ void Device::SetupFeatures() { | |||
| 1405 | is_shader_storage_image_multisample = features.shaderStorageImageMultisample; | 1406 | is_shader_storage_image_multisample = features.shaderStorageImageMultisample; |
| 1406 | is_blit_depth_stencil_supported = TestDepthStencilBlits(); | 1407 | is_blit_depth_stencil_supported = TestDepthStencilBlits(); |
| 1407 | is_optimal_astc_supported = IsOptimalAstcSupported(features); | 1408 | is_optimal_astc_supported = IsOptimalAstcSupported(features); |
| 1409 | |||
| 1410 | const VkPhysicalDeviceLimits& limits{properties.limits}; | ||
| 1411 | max_vertex_input_attributes = limits.maxVertexInputAttributes; | ||
| 1412 | max_vertex_input_bindings = limits.maxVertexInputBindings; | ||
| 1408 | } | 1413 | } |
| 1409 | 1414 | ||
| 1410 | void Device::SetupProperties() { | 1415 | void Device::SetupProperties() { |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 3755275c3..6a26c4e6e 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -373,6 +373,14 @@ public: | |||
| 373 | return must_emulate_bgr565; | 373 | return must_emulate_bgr565; |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | u32 GetMaxVertexInputAttributes() const { | ||
| 377 | return max_vertex_input_attributes; | ||
| 378 | } | ||
| 379 | |||
| 380 | u32 GetMaxVertexInputBindings() const { | ||
| 381 | return max_vertex_input_bindings; | ||
| 382 | } | ||
| 383 | |||
| 376 | private: | 384 | private: |
| 377 | /// Checks if the physical device is suitable. | 385 | /// Checks if the physical device is suitable. |
| 378 | void CheckSuitability(bool requires_swapchain) const; | 386 | void CheckSuitability(bool requires_swapchain) const; |
| @@ -473,6 +481,8 @@ private: | |||
| 473 | bool supports_d24_depth{}; ///< Supports D24 depth buffers. | 481 | bool supports_d24_depth{}; ///< Supports D24 depth buffers. |
| 474 | bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting. | 482 | bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting. |
| 475 | bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format. | 483 | bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format. |
| 484 | u32 max_vertex_input_attributes{}; ///< Max vertex input attributes in pipeline | ||
| 485 | u32 max_vertex_input_bindings{}; ///< Max vertex input buffers in pipeline | ||
| 476 | 486 | ||
| 477 | // Telemetry parameters | 487 | // Telemetry parameters |
| 478 | std::string vendor_name; ///< Device's driver name. | 488 | std::string vendor_name; ///< Device's driver name. |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 5b5b6fed8..682b37f47 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -44,6 +44,8 @@ | |||
| 44 | #include "yuzu/bootmanager.h" | 44 | #include "yuzu/bootmanager.h" |
| 45 | #include "yuzu/main.h" | 45 | #include "yuzu/main.h" |
| 46 | 46 | ||
| 47 | static Core::Frontend::WindowSystemType GetWindowSystemType(); | ||
| 48 | |||
| 47 | EmuThread::EmuThread(Core::System& system_) : system{system_} {} | 49 | EmuThread::EmuThread(Core::System& system_) : system{system_} {} |
| 48 | 50 | ||
| 49 | EmuThread::~EmuThread() = default; | 51 | EmuThread::~EmuThread() = default; |
| @@ -61,8 +63,6 @@ void EmuThread::run() { | |||
| 61 | 63 | ||
| 62 | // Main process has been loaded. Make the context current to this thread and begin GPU and CPU | 64 | // Main process has been loaded. Make the context current to this thread and begin GPU and CPU |
| 63 | // execution. | 65 | // execution. |
| 64 | gpu.Start(); | ||
| 65 | |||
| 66 | gpu.ObtainContext(); | 66 | gpu.ObtainContext(); |
| 67 | 67 | ||
| 68 | emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); | 68 | emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); |
| @@ -77,9 +77,15 @@ void EmuThread::run() { | |||
| 77 | emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); | 77 | emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); |
| 78 | 78 | ||
| 79 | gpu.ReleaseContext(); | 79 | gpu.ReleaseContext(); |
| 80 | gpu.Start(); | ||
| 80 | 81 | ||
| 81 | system.GetCpuManager().OnGpuReady(); | 82 | system.GetCpuManager().OnGpuReady(); |
| 82 | 83 | ||
| 84 | system.RegisterExitCallback([this]() { | ||
| 85 | stop_source.request_stop(); | ||
| 86 | SetRunning(false); | ||
| 87 | }); | ||
| 88 | |||
| 83 | // Holds whether the cpu was running during the last iteration, | 89 | // Holds whether the cpu was running during the last iteration, |
| 84 | // so that the DebugModeLeft signal can be emitted before the | 90 | // so that the DebugModeLeft signal can be emitted before the |
| 85 | // next execution step | 91 | // next execution step |
| @@ -225,6 +231,9 @@ public: | |||
| 225 | explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { | 231 | explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { |
| 226 | setAttribute(Qt::WA_NativeWindow); | 232 | setAttribute(Qt::WA_NativeWindow); |
| 227 | setAttribute(Qt::WA_PaintOnScreen); | 233 | setAttribute(Qt::WA_PaintOnScreen); |
| 234 | if (GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) { | ||
| 235 | setAttribute(Qt::WA_DontCreateNativeAncestors); | ||
| 236 | } | ||
| 228 | } | 237 | } |
| 229 | 238 | ||
| 230 | virtual ~RenderWidget() = default; | 239 | virtual ~RenderWidget() = default; |
| @@ -269,12 +278,14 @@ static Core::Frontend::WindowSystemType GetWindowSystemType() { | |||
| 269 | return Core::Frontend::WindowSystemType::X11; | 278 | return Core::Frontend::WindowSystemType::X11; |
| 270 | else if (platform_name == QStringLiteral("wayland")) | 279 | else if (platform_name == QStringLiteral("wayland")) |
| 271 | return Core::Frontend::WindowSystemType::Wayland; | 280 | return Core::Frontend::WindowSystemType::Wayland; |
| 281 | else if (platform_name == QStringLiteral("wayland-egl")) | ||
| 282 | return Core::Frontend::WindowSystemType::Wayland; | ||
| 272 | else if (platform_name == QStringLiteral("cocoa")) | 283 | else if (platform_name == QStringLiteral("cocoa")) |
| 273 | return Core::Frontend::WindowSystemType::Cocoa; | 284 | return Core::Frontend::WindowSystemType::Cocoa; |
| 274 | else if (platform_name == QStringLiteral("android")) | 285 | else if (platform_name == QStringLiteral("android")) |
| 275 | return Core::Frontend::WindowSystemType::Android; | 286 | return Core::Frontend::WindowSystemType::Android; |
| 276 | 287 | ||
| 277 | LOG_CRITICAL(Frontend, "Unknown Qt platform!"); | 288 | LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString()); |
| 278 | return Core::Frontend::WindowSystemType::Windows; | 289 | return Core::Frontend::WindowSystemType::Windows; |
| 279 | } | 290 | } |
| 280 | 291 | ||
| @@ -314,6 +325,9 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, | |||
| 314 | input_subsystem->Initialize(); | 325 | input_subsystem->Initialize(); |
| 315 | this->setMouseTracking(true); | 326 | this->setMouseTracking(true); |
| 316 | 327 | ||
| 328 | strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland") || | ||
| 329 | QGuiApplication::platformName() == QStringLiteral("wayland-egl"); | ||
| 330 | |||
| 317 | connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); | 331 | connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); |
| 318 | connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, | 332 | connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, |
| 319 | Qt::QueuedConnection); | 333 | Qt::QueuedConnection); |
| @@ -750,6 +764,7 @@ void GRenderWindow::InitializeCamera() { | |||
| 750 | return; | 764 | return; |
| 751 | } | 765 | } |
| 752 | 766 | ||
| 767 | camera_data.resize(CAMERA_WIDTH * CAMERA_HEIGHT); | ||
| 753 | camera_capture->setCaptureDestination(QCameraImageCapture::CaptureDestination::CaptureToBuffer); | 768 | camera_capture->setCaptureDestination(QCameraImageCapture::CaptureDestination::CaptureToBuffer); |
| 754 | connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, | 769 | connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, |
| 755 | &GRenderWindow::OnCameraCapture); | 770 | &GRenderWindow::OnCameraCapture); |
| @@ -805,16 +820,13 @@ void GRenderWindow::RequestCameraCapture() { | |||
| 805 | } | 820 | } |
| 806 | 821 | ||
| 807 | void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { | 822 | void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { |
| 808 | constexpr std::size_t camera_width = 320; | 823 | // TODO: Capture directly in the format and resolution needed |
| 809 | constexpr std::size_t camera_height = 240; | ||
| 810 | const auto converted = | 824 | const auto converted = |
| 811 | img.scaled(camera_width, camera_height, Qt::AspectRatioMode::IgnoreAspectRatio, | 825 | img.scaled(CAMERA_WIDTH, CAMERA_HEIGHT, Qt::AspectRatioMode::IgnoreAspectRatio, |
| 812 | Qt::TransformationMode::SmoothTransformation) | 826 | Qt::TransformationMode::SmoothTransformation) |
| 813 | .mirrored(false, true); | 827 | .mirrored(false, true); |
| 814 | std::vector<u32> camera_data{}; | 828 | std::memcpy(camera_data.data(), converted.bits(), CAMERA_WIDTH * CAMERA_HEIGHT * sizeof(u32)); |
| 815 | camera_data.resize(camera_width * camera_height); | 829 | input_subsystem->GetCamera()->SetCameraData(CAMERA_WIDTH, CAMERA_HEIGHT, camera_data); |
| 816 | std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32)); | ||
| 817 | input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data); | ||
| 818 | pending_camera_snapshots = 0; | 830 | pending_camera_snapshots = 0; |
| 819 | } | 831 | } |
| 820 | 832 | ||
| @@ -952,6 +964,12 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal | |||
| 952 | 964 | ||
| 953 | bool GRenderWindow::InitializeOpenGL() { | 965 | bool GRenderWindow::InitializeOpenGL() { |
| 954 | #ifdef HAS_OPENGL | 966 | #ifdef HAS_OPENGL |
| 967 | if (!QOpenGLContext::supportsThreadedOpenGL()) { | ||
| 968 | QMessageBox::warning(this, tr("OpenGL not available!"), | ||
| 969 | tr("OpenGL shared contexts are not supported.")); | ||
| 970 | return false; | ||
| 971 | } | ||
| 972 | |||
| 955 | // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, | 973 | // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, |
| 956 | // WA_DontShowOnScreen, WA_DeleteOnClose | 974 | // WA_DontShowOnScreen, WA_DeleteOnClose |
| 957 | auto child = new OpenGLRenderWidget(this); | 975 | auto child = new OpenGLRenderWidget(this); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index f4deae4ee..5bbcf61f7 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -84,9 +84,10 @@ public: | |||
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | /** | 86 | /** |
| 87 | * Requests for the emulation thread to stop running | 87 | * Requests for the emulation thread to immediately stop running |
| 88 | */ | 88 | */ |
| 89 | void RequestStop() { | 89 | void ForceStop() { |
| 90 | LOG_WARNING(Frontend, "Force stopping EmuThread"); | ||
| 90 | stop_source.request_stop(); | 91 | stop_source.request_stop(); |
| 91 | SetRunning(false); | 92 | SetRunning(false); |
| 92 | } | 93 | } |
| @@ -246,6 +247,9 @@ private: | |||
| 246 | #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA | 247 | #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA |
| 247 | std::unique_ptr<QCamera> camera; | 248 | std::unique_ptr<QCamera> camera; |
| 248 | std::unique_ptr<QCameraImageCapture> camera_capture; | 249 | std::unique_ptr<QCameraImageCapture> camera_capture; |
| 250 | static constexpr std::size_t CAMERA_WIDTH = 320; | ||
| 251 | static constexpr std::size_t CAMERA_HEIGHT = 240; | ||
| 252 | std::vector<u32> camera_data; | ||
| 249 | #endif | 253 | #endif |
| 250 | std::unique_ptr<QTimer> camera_timer; | 254 | std::unique_ptr<QTimer> camera_timer; |
| 251 | 255 | ||
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 90fb4b0a4..a8d47a2f9 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -783,6 +783,8 @@ void Config::ReadSystemValues() { | |||
| 783 | } | 783 | } |
| 784 | } | 784 | } |
| 785 | 785 | ||
| 786 | ReadBasicSetting(Settings::values.device_name); | ||
| 787 | |||
| 786 | if (global) { | 788 | if (global) { |
| 787 | ReadBasicSetting(Settings::values.current_user); | 789 | ReadBasicSetting(Settings::values.current_user); |
| 788 | Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0, | 790 | Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0, |
| @@ -1405,6 +1407,7 @@ void Config::SaveSystemValues() { | |||
| 1405 | Settings::values.rng_seed.UsingGlobal()); | 1407 | Settings::values.rng_seed.UsingGlobal()); |
| 1406 | WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.GetValue(global).value_or(0), | 1408 | WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.GetValue(global).value_or(0), |
| 1407 | 0, Settings::values.rng_seed.UsingGlobal()); | 1409 | 0, Settings::values.rng_seed.UsingGlobal()); |
| 1410 | WriteBasicSetting(Settings::values.device_name); | ||
| 1408 | 1411 | ||
| 1409 | if (global) { | 1412 | if (global) { |
| 1410 | WriteBasicSetting(Settings::values.current_user); | 1413 | WriteBasicSetting(Settings::values.current_user); |
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index bc9d9d77a..9b14e5903 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -72,6 +72,8 @@ void ConfigureSystem::SetConfiguration() { | |||
| 72 | ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value()); | 72 | ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value()); |
| 73 | ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value()); | 73 | ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value()); |
| 74 | ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time)); | 74 | ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time)); |
| 75 | ui->device_name_edit->setText( | ||
| 76 | QString::fromUtf8(Settings::values.device_name.GetValue().c_str())); | ||
| 75 | 77 | ||
| 76 | if (Settings::IsConfiguringGlobal()) { | 78 | if (Settings::IsConfiguringGlobal()) { |
| 77 | ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); | 79 | ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); |
| @@ -115,6 +117,8 @@ void ConfigureSystem::ApplyConfiguration() { | |||
| 115 | } | 117 | } |
| 116 | } | 118 | } |
| 117 | 119 | ||
| 120 | Settings::values.device_name = ui->device_name_edit->text().toStdString(); | ||
| 121 | |||
| 118 | if (!enabled) { | 122 | if (!enabled) { |
| 119 | return; | 123 | return; |
| 120 | } | 124 | } |
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui index b234ea87b..46892f5c1 100644 --- a/src/yuzu/configuration/configure_system.ui +++ b/src/yuzu/configuration/configure_system.ui | |||
| @@ -432,6 +432,13 @@ | |||
| 432 | </property> | 432 | </property> |
| 433 | </widget> | 433 | </widget> |
| 434 | </item> | 434 | </item> |
| 435 | <item row="7" column="0"> | ||
| 436 | <widget class="QLabel" name="device_name_label"> | ||
| 437 | <property name="text"> | ||
| 438 | <string>Device Name</string> | ||
| 439 | </property> | ||
| 440 | </widget> | ||
| 441 | </item> | ||
| 435 | <item row="3" column="1"> | 442 | <item row="3" column="1"> |
| 436 | <widget class="QComboBox" name="combo_sound"> | 443 | <widget class="QComboBox" name="combo_sound"> |
| 437 | <item> | 444 | <item> |
| @@ -476,6 +483,13 @@ | |||
| 476 | </property> | 483 | </property> |
| 477 | </widget> | 484 | </widget> |
| 478 | </item> | 485 | </item> |
| 486 | <item row="7" column="1"> | ||
| 487 | <widget class="QLineEdit" name="device_name_edit"> | ||
| 488 | <property name="maxLength"> | ||
| 489 | <number>128</number> | ||
| 490 | </property> | ||
| 491 | </widget> | ||
| 492 | </item> | ||
| 479 | <item row="6" column="1"> | 493 | <item row="6" column="1"> |
| 480 | <widget class="QLineEdit" name="rng_seed_edit"> | 494 | <widget class="QLineEdit" name="rng_seed_edit"> |
| 481 | <property name="sizePolicy"> | 495 | <property name="sizePolicy"> |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 5c33c1b0f..22aa19c56 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -554,6 +554,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri | |||
| 554 | QAction* dump_romfs_sdmc = dump_romfs_menu->addAction(tr("Dump RomFS to SDMC")); | 554 | QAction* dump_romfs_sdmc = dump_romfs_menu->addAction(tr("Dump RomFS to SDMC")); |
| 555 | QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); | 555 | QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); |
| 556 | QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry")); | 556 | QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry")); |
| 557 | #ifndef WIN32 | ||
| 558 | QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut")); | ||
| 559 | QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop")); | ||
| 560 | QAction* create_applications_menu_shortcut = | ||
| 561 | shortcut_menu->addAction(tr("Add to Applications Menu")); | ||
| 562 | #endif | ||
| 557 | context_menu.addSeparator(); | 563 | context_menu.addSeparator(); |
| 558 | QAction* properties = context_menu.addAction(tr("Properties")); | 564 | QAction* properties = context_menu.addAction(tr("Properties")); |
| 559 | 565 | ||
| @@ -619,6 +625,14 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri | |||
| 619 | connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() { | 625 | connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() { |
| 620 | emit NavigateToGamedbEntryRequested(program_id, compatibility_list); | 626 | emit NavigateToGamedbEntryRequested(program_id, compatibility_list); |
| 621 | }); | 627 | }); |
| 628 | #ifndef WIN32 | ||
| 629 | connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() { | ||
| 630 | emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop); | ||
| 631 | }); | ||
| 632 | connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() { | ||
| 633 | emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications); | ||
| 634 | }); | ||
| 635 | #endif | ||
| 622 | connect(properties, &QAction::triggered, | 636 | connect(properties, &QAction::triggered, |
| 623 | [this, path]() { emit OpenPerGameGeneralRequested(path); }); | 637 | [this, path]() { emit OpenPerGameGeneralRequested(path); }); |
| 624 | }; | 638 | }; |
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index cdf085019..f7ff93ed9 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -52,6 +52,11 @@ enum class DumpRomFSTarget { | |||
| 52 | SDMC, | 52 | SDMC, |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | enum class GameListShortcutTarget { | ||
| 56 | Desktop, | ||
| 57 | Applications, | ||
| 58 | }; | ||
| 59 | |||
| 55 | enum class InstalledEntryType { | 60 | enum class InstalledEntryType { |
| 56 | Game, | 61 | Game, |
| 57 | Update, | 62 | Update, |
| @@ -108,6 +113,8 @@ signals: | |||
| 108 | const std::string& game_path); | 113 | const std::string& game_path); |
| 109 | void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target); | 114 | void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target); |
| 110 | void CopyTIDRequested(u64 program_id); | 115 | void CopyTIDRequested(u64 program_id); |
| 116 | void CreateShortcut(u64 program_id, const std::string& game_path, | ||
| 117 | GameListShortcutTarget target); | ||
| 111 | void NavigateToGamedbEntryRequested(u64 program_id, | 118 | void NavigateToGamedbEntryRequested(u64 program_id, |
| 112 | const CompatibilityList& compatibility_list); | 119 | const CompatibilityList& compatibility_list); |
| 113 | void OpenPerGameGeneralRequested(const std::string& file); | 120 | void OpenPerGameGeneralRequested(const std::string& file); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 6c204416f..2e6c2311a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | #include <cinttypes> | 4 | #include <cinttypes> |
| 5 | #include <clocale> | 5 | #include <clocale> |
| 6 | #include <cmath> | 6 | #include <cmath> |
| 7 | #include <fstream> | ||
| 8 | #include <iostream> | ||
| 7 | #include <memory> | 9 | #include <memory> |
| 8 | #include <thread> | 10 | #include <thread> |
| 9 | #ifdef __APPLE__ | 11 | #ifdef __APPLE__ |
| @@ -1249,6 +1251,7 @@ void GMainWindow::ConnectWidgetEvents() { | |||
| 1249 | connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID); | 1251 | connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID); |
| 1250 | connect(game_list, &GameList::NavigateToGamedbEntryRequested, this, | 1252 | connect(game_list, &GameList::NavigateToGamedbEntryRequested, this, |
| 1251 | &GMainWindow::OnGameListNavigateToGamedbEntry); | 1253 | &GMainWindow::OnGameListNavigateToGamedbEntry); |
| 1254 | connect(game_list, &GameList::CreateShortcut, this, &GMainWindow::OnGameListCreateShortcut); | ||
| 1252 | connect(game_list, &GameList::AddDirectory, this, &GMainWindow::OnGameListAddDirectory); | 1255 | connect(game_list, &GameList::AddDirectory, this, &GMainWindow::OnGameListAddDirectory); |
| 1253 | connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this, | 1256 | connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this, |
| 1254 | &GMainWindow::OnGameListAddDirectory); | 1257 | &GMainWindow::OnGameListAddDirectory); |
| @@ -1707,9 +1710,6 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
| 1707 | system->RegisterExecuteProgramCallback( | 1710 | system->RegisterExecuteProgramCallback( |
| 1708 | [this](std::size_t program_index_) { render_window->ExecuteProgram(program_index_); }); | 1711 | [this](std::size_t program_index_) { render_window->ExecuteProgram(program_index_); }); |
| 1709 | 1712 | ||
| 1710 | // Register an Exit callback such that Core can exit the currently running application. | ||
| 1711 | system->RegisterExitCallback([this]() { render_window->Exit(); }); | ||
| 1712 | |||
| 1713 | connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); | 1713 | connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); |
| 1714 | connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity); | 1714 | connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity); |
| 1715 | // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views | 1715 | // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views |
| @@ -1796,12 +1796,16 @@ void GMainWindow::ShutdownGame() { | |||
| 1796 | system->SetShuttingDown(true); | 1796 | system->SetShuttingDown(true); |
| 1797 | system->DetachDebugger(); | 1797 | system->DetachDebugger(); |
| 1798 | discord_rpc->Pause(); | 1798 | discord_rpc->Pause(); |
| 1799 | emu_thread->RequestStop(); | 1799 | |
| 1800 | RequestGameExit(); | ||
| 1800 | 1801 | ||
| 1801 | emit EmulationStopping(); | 1802 | emit EmulationStopping(); |
| 1802 | 1803 | ||
| 1803 | // Wait for emulation thread to complete and delete it | 1804 | // Wait for emulation thread to complete and delete it |
| 1804 | emu_thread->wait(); | 1805 | if (!emu_thread->wait(5000)) { |
| 1806 | emu_thread->ForceStop(); | ||
| 1807 | emu_thread->wait(); | ||
| 1808 | } | ||
| 1805 | emu_thread = nullptr; | 1809 | emu_thread = nullptr; |
| 1806 | 1810 | ||
| 1807 | emulation_running = false; | 1811 | emulation_running = false; |
| @@ -2378,6 +2382,152 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, | |||
| 2378 | QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory)); | 2382 | QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory)); |
| 2379 | } | 2383 | } |
| 2380 | 2384 | ||
| 2385 | void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, | ||
| 2386 | GameListShortcutTarget target) { | ||
| 2387 | // Get path to yuzu executable | ||
| 2388 | const QStringList args = QApplication::arguments(); | ||
| 2389 | std::filesystem::path yuzu_command = args[0].toStdString(); | ||
| 2390 | |||
| 2391 | #if defined(__linux__) || defined(__FreeBSD__) | ||
| 2392 | // If relative path, make it an absolute path | ||
| 2393 | if (yuzu_command.c_str()[0] == '.') { | ||
| 2394 | yuzu_command = Common::FS::GetCurrentDir() / yuzu_command; | ||
| 2395 | } | ||
| 2396 | |||
| 2397 | #if defined(__linux__) | ||
| 2398 | // Warn once if we are making a shortcut to a volatile AppImage | ||
| 2399 | const std::string appimage_ending = | ||
| 2400 | std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage"); | ||
| 2401 | if (yuzu_command.string().ends_with(appimage_ending) && | ||
| 2402 | !UISettings::values.shortcut_already_warned) { | ||
| 2403 | if (QMessageBox::warning(this, tr("Create Shortcut"), | ||
| 2404 | tr("This will create a shortcut to the current AppImage. This may " | ||
| 2405 | "not work well if you update. Continue?"), | ||
| 2406 | QMessageBox::StandardButton::Ok | | ||
| 2407 | QMessageBox::StandardButton::Cancel) == | ||
| 2408 | QMessageBox::StandardButton::Cancel) { | ||
| 2409 | return; | ||
| 2410 | } | ||
| 2411 | UISettings::values.shortcut_already_warned = true; | ||
| 2412 | } | ||
| 2413 | #endif // __linux__ | ||
| 2414 | #endif // __linux__ || __FreeBSD__ | ||
| 2415 | |||
| 2416 | std::filesystem::path target_directory{}; | ||
| 2417 | // Determine target directory for shortcut | ||
| 2418 | #if defined(__linux__) || defined(__FreeBSD__) | ||
| 2419 | const char* home = std::getenv("HOME"); | ||
| 2420 | const std::filesystem::path home_path = (home == nullptr ? "~" : home); | ||
| 2421 | const char* xdg_data_home = std::getenv("XDG_DATA_HOME"); | ||
| 2422 | |||
| 2423 | if (target == GameListShortcutTarget::Desktop) { | ||
| 2424 | target_directory = home_path / "Desktop"; | ||
| 2425 | if (!Common::FS::IsDir(target_directory)) { | ||
| 2426 | QMessageBox::critical( | ||
| 2427 | this, tr("Create Shortcut"), | ||
| 2428 | tr("Cannot create shortcut on desktop. Path \"%1\" does not exist.") | ||
| 2429 | .arg(QString::fromStdString(target_directory)), | ||
| 2430 | QMessageBox::StandardButton::Ok); | ||
| 2431 | return; | ||
| 2432 | } | ||
| 2433 | } else if (target == GameListShortcutTarget::Applications) { | ||
| 2434 | target_directory = (xdg_data_home == nullptr ? home_path / ".local/share" : xdg_data_home) / | ||
| 2435 | "applications"; | ||
| 2436 | if (!Common::FS::CreateDirs(target_directory)) { | ||
| 2437 | QMessageBox::critical(this, tr("Create Shortcut"), | ||
| 2438 | tr("Cannot create shortcut in applications menu. Path \"%1\" " | ||
| 2439 | "does not exist and cannot be created.") | ||
| 2440 | .arg(QString::fromStdString(target_directory)), | ||
| 2441 | QMessageBox::StandardButton::Ok); | ||
| 2442 | return; | ||
| 2443 | } | ||
| 2444 | } | ||
| 2445 | #endif | ||
| 2446 | |||
| 2447 | const std::string game_file_name = std::filesystem::path(game_path).filename().string(); | ||
| 2448 | // Determine full paths for icon and shortcut | ||
| 2449 | #if defined(__linux__) || defined(__FreeBSD__) | ||
| 2450 | std::filesystem::path system_icons_path = | ||
| 2451 | (xdg_data_home == nullptr ? home_path / ".local/share/" : xdg_data_home) / | ||
| 2452 | "icons/hicolor/256x256"; | ||
| 2453 | if (!Common::FS::CreateDirs(system_icons_path)) { | ||
| 2454 | QMessageBox::critical( | ||
| 2455 | this, tr("Create Icon"), | ||
| 2456 | tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") | ||
| 2457 | .arg(QString::fromStdString(system_icons_path)), | ||
| 2458 | QMessageBox::StandardButton::Ok); | ||
| 2459 | return; | ||
| 2460 | } | ||
| 2461 | std::filesystem::path icon_path = | ||
| 2462 | system_icons_path / (program_id == 0 ? fmt::format("yuzu-{}.png", game_file_name) | ||
| 2463 | : fmt::format("yuzu-{:016X}.png", program_id)); | ||
| 2464 | const std::filesystem::path shortcut_path = | ||
| 2465 | target_directory / (program_id == 0 ? fmt::format("yuzu-{}.desktop", game_file_name) | ||
| 2466 | : fmt::format("yuzu-{:016X}.desktop", program_id)); | ||
| 2467 | #else | ||
| 2468 | const std::filesystem::path icon_path{}; | ||
| 2469 | const std::filesystem::path shortcut_path{}; | ||
| 2470 | #endif | ||
| 2471 | |||
| 2472 | // Get title from game file | ||
| 2473 | const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), | ||
| 2474 | system->GetContentProvider()}; | ||
| 2475 | const auto control = pm.GetControlMetadata(); | ||
| 2476 | const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); | ||
| 2477 | |||
| 2478 | std::string title{fmt::format("{:016X}", program_id)}; | ||
| 2479 | |||
| 2480 | if (control.first != nullptr) { | ||
| 2481 | title = control.first->GetApplicationName(); | ||
| 2482 | } else { | ||
| 2483 | loader->ReadTitle(title); | ||
| 2484 | } | ||
| 2485 | |||
| 2486 | // Get icon from game file | ||
| 2487 | std::vector<u8> icon_image_file{}; | ||
| 2488 | if (control.second != nullptr) { | ||
| 2489 | icon_image_file = control.second->ReadAllBytes(); | ||
| 2490 | } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) { | ||
| 2491 | LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path); | ||
| 2492 | } | ||
| 2493 | |||
| 2494 | QImage icon_jpeg = | ||
| 2495 | QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size())); | ||
| 2496 | #if defined(__linux__) || defined(__FreeBSD__) | ||
| 2497 | // Convert and write the icon as a PNG | ||
| 2498 | if (!icon_jpeg.save(QString::fromStdString(icon_path.string()))) { | ||
| 2499 | LOG_ERROR(Frontend, "Could not write icon as PNG to file"); | ||
| 2500 | } else { | ||
| 2501 | LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string()); | ||
| 2502 | } | ||
| 2503 | #endif // __linux__ | ||
| 2504 | |||
| 2505 | #if defined(__linux__) || defined(__FreeBSD__) | ||
| 2506 | const std::string comment = | ||
| 2507 | tr("Start %1 with the yuzu Emulator").arg(QString::fromStdString(title)).toStdString(); | ||
| 2508 | const std::string arguments = fmt::format("-g \"{:s}\"", game_path); | ||
| 2509 | const std::string categories = "Game;Emulator;Qt;"; | ||
| 2510 | const std::string keywords = "Switch;Nintendo;"; | ||
| 2511 | #else | ||
| 2512 | const std::string comment{}; | ||
| 2513 | const std::string arguments{}; | ||
| 2514 | const std::string categories{}; | ||
| 2515 | const std::string keywords{}; | ||
| 2516 | #endif | ||
| 2517 | if (!CreateShortcut(shortcut_path.string(), title, comment, icon_path.string(), | ||
| 2518 | yuzu_command.string(), arguments, categories, keywords)) { | ||
| 2519 | QMessageBox::critical(this, tr("Create Shortcut"), | ||
| 2520 | tr("Failed to create a shortcut at %1") | ||
| 2521 | .arg(QString::fromStdString(shortcut_path.string()))); | ||
| 2522 | return; | ||
| 2523 | } | ||
| 2524 | |||
| 2525 | LOG_INFO(Frontend, "Wrote a shortcut to {}", shortcut_path.string()); | ||
| 2526 | QMessageBox::information( | ||
| 2527 | this, tr("Create Shortcut"), | ||
| 2528 | tr("Successfully created a shortcut to %1").arg(QString::fromStdString(title))); | ||
| 2529 | } | ||
| 2530 | |||
| 2381 | void GMainWindow::OnGameListOpenDirectory(const QString& directory) { | 2531 | void GMainWindow::OnGameListOpenDirectory(const QString& directory) { |
| 2382 | std::filesystem::path fs_path; | 2532 | std::filesystem::path fs_path; |
| 2383 | if (directory == QStringLiteral("SDMC")) { | 2533 | if (directory == QStringLiteral("SDMC")) { |
| @@ -2915,9 +3065,15 @@ static QScreen* GuessCurrentScreen(QWidget* window) { | |||
| 2915 | }); | 3065 | }); |
| 2916 | } | 3066 | } |
| 2917 | 3067 | ||
| 3068 | bool GMainWindow::UsingExclusiveFullscreen() { | ||
| 3069 | return Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive || | ||
| 3070 | QGuiApplication::platformName() == QStringLiteral("wayland") || | ||
| 3071 | QGuiApplication::platformName() == QStringLiteral("wayland-egl"); | ||
| 3072 | } | ||
| 3073 | |||
| 2918 | void GMainWindow::ShowFullscreen() { | 3074 | void GMainWindow::ShowFullscreen() { |
| 2919 | const auto show_fullscreen = [](QWidget* window) { | 3075 | const auto show_fullscreen = [this](QWidget* window) { |
| 2920 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { | 3076 | if (UsingExclusiveFullscreen()) { |
| 2921 | window->showFullScreen(); | 3077 | window->showFullScreen(); |
| 2922 | return; | 3078 | return; |
| 2923 | } | 3079 | } |
| @@ -2945,7 +3101,7 @@ void GMainWindow::ShowFullscreen() { | |||
| 2945 | 3101 | ||
| 2946 | void GMainWindow::HideFullscreen() { | 3102 | void GMainWindow::HideFullscreen() { |
| 2947 | if (ui->action_Single_Window_Mode->isChecked()) { | 3103 | if (ui->action_Single_Window_Mode->isChecked()) { |
| 2948 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { | 3104 | if (UsingExclusiveFullscreen()) { |
| 2949 | showNormal(); | 3105 | showNormal(); |
| 2950 | restoreGeometry(UISettings::values.geometry); | 3106 | restoreGeometry(UISettings::values.geometry); |
| 2951 | } else { | 3107 | } else { |
| @@ -2959,7 +3115,7 @@ void GMainWindow::HideFullscreen() { | |||
| 2959 | statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked()); | 3115 | statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked()); |
| 2960 | ui->menubar->show(); | 3116 | ui->menubar->show(); |
| 2961 | } else { | 3117 | } else { |
| 2962 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { | 3118 | if (UsingExclusiveFullscreen()) { |
| 2963 | render_window->showNormal(); | 3119 | render_window->showNormal(); |
| 2964 | render_window->restoreGeometry(UISettings::values.renderwindow_geometry); | 3120 | render_window->restoreGeometry(UISettings::values.renderwindow_geometry); |
| 2965 | } else { | 3121 | } else { |
| @@ -3296,6 +3452,38 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file | |||
| 3296 | } | 3452 | } |
| 3297 | } | 3453 | } |
| 3298 | 3454 | ||
| 3455 | bool GMainWindow::CreateShortcut(const std::string& shortcut_path, const std::string& title, | ||
| 3456 | const std::string& comment, const std::string& icon_path, | ||
| 3457 | const std::string& command, const std::string& arguments, | ||
| 3458 | const std::string& categories, const std::string& keywords) { | ||
| 3459 | #if defined(__linux__) || defined(__FreeBSD__) | ||
| 3460 | // This desktop file template was writting referencing | ||
| 3461 | // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html | ||
| 3462 | std::string shortcut_contents{}; | ||
| 3463 | shortcut_contents.append("[Desktop Entry]\n"); | ||
| 3464 | shortcut_contents.append("Type=Application\n"); | ||
| 3465 | shortcut_contents.append("Version=1.0\n"); | ||
| 3466 | shortcut_contents.append(fmt::format("Name={:s}\n", title)); | ||
| 3467 | shortcut_contents.append(fmt::format("Comment={:s}\n", comment)); | ||
| 3468 | shortcut_contents.append(fmt::format("Icon={:s}\n", icon_path)); | ||
| 3469 | shortcut_contents.append(fmt::format("TryExec={:s}\n", command)); | ||
| 3470 | shortcut_contents.append(fmt::format("Exec={:s} {:s}\n", command, arguments)); | ||
| 3471 | shortcut_contents.append(fmt::format("Categories={:s}\n", categories)); | ||
| 3472 | shortcut_contents.append(fmt::format("Keywords={:s}\n", keywords)); | ||
| 3473 | |||
| 3474 | std::ofstream shortcut_stream(shortcut_path); | ||
| 3475 | if (!shortcut_stream.is_open()) { | ||
| 3476 | LOG_WARNING(Common, "Failed to create file {:s}", shortcut_path); | ||
| 3477 | return false; | ||
| 3478 | } | ||
| 3479 | shortcut_stream << shortcut_contents; | ||
| 3480 | shortcut_stream.close(); | ||
| 3481 | |||
| 3482 | return true; | ||
| 3483 | #endif | ||
| 3484 | return false; | ||
| 3485 | } | ||
| 3486 | |||
| 3299 | void GMainWindow::OnLoadAmiibo() { | 3487 | void GMainWindow::OnLoadAmiibo() { |
| 3300 | if (emu_thread == nullptr || !emu_thread->IsRunning()) { | 3488 | if (emu_thread == nullptr || !emu_thread->IsRunning()) { |
| 3301 | return; | 3489 | return; |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 62d629973..1047ba276 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -38,6 +38,7 @@ class QProgressDialog; | |||
| 38 | class WaitTreeWidget; | 38 | class WaitTreeWidget; |
| 39 | enum class GameListOpenTarget; | 39 | enum class GameListOpenTarget; |
| 40 | enum class GameListRemoveTarget; | 40 | enum class GameListRemoveTarget; |
| 41 | enum class GameListShortcutTarget; | ||
| 41 | enum class DumpRomFSTarget; | 42 | enum class DumpRomFSTarget; |
| 42 | enum class InstalledEntryType; | 43 | enum class InstalledEntryType; |
| 43 | class GameListPlaceholder; | 44 | class GameListPlaceholder; |
| @@ -293,6 +294,8 @@ private slots: | |||
| 293 | void OnGameListCopyTID(u64 program_id); | 294 | void OnGameListCopyTID(u64 program_id); |
| 294 | void OnGameListNavigateToGamedbEntry(u64 program_id, | 295 | void OnGameListNavigateToGamedbEntry(u64 program_id, |
| 295 | const CompatibilityList& compatibility_list); | 296 | const CompatibilityList& compatibility_list); |
| 297 | void OnGameListCreateShortcut(u64 program_id, const std::string& game_path, | ||
| 298 | GameListShortcutTarget target); | ||
| 296 | void OnGameListOpenDirectory(const QString& directory); | 299 | void OnGameListOpenDirectory(const QString& directory); |
| 297 | void OnGameListAddDirectory(); | 300 | void OnGameListAddDirectory(); |
| 298 | void OnGameListShowList(bool show); | 301 | void OnGameListShowList(bool show); |
| @@ -320,6 +323,7 @@ private slots: | |||
| 320 | void OnDisplayTitleBars(bool); | 323 | void OnDisplayTitleBars(bool); |
| 321 | void InitializeHotkeys(); | 324 | void InitializeHotkeys(); |
| 322 | void ToggleFullscreen(); | 325 | void ToggleFullscreen(); |
| 326 | bool UsingExclusiveFullscreen(); | ||
| 323 | void ShowFullscreen(); | 327 | void ShowFullscreen(); |
| 324 | void HideFullscreen(); | 328 | void HideFullscreen(); |
| 325 | void ToggleWindowMode(); | 329 | void ToggleWindowMode(); |
| @@ -365,6 +369,10 @@ private: | |||
| 365 | bool CheckDarkMode(); | 369 | bool CheckDarkMode(); |
| 366 | 370 | ||
| 367 | QString GetTasStateDescription() const; | 371 | QString GetTasStateDescription() const; |
| 372 | bool CreateShortcut(const std::string& shortcut_path, const std::string& title, | ||
| 373 | const std::string& comment, const std::string& icon_path, | ||
| 374 | const std::string& command, const std::string& arguments, | ||
| 375 | const std::string& categories, const std::string& keywords); | ||
| 368 | 376 | ||
| 369 | std::unique_ptr<Ui::MainWindow> ui; | 377 | std::unique_ptr<Ui::MainWindow> ui; |
| 370 | 378 | ||
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 452038cd9..2006b883e 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -138,6 +138,7 @@ struct Values { | |||
| 138 | 138 | ||
| 139 | bool configuration_applied; | 139 | bool configuration_applied; |
| 140 | bool reset_to_defaults; | 140 | bool reset_to_defaults; |
| 141 | bool shortcut_already_warned{false}; | ||
| 141 | Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"}; | 142 | Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"}; |
| 142 | }; | 143 | }; |
| 143 | 144 | ||
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 { | |||
| 115 | 115 | ||
| 116 | void EmuWindow_SDL2::OnResize() { | 116 | void EmuWindow_SDL2::OnResize() { |
| 117 | int width, height; | 117 | int width, height; |
| 118 | SDL_GetWindowSize(render_window, &width, &height); | 118 | SDL_GL_GetDrawableSize(render_window, &width, &height); |
| 119 | UpdateCurrentFramebufferLayout(width, height); | 119 | UpdateCurrentFramebufferLayout(width, height); |
| 120 | } | 120 | } |
| 121 | 121 | ||
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 | |||
| 104 | exit(1); | 104 | exit(1); |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | strict_context_required = strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0; | ||
| 108 | |||
| 107 | SetWindowIcon(); | 109 | SetWindowIcon(); |
| 108 | 110 | ||
| 109 | if (fullscreen) { | 111 | if (fullscreen) { |