diff options
25 files changed, 260 insertions, 56 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2da983cad..7bb88c8ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt | |||
| @@ -134,7 +134,7 @@ else() | |||
| 134 | endif() | 134 | endif() |
| 135 | 135 | ||
| 136 | # GCC bugs | 136 | # GCC bugs |
| 137 | if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") | 137 | if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "11" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") |
| 138 | # These diagnostics would be great if they worked, but are just completely broken | 138 | # These diagnostics would be great if they worked, but are just completely broken |
| 139 | # and produce bogus errors on external libraries like fmt. | 139 | # and produce bogus errors on external libraries like fmt. |
| 140 | add_compile_options( | 140 | add_compile_options( |
diff --git a/src/core/hle/kernel/k_hardware_timer.h b/src/core/hle/kernel/k_hardware_timer.h index 00bef6ea1..27f43cd19 100644 --- a/src/core/hle/kernel/k_hardware_timer.h +++ b/src/core/hle/kernel/k_hardware_timer.h | |||
| @@ -19,13 +19,7 @@ public: | |||
| 19 | void Initialize(); | 19 | void Initialize(); |
| 20 | void Finalize(); | 20 | void Finalize(); |
| 21 | 21 | ||
| 22 | s64 GetCount() const { | 22 | s64 GetTick() const; |
| 23 | return GetTick(); | ||
| 24 | } | ||
| 25 | |||
| 26 | void RegisterTask(KTimerTask* task, s64 time_from_now) { | ||
| 27 | this->RegisterAbsoluteTask(task, GetTick() + time_from_now); | ||
| 28 | } | ||
| 29 | 23 | ||
| 30 | void RegisterAbsoluteTask(KTimerTask* task, s64 task_time) { | 24 | void RegisterAbsoluteTask(KTimerTask* task, s64 task_time) { |
| 31 | KScopedDisableDispatch dd{m_kernel}; | 25 | KScopedDisableDispatch dd{m_kernel}; |
| @@ -42,7 +36,6 @@ private: | |||
| 42 | void EnableInterrupt(s64 wakeup_time); | 36 | void EnableInterrupt(s64 wakeup_time); |
| 43 | void DisableInterrupt(); | 37 | void DisableInterrupt(); |
| 44 | bool GetInterruptEnabled(); | 38 | bool GetInterruptEnabled(); |
| 45 | s64 GetTick() const; | ||
| 46 | void DoTask(); | 39 | void DoTask(); |
| 47 | 40 | ||
| 48 | private: | 41 | private: |
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index fcee26a29..d8a63aaf8 100644 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include "common/overflow.h" | 5 | #include "common/overflow.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 8 | #include "core/hle/kernel/k_resource_limit.h" | 9 | #include "core/hle/kernel/k_resource_limit.h" |
| 9 | #include "core/hle/kernel/svc_results.h" | 10 | #include "core/hle/kernel/svc_results.h" |
| 10 | 11 | ||
| @@ -15,9 +16,7 @@ KResourceLimit::KResourceLimit(KernelCore& kernel) | |||
| 15 | : KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock{m_kernel}, m_cond_var{m_kernel} {} | 16 | : KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock{m_kernel}, m_cond_var{m_kernel} {} |
| 16 | KResourceLimit::~KResourceLimit() = default; | 17 | KResourceLimit::~KResourceLimit() = default; |
| 17 | 18 | ||
| 18 | void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing) { | 19 | void KResourceLimit::Initialize() {} |
| 19 | m_core_timing = core_timing; | ||
| 20 | } | ||
| 21 | 20 | ||
| 22 | void KResourceLimit::Finalize() {} | 21 | void KResourceLimit::Finalize() {} |
| 23 | 22 | ||
| @@ -86,7 +85,7 @@ Result KResourceLimit::SetLimitValue(LimitableResource which, s64 value) { | |||
| 86 | } | 85 | } |
| 87 | 86 | ||
| 88 | bool KResourceLimit::Reserve(LimitableResource which, s64 value) { | 87 | bool KResourceLimit::Reserve(LimitableResource which, s64 value) { |
| 89 | return Reserve(which, value, m_core_timing->GetGlobalTimeNs().count() + DefaultTimeout); | 88 | return Reserve(which, value, m_kernel.HardwareTimer().GetTick() + DefaultTimeout); |
| 90 | } | 89 | } |
| 91 | 90 | ||
| 92 | bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { | 91 | bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { |
| @@ -117,7 +116,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { | |||
| 117 | } | 116 | } |
| 118 | 117 | ||
| 119 | if (m_current_hints[index] + value <= m_limit_values[index] && | 118 | if (m_current_hints[index] + value <= m_limit_values[index] && |
| 120 | (timeout < 0 || m_core_timing->GetGlobalTimeNs().count() < timeout)) { | 119 | (timeout < 0 || m_kernel.HardwareTimer().GetTick() < timeout)) { |
| 121 | m_waiter_count++; | 120 | m_waiter_count++; |
| 122 | m_cond_var.Wait(std::addressof(m_lock), timeout, false); | 121 | m_cond_var.Wait(std::addressof(m_lock), timeout, false); |
| 123 | m_waiter_count--; | 122 | m_waiter_count--; |
| @@ -154,7 +153,7 @@ void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) { | |||
| 154 | 153 | ||
| 155 | KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size) { | 154 | KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size) { |
| 156 | auto* resource_limit = KResourceLimit::Create(system.Kernel()); | 155 | auto* resource_limit = KResourceLimit::Create(system.Kernel()); |
| 157 | resource_limit->Initialize(std::addressof(system.CoreTiming())); | 156 | resource_limit->Initialize(); |
| 158 | 157 | ||
| 159 | // Initialize default resource limit values. | 158 | // Initialize default resource limit values. |
| 160 | // TODO(bunnei): These values are the system defaults, the limits for service processes are | 159 | // TODO(bunnei): These values are the system defaults, the limits for service processes are |
diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h index 15e69af56..b733ec8f8 100644 --- a/src/core/hle/kernel/k_resource_limit.h +++ b/src/core/hle/kernel/k_resource_limit.h | |||
| @@ -31,7 +31,7 @@ public: | |||
| 31 | explicit KResourceLimit(KernelCore& kernel); | 31 | explicit KResourceLimit(KernelCore& kernel); |
| 32 | ~KResourceLimit() override; | 32 | ~KResourceLimit() override; |
| 33 | 33 | ||
| 34 | void Initialize(const Core::Timing::CoreTiming* core_timing); | 34 | void Initialize(); |
| 35 | void Finalize() override; | 35 | void Finalize() override; |
| 36 | 36 | ||
| 37 | s64 GetLimitValue(LimitableResource which) const; | 37 | s64 GetLimitValue(LimitableResource which) const; |
| @@ -57,7 +57,6 @@ private: | |||
| 57 | mutable KLightLock m_lock; | 57 | mutable KLightLock m_lock; |
| 58 | s32 m_waiter_count{}; | 58 | s32 m_waiter_count{}; |
| 59 | KLightConditionVariable m_cond_var; | 59 | KLightConditionVariable m_cond_var; |
| 60 | const Core::Timing::CoreTiming* m_core_timing{}; | ||
| 61 | }; | 60 | }; |
| 62 | 61 | ||
| 63 | KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size); | 62 | KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size); |
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index c485022f5..b62415da7 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h | |||
| @@ -28,7 +28,7 @@ public: | |||
| 28 | ~KScopedSchedulerLockAndSleep() { | 28 | ~KScopedSchedulerLockAndSleep() { |
| 29 | // Register the sleep. | 29 | // Register the sleep. |
| 30 | if (m_timeout_tick > 0) { | 30 | if (m_timeout_tick > 0) { |
| 31 | m_timer->RegisterTask(m_thread, m_timeout_tick); | 31 | m_timer->RegisterAbsoluteTask(m_thread, m_timeout_tick); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | // Unlock the scheduler. | 34 | // Unlock the scheduler. |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ebe7582c6..a1134b7e2 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -231,7 +231,7 @@ struct KernelCore::Impl { | |||
| 231 | void InitializeSystemResourceLimit(KernelCore& kernel, | 231 | void InitializeSystemResourceLimit(KernelCore& kernel, |
| 232 | const Core::Timing::CoreTiming& core_timing) { | 232 | const Core::Timing::CoreTiming& core_timing) { |
| 233 | system_resource_limit = KResourceLimit::Create(system.Kernel()); | 233 | system_resource_limit = KResourceLimit::Create(system.Kernel()); |
| 234 | system_resource_limit->Initialize(&core_timing); | 234 | system_resource_limit->Initialize(); |
| 235 | KResourceLimit::Register(kernel, system_resource_limit); | 235 | KResourceLimit::Register(kernel, system_resource_limit); |
| 236 | 236 | ||
| 237 | const auto sizes{memory_layout->GetTotalAndKernelMemorySizes()}; | 237 | const auto sizes{memory_layout->GetTotalAndKernelMemorySizes()}; |
diff --git a/src/core/hle/kernel/svc/svc_address_arbiter.cpp b/src/core/hle/kernel/svc/svc_address_arbiter.cpp index 04cc5ea64..90ee43521 100644 --- a/src/core/hle/kernel/svc/svc_address_arbiter.cpp +++ b/src/core/hle/kernel/svc/svc_address_arbiter.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/core.h" | 4 | #include "core/core.h" |
| 5 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 5 | #include "core/hle/kernel/k_memory_layout.h" | 6 | #include "core/hle/kernel/k_memory_layout.h" |
| 6 | #include "core/hle/kernel/k_process.h" | 7 | #include "core/hle/kernel/k_process.h" |
| 7 | #include "core/hle/kernel/kernel.h" | 8 | #include "core/hle/kernel/kernel.h" |
| @@ -52,7 +53,7 @@ Result WaitForAddress(Core::System& system, u64 address, ArbitrationType arb_typ | |||
| 52 | if (timeout_ns > 0) { | 53 | if (timeout_ns > 0) { |
| 53 | const s64 offset_tick(timeout_ns); | 54 | const s64 offset_tick(timeout_ns); |
| 54 | if (offset_tick > 0) { | 55 | if (offset_tick > 0) { |
| 55 | timeout = offset_tick + 2; | 56 | timeout = system.Kernel().HardwareTimer().GetTick() + offset_tick + 2; |
| 56 | if (timeout <= 0) { | 57 | if (timeout <= 0) { |
| 57 | timeout = std::numeric_limits<s64>::max(); | 58 | timeout = std::numeric_limits<s64>::max(); |
| 58 | } | 59 | } |
diff --git a/src/core/hle/kernel/svc/svc_condition_variable.cpp b/src/core/hle/kernel/svc/svc_condition_variable.cpp index ca120d67e..bb678e6c5 100644 --- a/src/core/hle/kernel/svc/svc_condition_variable.cpp +++ b/src/core/hle/kernel/svc/svc_condition_variable.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/core.h" | 4 | #include "core/core.h" |
| 5 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 5 | #include "core/hle/kernel/k_memory_layout.h" | 6 | #include "core/hle/kernel/k_memory_layout.h" |
| 6 | #include "core/hle/kernel/k_process.h" | 7 | #include "core/hle/kernel/k_process.h" |
| 7 | #include "core/hle/kernel/kernel.h" | 8 | #include "core/hle/kernel/kernel.h" |
| @@ -25,7 +26,7 @@ Result WaitProcessWideKeyAtomic(Core::System& system, u64 address, u64 cv_key, u | |||
| 25 | if (timeout_ns > 0) { | 26 | if (timeout_ns > 0) { |
| 26 | const s64 offset_tick(timeout_ns); | 27 | const s64 offset_tick(timeout_ns); |
| 27 | if (offset_tick > 0) { | 28 | if (offset_tick > 0) { |
| 28 | timeout = offset_tick + 2; | 29 | timeout = system.Kernel().HardwareTimer().GetTick() + offset_tick + 2; |
| 29 | if (timeout <= 0) { | 30 | if (timeout <= 0) { |
| 30 | timeout = std::numeric_limits<s64>::max(); | 31 | timeout = std::numeric_limits<s64>::max(); |
| 31 | } | 32 | } |
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp index 373ae7c8d..6b5e1cb8d 100644 --- a/src/core/hle/kernel/svc/svc_ipc.cpp +++ b/src/core/hle/kernel/svc/svc_ipc.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include "common/scratch_buffer.h" | 5 | #include "common/scratch_buffer.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hle/kernel/k_client_session.h" | 7 | #include "core/hle/kernel/k_client_session.h" |
| 8 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 8 | #include "core/hle/kernel/k_process.h" | 9 | #include "core/hle/kernel/k_process.h" |
| 9 | #include "core/hle/kernel/k_server_session.h" | 10 | #include "core/hle/kernel/k_server_session.h" |
| 10 | #include "core/hle/kernel/svc.h" | 11 | #include "core/hle/kernel/svc.h" |
| @@ -82,12 +83,29 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad | |||
| 82 | R_TRY(session->SendReply()); | 83 | R_TRY(session->SendReply()); |
| 83 | } | 84 | } |
| 84 | 85 | ||
| 86 | // Convert the timeout from nanoseconds to ticks. | ||
| 87 | // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... | ||
| 88 | s64 timeout; | ||
| 89 | if (timeout_ns > 0) { | ||
| 90 | const s64 offset_tick(timeout_ns); | ||
| 91 | if (offset_tick > 0) { | ||
| 92 | timeout = kernel.HardwareTimer().GetTick() + offset_tick + 2; | ||
| 93 | if (timeout <= 0) { | ||
| 94 | timeout = std::numeric_limits<s64>::max(); | ||
| 95 | } | ||
| 96 | } else { | ||
| 97 | timeout = std::numeric_limits<s64>::max(); | ||
| 98 | } | ||
| 99 | } else { | ||
| 100 | timeout = timeout_ns; | ||
| 101 | } | ||
| 102 | |||
| 85 | // Wait for a message. | 103 | // Wait for a message. |
| 86 | while (true) { | 104 | while (true) { |
| 87 | // Wait for an object. | 105 | // Wait for an object. |
| 88 | s32 index; | 106 | s32 index; |
| 89 | Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(), | 107 | Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(), |
| 90 | num_handles, timeout_ns); | 108 | num_handles, timeout); |
| 91 | if (result == ResultTimedOut) { | 109 | if (result == ResultTimedOut) { |
| 92 | R_RETURN(result); | 110 | R_RETURN(result); |
| 93 | } | 111 | } |
diff --git a/src/core/hle/kernel/svc/svc_resource_limit.cpp b/src/core/hle/kernel/svc/svc_resource_limit.cpp index 732bc017e..c8e820b6a 100644 --- a/src/core/hle/kernel/svc/svc_resource_limit.cpp +++ b/src/core/hle/kernel/svc/svc_resource_limit.cpp | |||
| @@ -21,7 +21,7 @@ Result CreateResourceLimit(Core::System& system, Handle* out_handle) { | |||
| 21 | SCOPE_EXIT({ resource_limit->Close(); }); | 21 | SCOPE_EXIT({ resource_limit->Close(); }); |
| 22 | 22 | ||
| 23 | // Initialize the resource limit. | 23 | // Initialize the resource limit. |
| 24 | resource_limit->Initialize(std::addressof(system.CoreTiming())); | 24 | resource_limit->Initialize(); |
| 25 | 25 | ||
| 26 | // Register the limit. | 26 | // Register the limit. |
| 27 | KResourceLimit::Register(kernel, resource_limit); | 27 | KResourceLimit::Register(kernel, resource_limit); |
diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp index 366e8ed4a..8ebc1bd1c 100644 --- a/src/core/hle/kernel/svc/svc_synchronization.cpp +++ b/src/core/hle/kernel/svc/svc_synchronization.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include "common/scope_exit.h" | 4 | #include "common/scope_exit.h" |
| 5 | #include "common/scratch_buffer.h" | 5 | #include "common/scratch_buffer.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 7 | #include "core/hle/kernel/k_process.h" | 8 | #include "core/hle/kernel/k_process.h" |
| 8 | #include "core/hle/kernel/k_readable_event.h" | 9 | #include "core/hle/kernel/k_readable_event.h" |
| 9 | #include "core/hle/kernel/svc.h" | 10 | #include "core/hle/kernel/svc.h" |
| @@ -83,9 +84,20 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha | |||
| 83 | } | 84 | } |
| 84 | }); | 85 | }); |
| 85 | 86 | ||
| 87 | // Convert the timeout from nanoseconds to ticks. | ||
| 88 | s64 timeout; | ||
| 89 | if (timeout_ns > 0) { | ||
| 90 | u64 ticks = kernel.HardwareTimer().GetTick(); | ||
| 91 | ticks += timeout_ns; | ||
| 92 | ticks += 2; | ||
| 93 | |||
| 94 | timeout = ticks; | ||
| 95 | } else { | ||
| 96 | timeout = timeout_ns; | ||
| 97 | } | ||
| 98 | |||
| 86 | // Wait on the objects. | 99 | // Wait on the objects. |
| 87 | Result res = | 100 | Result res = KSynchronizationObject::Wait(kernel, out_index, objs.data(), num_handles, timeout); |
| 88 | KSynchronizationObject::Wait(kernel, out_index, objs.data(), num_handles, timeout_ns); | ||
| 89 | 101 | ||
| 90 | R_SUCCEED_IF(res == ResultSessionClosed); | 102 | R_SUCCEED_IF(res == ResultSessionClosed); |
| 91 | R_RETURN(res); | 103 | R_RETURN(res); |
diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp index 92bcea72b..933b82e30 100644 --- a/src/core/hle/kernel/svc/svc_thread.cpp +++ b/src/core/hle/kernel/svc/svc_thread.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include "common/scope_exit.h" | 4 | #include "common/scope_exit.h" |
| 5 | #include "core/core.h" | 5 | #include "core/core.h" |
| 6 | #include "core/core_timing.h" | 6 | #include "core/core_timing.h" |
| 7 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 7 | #include "core/hle/kernel/k_process.h" | 8 | #include "core/hle/kernel/k_process.h" |
| 8 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | 9 | #include "core/hle/kernel/k_scoped_resource_reservation.h" |
| 9 | #include "core/hle/kernel/k_thread.h" | 10 | #include "core/hle/kernel/k_thread.h" |
| @@ -42,9 +43,9 @@ Result CreateThread(Core::System& system, Handle* out_handle, u64 entry_point, u | |||
| 42 | R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority); | 43 | R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority); |
| 43 | 44 | ||
| 44 | // Reserve a new thread from the process resource limit (waiting up to 100ms). | 45 | // Reserve a new thread from the process resource limit (waiting up to 100ms). |
| 45 | KScopedResourceReservation thread_reservation( | 46 | KScopedResourceReservation thread_reservation(std::addressof(process), |
| 46 | std::addressof(process), LimitableResource::ThreadCountMax, 1, | 47 | LimitableResource::ThreadCountMax, 1, |
| 47 | system.CoreTiming().GetGlobalTimeNs().count() + 100000000); | 48 | kernel.HardwareTimer().GetTick() + 100000000); |
| 48 | R_UNLESS(thread_reservation.Succeeded(), ResultLimitReached); | 49 | R_UNLESS(thread_reservation.Succeeded(), ResultLimitReached); |
| 49 | 50 | ||
| 50 | // Create the thread. | 51 | // Create the thread. |
| @@ -102,20 +103,31 @@ void ExitThread(Core::System& system) { | |||
| 102 | } | 103 | } |
| 103 | 104 | ||
| 104 | /// Sleep the current thread | 105 | /// Sleep the current thread |
| 105 | void SleepThread(Core::System& system, s64 nanoseconds) { | 106 | void SleepThread(Core::System& system, s64 ns) { |
| 106 | auto& kernel = system.Kernel(); | 107 | auto& kernel = system.Kernel(); |
| 107 | const auto yield_type = static_cast<Svc::YieldType>(nanoseconds); | 108 | const auto yield_type = static_cast<Svc::YieldType>(ns); |
| 108 | 109 | ||
| 109 | LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); | 110 | LOG_TRACE(Kernel_SVC, "called nanoseconds={}", ns); |
| 110 | 111 | ||
| 111 | // When the input tick is positive, sleep. | 112 | // When the input tick is positive, sleep. |
| 112 | if (nanoseconds > 0) { | 113 | if (ns > 0) { |
| 113 | // Convert the timeout from nanoseconds to ticks. | 114 | // Convert the timeout from nanoseconds to ticks. |
| 114 | // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... | 115 | // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... |
| 116 | s64 timeout; | ||
| 117 | |||
| 118 | const s64 offset_tick(ns); | ||
| 119 | if (offset_tick > 0) { | ||
| 120 | timeout = kernel.HardwareTimer().GetTick() + offset_tick + 2; | ||
| 121 | if (timeout <= 0) { | ||
| 122 | timeout = std::numeric_limits<s64>::max(); | ||
| 123 | } | ||
| 124 | } else { | ||
| 125 | timeout = std::numeric_limits<s64>::max(); | ||
| 126 | } | ||
| 115 | 127 | ||
| 116 | // Sleep. | 128 | // Sleep. |
| 117 | // NOTE: Nintendo does not check the result of this sleep. | 129 | // NOTE: Nintendo does not check the result of this sleep. |
| 118 | static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds)); | 130 | static_cast<void>(GetCurrentThread(kernel).Sleep(timeout)); |
| 119 | } else if (yield_type == Svc::YieldType::WithoutCoreMigration) { | 131 | } else if (yield_type == Svc::YieldType::WithoutCoreMigration) { |
| 120 | KScheduler::YieldWithoutCoreMigration(kernel); | 132 | KScheduler::YieldWithoutCoreMigration(kernel); |
| 121 | } else if (yield_type == Svc::YieldType::WithCoreMigration) { | 133 | } else if (yield_type == Svc::YieldType::WithCoreMigration) { |
| @@ -124,7 +136,6 @@ void SleepThread(Core::System& system, s64 nanoseconds) { | |||
| 124 | KScheduler::YieldToAnyThread(kernel); | 136 | KScheduler::YieldToAnyThread(kernel); |
| 125 | } else { | 137 | } else { |
| 126 | // Nintendo does nothing at all if an otherwise invalid value is passed. | 138 | // Nintendo does nothing at all if an otherwise invalid value is passed. |
| 127 | ASSERT_MSG(false, "Unimplemented sleep yield type '{:016X}'!", nanoseconds); | ||
| 128 | } | 139 | } |
| 129 | } | 140 | } |
| 130 | 141 | ||
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h index 77426c46e..f86af01a4 100644 --- a/src/core/hle/service/sockets/sockets.h +++ b/src/core/hle/service/sockets/sockets.h | |||
| @@ -18,7 +18,9 @@ enum class Errno : u32 { | |||
| 18 | AGAIN = 11, | 18 | AGAIN = 11, |
| 19 | INVAL = 22, | 19 | INVAL = 22, |
| 20 | MFILE = 24, | 20 | MFILE = 24, |
| 21 | PIPE = 32, | ||
| 21 | MSGSIZE = 90, | 22 | MSGSIZE = 90, |
| 23 | CONNABORTED = 103, | ||
| 22 | CONNRESET = 104, | 24 | CONNRESET = 104, |
| 23 | NOTCONN = 107, | 25 | NOTCONN = 107, |
| 24 | TIMEDOUT = 110, | 26 | TIMEDOUT = 110, |
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp index c1187209f..aed05250c 100644 --- a/src/core/hle/service/sockets/sockets_translate.cpp +++ b/src/core/hle/service/sockets/sockets_translate.cpp | |||
| @@ -23,10 +23,14 @@ Errno Translate(Network::Errno value) { | |||
| 23 | return Errno::INVAL; | 23 | return Errno::INVAL; |
| 24 | case Network::Errno::MFILE: | 24 | case Network::Errno::MFILE: |
| 25 | return Errno::MFILE; | 25 | return Errno::MFILE; |
| 26 | case Network::Errno::PIPE: | ||
| 27 | return Errno::PIPE; | ||
| 26 | case Network::Errno::NOTCONN: | 28 | case Network::Errno::NOTCONN: |
| 27 | return Errno::NOTCONN; | 29 | return Errno::NOTCONN; |
| 28 | case Network::Errno::TIMEDOUT: | 30 | case Network::Errno::TIMEDOUT: |
| 29 | return Errno::TIMEDOUT; | 31 | return Errno::TIMEDOUT; |
| 32 | case Network::Errno::CONNABORTED: | ||
| 33 | return Errno::CONNABORTED; | ||
| 30 | case Network::Errno::CONNRESET: | 34 | case Network::Errno::CONNRESET: |
| 31 | return Errno::CONNRESET; | 35 | return Errno::CONNRESET; |
| 32 | case Network::Errno::INPROGRESS: | 36 | case Network::Errno::INPROGRESS: |
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index bda9fa2e0..5d28300e6 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp | |||
| @@ -39,6 +39,11 @@ namespace Network { | |||
| 39 | 39 | ||
| 40 | namespace { | 40 | namespace { |
| 41 | 41 | ||
| 42 | enum class CallType { | ||
| 43 | Send, | ||
| 44 | Other, | ||
| 45 | }; | ||
| 46 | |||
| 42 | #ifdef _WIN32 | 47 | #ifdef _WIN32 |
| 43 | 48 | ||
| 44 | using socklen_t = int; | 49 | using socklen_t = int; |
| @@ -96,7 +101,7 @@ bool EnableNonBlock(SOCKET fd, bool enable) { | |||
| 96 | return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; | 101 | return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; |
| 97 | } | 102 | } |
| 98 | 103 | ||
| 99 | Errno TranslateNativeError(int e) { | 104 | Errno TranslateNativeError(int e, CallType call_type = CallType::Other) { |
| 100 | switch (e) { | 105 | switch (e) { |
| 101 | case 0: | 106 | case 0: |
| 102 | return Errno::SUCCESS; | 107 | return Errno::SUCCESS; |
| @@ -112,6 +117,14 @@ Errno TranslateNativeError(int e) { | |||
| 112 | return Errno::AGAIN; | 117 | return Errno::AGAIN; |
| 113 | case WSAECONNREFUSED: | 118 | case WSAECONNREFUSED: |
| 114 | return Errno::CONNREFUSED; | 119 | return Errno::CONNREFUSED; |
| 120 | case WSAECONNABORTED: | ||
| 121 | if (call_type == CallType::Send) { | ||
| 122 | // Winsock yields WSAECONNABORTED from `send` in situations where Unix | ||
| 123 | // systems, and actual Switches, yield EPIPE. | ||
| 124 | return Errno::PIPE; | ||
| 125 | } else { | ||
| 126 | return Errno::CONNABORTED; | ||
| 127 | } | ||
| 115 | case WSAECONNRESET: | 128 | case WSAECONNRESET: |
| 116 | return Errno::CONNRESET; | 129 | return Errno::CONNRESET; |
| 117 | case WSAEHOSTUNREACH: | 130 | case WSAEHOSTUNREACH: |
| @@ -198,7 +211,7 @@ bool EnableNonBlock(int fd, bool enable) { | |||
| 198 | return fcntl(fd, F_SETFL, flags) == 0; | 211 | return fcntl(fd, F_SETFL, flags) == 0; |
| 199 | } | 212 | } |
| 200 | 213 | ||
| 201 | Errno TranslateNativeError(int e) { | 214 | Errno TranslateNativeError(int e, CallType call_type = CallType::Other) { |
| 202 | switch (e) { | 215 | switch (e) { |
| 203 | case 0: | 216 | case 0: |
| 204 | return Errno::SUCCESS; | 217 | return Errno::SUCCESS; |
| @@ -208,6 +221,10 @@ Errno TranslateNativeError(int e) { | |||
| 208 | return Errno::INVAL; | 221 | return Errno::INVAL; |
| 209 | case EMFILE: | 222 | case EMFILE: |
| 210 | return Errno::MFILE; | 223 | return Errno::MFILE; |
| 224 | case EPIPE: | ||
| 225 | return Errno::PIPE; | ||
| 226 | case ECONNABORTED: | ||
| 227 | return Errno::CONNABORTED; | ||
| 211 | case ENOTCONN: | 228 | case ENOTCONN: |
| 212 | return Errno::NOTCONN; | 229 | return Errno::NOTCONN; |
| 213 | case EAGAIN: | 230 | case EAGAIN: |
| @@ -236,13 +253,13 @@ Errno TranslateNativeError(int e) { | |||
| 236 | 253 | ||
| 237 | #endif | 254 | #endif |
| 238 | 255 | ||
| 239 | Errno GetAndLogLastError() { | 256 | Errno GetAndLogLastError(CallType call_type = CallType::Other) { |
| 240 | #ifdef _WIN32 | 257 | #ifdef _WIN32 |
| 241 | int e = WSAGetLastError(); | 258 | int e = WSAGetLastError(); |
| 242 | #else | 259 | #else |
| 243 | int e = errno; | 260 | int e = errno; |
| 244 | #endif | 261 | #endif |
| 245 | const Errno err = TranslateNativeError(e); | 262 | const Errno err = TranslateNativeError(e, call_type); |
| 246 | if (err == Errno::AGAIN || err == Errno::TIMEDOUT || err == Errno::INPROGRESS) { | 263 | if (err == Errno::AGAIN || err == Errno::TIMEDOUT || err == Errno::INPROGRESS) { |
| 247 | // These happen during normal operation, so only log them at debug level. | 264 | // These happen during normal operation, so only log them at debug level. |
| 248 | LOG_DEBUG(Network, "Socket operation error: {}", Common::NativeErrorToString(e)); | 265 | LOG_DEBUG(Network, "Socket operation error: {}", Common::NativeErrorToString(e)); |
| @@ -731,13 +748,17 @@ std::pair<s32, Errno> Socket::Send(std::span<const u8> message, int flags) { | |||
| 731 | ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); | 748 | ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); |
| 732 | ASSERT(flags == 0); | 749 | ASSERT(flags == 0); |
| 733 | 750 | ||
| 751 | int native_flags = 0; | ||
| 752 | #if YUZU_UNIX | ||
| 753 | native_flags |= MSG_NOSIGNAL; // do not send us SIGPIPE | ||
| 754 | #endif | ||
| 734 | const auto result = send(fd, reinterpret_cast<const char*>(message.data()), | 755 | const auto result = send(fd, reinterpret_cast<const char*>(message.data()), |
| 735 | static_cast<int>(message.size()), 0); | 756 | static_cast<int>(message.size()), native_flags); |
| 736 | if (result != SOCKET_ERROR) { | 757 | if (result != SOCKET_ERROR) { |
| 737 | return {static_cast<s32>(result), Errno::SUCCESS}; | 758 | return {static_cast<s32>(result), Errno::SUCCESS}; |
| 738 | } | 759 | } |
| 739 | 760 | ||
| 740 | return {-1, GetAndLogLastError()}; | 761 | return {-1, GetAndLogLastError(CallType::Send)}; |
| 741 | } | 762 | } |
| 742 | 763 | ||
| 743 | std::pair<s32, Errno> Socket::SendTo(u32 flags, std::span<const u8> message, | 764 | std::pair<s32, Errno> Socket::SendTo(u32 flags, std::span<const u8> message, |
| @@ -759,7 +780,7 @@ std::pair<s32, Errno> Socket::SendTo(u32 flags, std::span<const u8> message, | |||
| 759 | return {static_cast<s32>(result), Errno::SUCCESS}; | 780 | return {static_cast<s32>(result), Errno::SUCCESS}; |
| 760 | } | 781 | } |
| 761 | 782 | ||
| 762 | return {-1, GetAndLogLastError()}; | 783 | return {-1, GetAndLogLastError(CallType::Send)}; |
| 763 | } | 784 | } |
| 764 | 785 | ||
| 765 | Errno Socket::Close() { | 786 | Errno Socket::Close() { |
diff --git a/src/core/internal_network/network.h b/src/core/internal_network/network.h index badcb8369..c7e20ae34 100644 --- a/src/core/internal_network/network.h +++ b/src/core/internal_network/network.h | |||
| @@ -33,10 +33,12 @@ enum class Errno { | |||
| 33 | BADF, | 33 | BADF, |
| 34 | INVAL, | 34 | INVAL, |
| 35 | MFILE, | 35 | MFILE, |
| 36 | PIPE, | ||
| 36 | NOTCONN, | 37 | NOTCONN, |
| 37 | AGAIN, | 38 | AGAIN, |
| 38 | CONNREFUSED, | 39 | CONNREFUSED, |
| 39 | CONNRESET, | 40 | CONNRESET, |
| 41 | CONNABORTED, | ||
| 40 | HOSTUNREACH, | 42 | HOSTUNREACH, |
| 41 | NETDOWN, | 43 | NETDOWN, |
| 42 | NETUNREACH, | 44 | NETUNREACH, |
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index e61d9af80..c4d459077 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt | |||
| @@ -50,6 +50,7 @@ set(SHADER_FILES | |||
| 50 | vulkan_blit_depth_stencil.frag | 50 | vulkan_blit_depth_stencil.frag |
| 51 | vulkan_color_clear.frag | 51 | vulkan_color_clear.frag |
| 52 | vulkan_color_clear.vert | 52 | vulkan_color_clear.vert |
| 53 | vulkan_depthstencil_clear.frag | ||
| 53 | vulkan_fidelityfx_fsr_easu_fp16.comp | 54 | vulkan_fidelityfx_fsr_easu_fp16.comp |
| 54 | vulkan_fidelityfx_fsr_easu_fp32.comp | 55 | vulkan_fidelityfx_fsr_easu_fp32.comp |
| 55 | vulkan_fidelityfx_fsr_rcas_fp16.comp | 56 | vulkan_fidelityfx_fsr_rcas_fp16.comp |
diff --git a/src/video_core/host_shaders/vulkan_depthstencil_clear.frag b/src/video_core/host_shaders/vulkan_depthstencil_clear.frag new file mode 100644 index 000000000..1ac177c7e --- /dev/null +++ b/src/video_core/host_shaders/vulkan_depthstencil_clear.frag | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #version 460 core | ||
| 5 | |||
| 6 | layout (push_constant) uniform PushConstants { | ||
| 7 | vec4 clear_depth; | ||
| 8 | }; | ||
| 9 | |||
| 10 | void main() { | ||
| 11 | gl_FragDepth = clear_depth.x; | ||
| 12 | } | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index aadd6967c..1ba31be88 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -1335,7 +1335,8 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info, | |||
| 1335 | } | 1335 | } |
| 1336 | const u32 buffer_size = static_cast<u32>(buffer_operand.pitch * buffer_operand.height); | 1336 | const u32 buffer_size = static_cast<u32>(buffer_operand.pitch * buffer_operand.height); |
| 1337 | static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize; | 1337 | static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize; |
| 1338 | const auto post_op = VideoCommon::ObtainBufferOperation::DoNothing; | 1338 | const auto post_op = IS_IMAGE_UPLOAD ? VideoCommon::ObtainBufferOperation::DoNothing |
| 1339 | : VideoCommon::ObtainBufferOperation::MarkAsWritten; | ||
| 1339 | const auto [buffer, offset] = | 1340 | const auto [buffer, offset] = |
| 1340 | buffer_cache.ObtainBuffer(buffer_operand.address, buffer_size, sync_info, post_op); | 1341 | buffer_cache.ObtainBuffer(buffer_operand.address, buffer_size, sync_info, post_op); |
| 1341 | 1342 | ||
| @@ -1344,8 +1345,12 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info, | |||
| 1344 | const std::span copy_span{©, 1}; | 1345 | const std::span copy_span{©, 1}; |
| 1345 | 1346 | ||
| 1346 | if constexpr (IS_IMAGE_UPLOAD) { | 1347 | if constexpr (IS_IMAGE_UPLOAD) { |
| 1348 | texture_cache.PrepareImage(image_id, true, false); | ||
| 1347 | image->UploadMemory(buffer->Handle(), offset, copy_span); | 1349 | image->UploadMemory(buffer->Handle(), offset, copy_span); |
| 1348 | } else { | 1350 | } else { |
| 1351 | if (offset % BytesPerBlock(image->info.format)) { | ||
| 1352 | return false; | ||
| 1353 | } | ||
| 1349 | texture_cache.DownloadImageIntoBuffer(image, buffer->Handle(), offset, copy_span, | 1354 | texture_cache.DownloadImageIntoBuffer(image, buffer->Handle(), offset, copy_span, |
| 1350 | buffer_operand.address, buffer_size); | 1355 | buffer_operand.address, buffer_size); |
| 1351 | } | 1356 | } |
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index f74ae972e..1032c9d12 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" | 16 | #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" |
| 17 | #include "video_core/host_shaders/vulkan_color_clear_frag_spv.h" | 17 | #include "video_core/host_shaders/vulkan_color_clear_frag_spv.h" |
| 18 | #include "video_core/host_shaders/vulkan_color_clear_vert_spv.h" | 18 | #include "video_core/host_shaders/vulkan_color_clear_vert_spv.h" |
| 19 | #include "video_core/host_shaders/vulkan_depthstencil_clear_frag_spv.h" | ||
| 19 | #include "video_core/renderer_vulkan/blit_image.h" | 20 | #include "video_core/renderer_vulkan/blit_image.h" |
| 20 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 21 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 21 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 22 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| @@ -428,6 +429,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, | |||
| 428 | blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)), | 429 | blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)), |
| 429 | clear_color_vert(BuildShader(device, VULKAN_COLOR_CLEAR_VERT_SPV)), | 430 | clear_color_vert(BuildShader(device, VULKAN_COLOR_CLEAR_VERT_SPV)), |
| 430 | clear_color_frag(BuildShader(device, VULKAN_COLOR_CLEAR_FRAG_SPV)), | 431 | clear_color_frag(BuildShader(device, VULKAN_COLOR_CLEAR_FRAG_SPV)), |
| 432 | clear_stencil_frag(BuildShader(device, VULKAN_DEPTHSTENCIL_CLEAR_FRAG_SPV)), | ||
| 431 | convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), | 433 | convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), |
| 432 | convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), | 434 | convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), |
| 433 | convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), | 435 | convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), |
| @@ -593,6 +595,28 @@ void BlitImageHelper::ClearColor(const Framebuffer* dst_framebuffer, u8 color_ma | |||
| 593 | scheduler.InvalidateState(); | 595 | scheduler.InvalidateState(); |
| 594 | } | 596 | } |
| 595 | 597 | ||
| 598 | void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool depth_clear, | ||
| 599 | f32 clear_depth, u8 stencil_mask, u32 stencil_ref, | ||
| 600 | u32 stencil_compare_mask, const Region2D& dst_region) { | ||
| 601 | const BlitDepthStencilPipelineKey key{ | ||
| 602 | .renderpass = dst_framebuffer->RenderPass(), | ||
| 603 | .depth_clear = depth_clear, | ||
| 604 | .stencil_mask = stencil_mask, | ||
| 605 | .stencil_compare_mask = stencil_compare_mask, | ||
| 606 | .stencil_ref = stencil_ref, | ||
| 607 | }; | ||
| 608 | const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key); | ||
| 609 | const VkPipelineLayout layout = *clear_color_pipeline_layout; | ||
| 610 | scheduler.RequestRenderpass(dst_framebuffer); | ||
| 611 | scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) { | ||
| 612 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||
| 613 | BindBlitState(cmdbuf, dst_region); | ||
| 614 | cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_depth); | ||
| 615 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 616 | }); | ||
| 617 | scheduler.InvalidateState(); | ||
| 618 | } | ||
| 619 | |||
| 596 | void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | 620 | void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, |
| 597 | const ImageView& src_image_view) { | 621 | const ImageView& src_image_view) { |
| 598 | const VkPipelineLayout layout = *one_texture_pipeline_layout; | 622 | const VkPipelineLayout layout = *one_texture_pipeline_layout; |
| @@ -820,6 +844,61 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel | |||
| 820 | return *clear_color_pipelines.back(); | 844 | return *clear_color_pipelines.back(); |
| 821 | } | 845 | } |
| 822 | 846 | ||
| 847 | VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline( | ||
| 848 | const BlitDepthStencilPipelineKey& key) { | ||
| 849 | const auto it = std::ranges::find(clear_stencil_keys, key); | ||
| 850 | if (it != clear_stencil_keys.end()) { | ||
| 851 | return *clear_stencil_pipelines[std::distance(clear_stencil_keys.begin(), it)]; | ||
| 852 | } | ||
| 853 | clear_stencil_keys.push_back(key); | ||
| 854 | const std::array stages = MakeStages(*clear_color_vert, *clear_stencil_frag); | ||
| 855 | const auto stencil = VkStencilOpState{ | ||
| 856 | .failOp = VK_STENCIL_OP_KEEP, | ||
| 857 | .passOp = VK_STENCIL_OP_REPLACE, | ||
| 858 | .depthFailOp = VK_STENCIL_OP_KEEP, | ||
| 859 | .compareOp = VK_COMPARE_OP_ALWAYS, | ||
| 860 | .compareMask = key.stencil_compare_mask, | ||
| 861 | .writeMask = key.stencil_mask, | ||
| 862 | .reference = key.stencil_ref, | ||
| 863 | }; | ||
| 864 | const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{ | ||
| 865 | .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, | ||
| 866 | .pNext = nullptr, | ||
| 867 | .flags = 0, | ||
| 868 | .depthTestEnable = VK_FALSE, | ||
| 869 | .depthWriteEnable = key.depth_clear, | ||
| 870 | .depthCompareOp = VK_COMPARE_OP_ALWAYS, | ||
| 871 | .depthBoundsTestEnable = VK_FALSE, | ||
| 872 | .stencilTestEnable = VK_TRUE, | ||
| 873 | .front = stencil, | ||
| 874 | .back = stencil, | ||
| 875 | .minDepthBounds = 0.0f, | ||
| 876 | .maxDepthBounds = 0.0f, | ||
| 877 | }; | ||
| 878 | clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ | ||
| 879 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 880 | .pNext = nullptr, | ||
| 881 | .flags = 0, | ||
| 882 | .stageCount = static_cast<u32>(stages.size()), | ||
| 883 | .pStages = stages.data(), | ||
| 884 | .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 885 | .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 886 | .pTessellationState = nullptr, | ||
| 887 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 888 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 889 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 890 | .pDepthStencilState = &depth_stencil_ci, | ||
| 891 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, | ||
| 892 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 893 | .layout = *clear_color_pipeline_layout, | ||
| 894 | .renderPass = key.renderpass, | ||
| 895 | .subpass = 0, | ||
| 896 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 897 | .basePipelineIndex = 0, | ||
| 898 | })); | ||
| 899 | return *clear_stencil_pipelines.back(); | ||
| 900 | } | ||
| 901 | |||
| 823 | void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, | 902 | void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 824 | bool is_target_depth) { | 903 | bool is_target_depth) { |
| 825 | if (pipeline) { | 904 | if (pipeline) { |
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 2976a7d91..dcfe217aa 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h | |||
| @@ -27,6 +27,16 @@ struct BlitImagePipelineKey { | |||
| 27 | Tegra::Engines::Fermi2D::Operation operation; | 27 | Tegra::Engines::Fermi2D::Operation operation; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | struct BlitDepthStencilPipelineKey { | ||
| 31 | constexpr auto operator<=>(const BlitDepthStencilPipelineKey&) const noexcept = default; | ||
| 32 | |||
| 33 | VkRenderPass renderpass; | ||
| 34 | bool depth_clear; | ||
| 35 | u8 stencil_mask; | ||
| 36 | u32 stencil_compare_mask; | ||
| 37 | u32 stencil_ref; | ||
| 38 | }; | ||
| 39 | |||
| 30 | class BlitImageHelper { | 40 | class BlitImageHelper { |
| 31 | public: | 41 | public: |
| 32 | explicit BlitImageHelper(const Device& device, Scheduler& scheduler, | 42 | explicit BlitImageHelper(const Device& device, Scheduler& scheduler, |
| @@ -64,6 +74,10 @@ public: | |||
| 64 | void ClearColor(const Framebuffer* dst_framebuffer, u8 color_mask, | 74 | void ClearColor(const Framebuffer* dst_framebuffer, u8 color_mask, |
| 65 | const std::array<f32, 4>& clear_color, const Region2D& dst_region); | 75 | const std::array<f32, 4>& clear_color, const Region2D& dst_region); |
| 66 | 76 | ||
| 77 | void ClearDepthStencil(const Framebuffer* dst_framebuffer, bool depth_clear, f32 clear_depth, | ||
| 78 | u8 stencil_mask, u32 stencil_ref, u32 stencil_compare_mask, | ||
| 79 | const Region2D& dst_region); | ||
| 80 | |||
| 67 | private: | 81 | private: |
| 68 | void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | 82 | void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, |
| 69 | const ImageView& src_image_view); | 83 | const ImageView& src_image_view); |
| @@ -76,6 +90,8 @@ private: | |||
| 76 | [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key); | 90 | [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key); |
| 77 | 91 | ||
| 78 | [[nodiscard]] VkPipeline FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key); | 92 | [[nodiscard]] VkPipeline FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key); |
| 93 | [[nodiscard]] VkPipeline FindOrEmplaceClearStencilPipeline( | ||
| 94 | const BlitDepthStencilPipelineKey& key); | ||
| 79 | 95 | ||
| 80 | void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth); | 96 | void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth); |
| 81 | 97 | ||
| @@ -108,6 +124,7 @@ private: | |||
| 108 | vk::ShaderModule blit_depth_stencil_frag; | 124 | vk::ShaderModule blit_depth_stencil_frag; |
| 109 | vk::ShaderModule clear_color_vert; | 125 | vk::ShaderModule clear_color_vert; |
| 110 | vk::ShaderModule clear_color_frag; | 126 | vk::ShaderModule clear_color_frag; |
| 127 | vk::ShaderModule clear_stencil_frag; | ||
| 111 | vk::ShaderModule convert_depth_to_float_frag; | 128 | vk::ShaderModule convert_depth_to_float_frag; |
| 112 | vk::ShaderModule convert_float_to_depth_frag; | 129 | vk::ShaderModule convert_float_to_depth_frag; |
| 113 | vk::ShaderModule convert_abgr8_to_d24s8_frag; | 130 | vk::ShaderModule convert_abgr8_to_d24s8_frag; |
| @@ -122,6 +139,8 @@ private: | |||
| 122 | std::vector<vk::Pipeline> blit_depth_stencil_pipelines; | 139 | std::vector<vk::Pipeline> blit_depth_stencil_pipelines; |
| 123 | std::vector<BlitImagePipelineKey> clear_color_keys; | 140 | std::vector<BlitImagePipelineKey> clear_color_keys; |
| 124 | std::vector<vk::Pipeline> clear_color_pipelines; | 141 | std::vector<vk::Pipeline> clear_color_pipelines; |
| 142 | std::vector<BlitDepthStencilPipelineKey> clear_stencil_keys; | ||
| 143 | std::vector<vk::Pipeline> clear_stencil_pipelines; | ||
| 125 | vk::Pipeline convert_d32_to_r32_pipeline; | 144 | vk::Pipeline convert_d32_to_r32_pipeline; |
| 126 | vk::Pipeline convert_r32_to_d32_pipeline; | 145 | vk::Pipeline convert_r32_to_d32_pipeline; |
| 127 | vk::Pipeline convert_d16_to_r16_pipeline; | 146 | vk::Pipeline convert_d16_to_r16_pipeline; |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index a8540339d..35bf80ea3 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp | |||
| @@ -126,7 +126,7 @@ struct FormatTuple { | |||
| 126 | {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM | 126 | {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM |
| 127 | {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM | 127 | {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM |
| 128 | {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT | 128 | {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT |
| 129 | {VK_FORMAT_A2R10G10B10_UNORM_PACK32, Attachable | Storage}, // A2R10G10B10_UNORM | 129 | {VK_FORMAT_A2R10G10B10_UNORM_PACK32, Attachable}, // A2R10G10B10_UNORM |
| 130 | {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1B5G5R5_UNORM (flipped with swizzle) | 130 | {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1B5G5R5_UNORM (flipped with swizzle) |
| 131 | {VK_FORMAT_R5G5B5A1_UNORM_PACK16}, // A5B5G5R1_UNORM (specially swizzled) | 131 | {VK_FORMAT_R5G5B5A1_UNORM_PACK16}, // A5B5G5R1_UNORM (specially swizzled) |
| 132 | {VK_FORMAT_R8_UNORM, Attachable | Storage}, // R8_UNORM | 132 | {VK_FORMAT_R8_UNORM, Attachable | Storage}, // R8_UNORM |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index aa59889bd..032f694bc 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -428,15 +428,27 @@ void RasterizerVulkan::Clear(u32 layer_count) { | |||
| 428 | if (aspect_flags == 0) { | 428 | if (aspect_flags == 0) { |
| 429 | return; | 429 | return; |
| 430 | } | 430 | } |
| 431 | scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil, | 431 | |
| 432 | clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) { | 432 | if (use_stencil && regs.stencil_front_mask != 0xFF && regs.stencil_front_mask != 0) { |
| 433 | VkClearAttachment attachment; | 433 | Region2D dst_region = { |
| 434 | attachment.aspectMask = aspect_flags; | 434 | Offset2D{.x = clear_rect.rect.offset.x, .y = clear_rect.rect.offset.y}, |
| 435 | attachment.colorAttachment = 0; | 435 | Offset2D{.x = clear_rect.rect.offset.x + static_cast<s32>(clear_rect.rect.extent.width), |
| 436 | attachment.clearValue.depthStencil.depth = clear_depth; | 436 | .y = clear_rect.rect.offset.y + |
| 437 | attachment.clearValue.depthStencil.stencil = clear_stencil; | 437 | static_cast<s32>(clear_rect.rect.extent.height)}}; |
| 438 | cmdbuf.ClearAttachments(attachment, clear_rect); | 438 | blit_image.ClearDepthStencil(framebuffer, use_depth, regs.clear_depth, |
| 439 | }); | 439 | static_cast<u8>(regs.stencil_front_mask), regs.clear_stencil, |
| 440 | regs.stencil_front_func_mask, dst_region); | ||
| 441 | } else { | ||
| 442 | scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil, | ||
| 443 | clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) { | ||
| 444 | VkClearAttachment attachment; | ||
| 445 | attachment.aspectMask = aspect_flags; | ||
| 446 | attachment.colorAttachment = 0; | ||
| 447 | attachment.clearValue.depthStencil.depth = clear_depth; | ||
| 448 | attachment.clearValue.depthStencil.stencil = clear_stencil; | ||
| 449 | cmdbuf.ClearAttachments(attachment, clear_rect); | ||
| 450 | }); | ||
| 451 | } | ||
| 440 | } | 452 | } |
| 441 | 453 | ||
| 442 | void RasterizerVulkan::DispatchCompute() { | 454 | void RasterizerVulkan::DispatchCompute() { |
| @@ -830,7 +842,8 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info, | |||
| 830 | } | 842 | } |
| 831 | const u32 buffer_size = static_cast<u32>(buffer_operand.pitch * buffer_operand.height); | 843 | const u32 buffer_size = static_cast<u32>(buffer_operand.pitch * buffer_operand.height); |
| 832 | static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize; | 844 | static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize; |
| 833 | const auto post_op = VideoCommon::ObtainBufferOperation::DoNothing; | 845 | const auto post_op = IS_IMAGE_UPLOAD ? VideoCommon::ObtainBufferOperation::DoNothing |
| 846 | : VideoCommon::ObtainBufferOperation::MarkAsWritten; | ||
| 834 | const auto [buffer, offset] = | 847 | const auto [buffer, offset] = |
| 835 | buffer_cache.ObtainBuffer(buffer_operand.address, buffer_size, sync_info, post_op); | 848 | buffer_cache.ObtainBuffer(buffer_operand.address, buffer_size, sync_info, post_op); |
| 836 | 849 | ||
| @@ -839,8 +852,12 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info, | |||
| 839 | const std::span copy_span{©, 1}; | 852 | const std::span copy_span{©, 1}; |
| 840 | 853 | ||
| 841 | if constexpr (IS_IMAGE_UPLOAD) { | 854 | if constexpr (IS_IMAGE_UPLOAD) { |
| 855 | texture_cache.PrepareImage(image_id, true, false); | ||
| 842 | image->UploadMemory(buffer->Handle(), offset, copy_span); | 856 | image->UploadMemory(buffer->Handle(), offset, copy_span); |
| 843 | } else { | 857 | } else { |
| 858 | if (offset % BytesPerBlock(image->info.format)) { | ||
| 859 | return false; | ||
| 860 | } | ||
| 844 | texture_cache.DownloadImageIntoBuffer(image, buffer->Handle(), offset, copy_span, | 861 | texture_cache.DownloadImageIntoBuffer(image, buffer->Handle(), offset, copy_span, |
| 845 | buffer_operand.address, buffer_size); | 862 | buffer_operand.address, buffer_size); |
| 846 | } | 863 | } |
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index e9ec91265..a40825c9f 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h | |||
| @@ -243,6 +243,9 @@ public: | |||
| 243 | /// Create channel state. | 243 | /// Create channel state. |
| 244 | void CreateChannel(Tegra::Control::ChannelState& channel) final override; | 244 | void CreateChannel(Tegra::Control::ChannelState& channel) final override; |
| 245 | 245 | ||
| 246 | /// Prepare an image to be used | ||
| 247 | void PrepareImage(ImageId image_id, bool is_modification, bool invalidate); | ||
| 248 | |||
| 246 | std::recursive_mutex mutex; | 249 | std::recursive_mutex mutex; |
| 247 | 250 | ||
| 248 | private: | 251 | private: |
| @@ -387,9 +390,6 @@ private: | |||
| 387 | /// Synchronize image aliases, copying data if needed | 390 | /// Synchronize image aliases, copying data if needed |
| 388 | void SynchronizeAliases(ImageId image_id); | 391 | void SynchronizeAliases(ImageId image_id); |
| 389 | 392 | ||
| 390 | /// Prepare an image to be used | ||
| 391 | void PrepareImage(ImageId image_id, bool is_modification, bool invalidate); | ||
| 392 | |||
| 393 | /// Prepare an image view to be used | 393 | /// Prepare an image view to be used |
| 394 | void PrepareImageView(ImageViewId image_view_id, bool is_modification, bool invalidate); | 394 | void PrepareImageView(ImageViewId image_view_id, bool is_modification, bool invalidate); |
| 395 | 395 | ||
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index adde96aa5..617417040 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -71,6 +71,11 @@ constexpr std::array R8G8B8_SSCALED{ | |||
| 71 | VK_FORMAT_UNDEFINED, | 71 | VK_FORMAT_UNDEFINED, |
| 72 | }; | 72 | }; |
| 73 | 73 | ||
| 74 | constexpr std::array VK_FORMAT_R32G32B32_SFLOAT{ | ||
| 75 | VK_FORMAT_R32G32B32A32_SFLOAT, | ||
| 76 | VK_FORMAT_UNDEFINED, | ||
| 77 | }; | ||
| 78 | |||
| 74 | } // namespace Alternatives | 79 | } // namespace Alternatives |
| 75 | 80 | ||
| 76 | enum class NvidiaArchitecture { | 81 | enum class NvidiaArchitecture { |
| @@ -103,6 +108,8 @@ constexpr const VkFormat* GetFormatAlternatives(VkFormat format) { | |||
| 103 | return Alternatives::R16G16B16_SSCALED.data(); | 108 | return Alternatives::R16G16B16_SSCALED.data(); |
| 104 | case VK_FORMAT_R8G8B8_SSCALED: | 109 | case VK_FORMAT_R8G8B8_SSCALED: |
| 105 | return Alternatives::R8G8B8_SSCALED.data(); | 110 | return Alternatives::R8G8B8_SSCALED.data(); |
| 111 | case VK_FORMAT_R32G32B32_SFLOAT: | ||
| 112 | return Alternatives::VK_FORMAT_R32G32B32_SFLOAT.data(); | ||
| 106 | default: | 113 | default: |
| 107 | return nullptr; | 114 | return nullptr; |
| 108 | } | 115 | } |
| @@ -130,6 +137,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica | |||
| 130 | VK_FORMAT_A2B10G10R10_UINT_PACK32, | 137 | VK_FORMAT_A2B10G10R10_UINT_PACK32, |
| 131 | VK_FORMAT_A2B10G10R10_UNORM_PACK32, | 138 | VK_FORMAT_A2B10G10R10_UNORM_PACK32, |
| 132 | VK_FORMAT_A2B10G10R10_USCALED_PACK32, | 139 | VK_FORMAT_A2B10G10R10_USCALED_PACK32, |
| 140 | VK_FORMAT_A2R10G10B10_UNORM_PACK32, | ||
| 133 | VK_FORMAT_A8B8G8R8_SINT_PACK32, | 141 | VK_FORMAT_A8B8G8R8_SINT_PACK32, |
| 134 | VK_FORMAT_A8B8G8R8_SNORM_PACK32, | 142 | VK_FORMAT_A8B8G8R8_SNORM_PACK32, |
| 135 | VK_FORMAT_A8B8G8R8_SRGB_PACK32, | 143 | VK_FORMAT_A8B8G8R8_SRGB_PACK32, |