summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/device/audio_buffers.h8
-rw-r--r--src/audio_core/device/device_session.cpp6
-rw-r--r--src/audio_core/device/device_session.h5
-rw-r--r--src/audio_core/in/audio_in_system.cpp7
-rw-r--r--src/audio_core/out/audio_out_system.cpp7
-rw-r--r--src/common/settings.cpp1
-rw-r--r--src/common/settings.h1
-rw-r--r--src/core/frontend/emu_window.h6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp22
-rw-r--r--src/core/hle/kernel/k_process.cpp11
-rw-r--r--src/core/hle/kernel/k_process.h3
-rw-r--r--src/core/hle/kernel/svc.cpp130
-rw-r--r--src/core/hle/service/audio/audin_u.cpp5
-rw-r--r--src/core/hle/service/audio/audout_u.cpp10
-rw-r--r--src/core/hle/service/audio/audren_u.cpp15
-rw-r--r--src/core/hle/service/set/set.cpp9
-rw-r--r--src/core/hle/service/set/set.h1
-rw-r--r--src/core/hle/service/set/set_sys.cpp10
-rw-r--r--src/core/hle/service/set/set_sys.h1
-rw-r--r--src/input_common/drivers/camera.cpp2
-rw-r--r--src/input_common/drivers/camera.h4
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp2
-rw-r--r--src/video_core/gpu.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_device.h8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp76
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h1
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp4
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp14
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp15
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h14
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp7
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h10
-rw-r--r--src/yuzu/bootmanager.cpp38
-rw-r--r--src/yuzu/bootmanager.h8
-rw-r--r--src/yuzu/configuration/config.cpp3
-rw-r--r--src/yuzu/configuration/configure_system.cpp4
-rw-r--r--src/yuzu/configuration/configure_system.ui14
-rw-r--r--src/yuzu/game_list.cpp14
-rw-r--r--src/yuzu/game_list.h7
-rw-r--r--src/yuzu/main.cpp206
-rw-r--r--src/yuzu/main.h8
-rw-r--r--src/yuzu/uisettings.h1
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp2
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
76void DeviceSession::ClearBuffers() {
77 if (stream) {
78 stream->ClearQueue();
79 }
80}
81
76void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const { 82void 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() {
23void System::Finalize() { 23void System::Finalize() {
24 Stop(); 24 Stop();
25 session->Finalize(); 25 session->Finalize();
26 buffer_event->Signal();
27} 26}
28 27
29void System::StartSession() { 28void 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
140void System::ReleaseBuffers() { 143void 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() {
24void System::Finalize() { 24void System::Finalize() {
25 Stop(); 25 Stop();
26 session->Finalize(); 26 session->Finalize();
27 buffer_event->Signal();
28} 27}
29 28
30std::string_view System::GetDefaultOutputDeviceName() const { 29std::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
140void System::ReleaseBuffers() { 143void 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
210private: 216private:
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
320std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { 328std::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
342std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, 348std::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
288u64 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
288Result KProcess::Reset() { 299Result 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
205AudInU::AudInU(Core::System& system_) 205AudInU::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
222AudOutU::AudOutU(Core::System& system_) 223AudOutU::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> {
242public: 243public:
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
420AudRenU::AudRenU(Core::System& system_) 423AudRenU::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
194void 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
194SET::SET(Core::System& system_) : ServiceFramework{system_, "set"} { 201SET::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
180void 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
179SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { 187SET_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
20void Camera::SetCameraData(std::size_t width, std::size_t height, std::vector<u32> data) { 20void 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
8namespace InputCommon { 10namespace InputCommon {
@@ -15,7 +17,7 @@ class Camera final : public InputEngine {
15public: 17public:
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
115Device::Device() { 115Device::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
10namespace Settings { 11namespace Settings {
@@ -15,7 +16,7 @@ namespace OpenGL {
15 16
16class Device { 17class Device {
17public: 18public:
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
176private: 181private:
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
286void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, 286void 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
347PipelineCache::~PipelineCache() = default; 356PipelineCache::~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
70Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, u32 width, 70Swapchain::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
76Swapchain::~Swapchain() = default; 76Swapchain::~Swapchain() = default;
77 77
78void Swapchain::Create(u32 width, u32 height, bool srgb) { 78void 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
151void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height, 153void 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
83private: 91private:
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
1410void Device::SetupProperties() { 1415void 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
376private: 384private:
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
47static Core::Frontend::WindowSystemType GetWindowSystemType();
48
47EmuThread::EmuThread(Core::System& system_) : system{system_} {} 49EmuThread::EmuThread(Core::System& system_) : system{system_} {}
48 50
49EmuThread::~EmuThread() = default; 51EmuThread::~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
807void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { 822void 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
953bool GRenderWindow::InitializeOpenGL() { 965bool 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
55enum class GameListShortcutTarget {
56 Desktop,
57 Applications,
58};
59
55enum class InstalledEntryType { 60enum 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
2385void 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
2381void GMainWindow::OnGameListOpenDirectory(const QString& directory) { 2531void 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
3068bool 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
2918void GMainWindow::ShowFullscreen() { 3074void 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
2946void GMainWindow::HideFullscreen() { 3102void 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
3455bool 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
3299void GMainWindow::OnLoadAmiibo() { 3487void 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;
38class WaitTreeWidget; 38class WaitTreeWidget;
39enum class GameListOpenTarget; 39enum class GameListOpenTarget;
40enum class GameListRemoveTarget; 40enum class GameListRemoveTarget;
41enum class GameListShortcutTarget;
41enum class DumpRomFSTarget; 42enum class DumpRomFSTarget;
42enum class InstalledEntryType; 43enum class InstalledEntryType;
43class GameListPlaceholder; 44class 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
116void EmuWindow_SDL2::OnResize() { 116void 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) {