summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/k_hardware_timer.h9
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp11
-rw-r--r--src/core/hle/kernel/k_resource_limit.h3
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp2
-rw-r--r--src/core/hle/kernel/svc/svc_address_arbiter.cpp3
-rw-r--r--src/core/hle/kernel/svc/svc_condition_variable.cpp3
-rw-r--r--src/core/hle/kernel/svc/svc_ipc.cpp20
-rw-r--r--src/core/hle/kernel/svc/svc_resource_limit.cpp2
-rw-r--r--src/core/hle/kernel/svc/svc_synchronization.cpp16
-rw-r--r--src/core/hle/kernel/svc/svc_thread.cpp29
-rw-r--r--src/core/hle/service/sockets/sockets.h2
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp4
-rw-r--r--src/core/internal_network/network.cpp35
-rw-r--r--src/core/internal_network/network.h2
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt1
-rw-r--r--src/video_core/host_shaders/vulkan_depthstencil_clear.frag12
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp7
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp79
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h19
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp37
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h6
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp8
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
48private: 41private:
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} {}
16KResourceLimit::~KResourceLimit() = default; 17KResourceLimit::~KResourceLimit() = default;
17 18
18void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing) { 19void KResourceLimit::Initialize() {}
19 m_core_timing = core_timing;
20}
21 20
22void KResourceLimit::Finalize() {} 21void KResourceLimit::Finalize() {}
23 22
@@ -86,7 +85,7 @@ Result KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
86} 85}
87 86
88bool KResourceLimit::Reserve(LimitableResource which, s64 value) { 87bool 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
92bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { 91bool 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
155KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size) { 154KResourceLimit* 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
63KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size); 62KResourceLimit* 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
105void SleepThread(Core::System& system, s64 nanoseconds) { 106void 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
40namespace { 40namespace {
41 41
42enum class CallType {
43 Send,
44 Other,
45};
46
42#ifdef _WIN32 47#ifdef _WIN32
43 48
44using socklen_t = int; 49using 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
99Errno TranslateNativeError(int e) { 104Errno 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
201Errno TranslateNativeError(int e) { 214Errno 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
239Errno GetAndLogLastError() { 256Errno 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
743std::pair<s32, Errno> Socket::SendTo(u32 flags, std::span<const u8> message, 764std::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
765Errno Socket::Close() { 786Errno 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
6layout (push_constant) uniform PushConstants {
7 vec4 clear_depth;
8};
9
10void 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{&copy, 1}; 1345 const std::span copy_span{&copy, 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
598void 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
596void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, 620void 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
847VkPipeline 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
823void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, 902void 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
30struct 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
30class BlitImageHelper { 40class BlitImageHelper {
31public: 41public:
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
67private: 81private:
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
442void RasterizerVulkan::DispatchCompute() { 454void 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{&copy, 1}; 852 const std::span copy_span{&copy, 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
248private: 251private:
@@ -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
74constexpr 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
76enum class NvidiaArchitecture { 81enum 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,