diff options
44 files changed, 749 insertions, 331 deletions
diff --git a/src/common/polyfill_thread.h b/src/common/polyfill_thread.h index 5a8d1ce08..b2c929d2f 100644 --- a/src/common/polyfill_thread.h +++ b/src/common/polyfill_thread.h | |||
| @@ -11,6 +11,8 @@ | |||
| 11 | 11 | ||
| 12 | #ifdef __cpp_lib_jthread | 12 | #ifdef __cpp_lib_jthread |
| 13 | 13 | ||
| 14 | #include <chrono> | ||
| 15 | #include <condition_variable> | ||
| 14 | #include <stop_token> | 16 | #include <stop_token> |
| 15 | #include <thread> | 17 | #include <thread> |
| 16 | 18 | ||
| @@ -21,11 +23,23 @@ void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred&& pred) { | |||
| 21 | cv.wait(lock, token, std::move(pred)); | 23 | cv.wait(lock, token, std::move(pred)); |
| 22 | } | 24 | } |
| 23 | 25 | ||
| 26 | template <typename Rep, typename Period> | ||
| 27 | bool StoppableTimedWait(std::stop_token token, const std::chrono::duration<Rep, Period>& rel_time) { | ||
| 28 | std::condition_variable_any cv; | ||
| 29 | std::mutex m; | ||
| 30 | |||
| 31 | // Perform the timed wait. | ||
| 32 | std::unique_lock lk{m}; | ||
| 33 | return !cv.wait_for(lk, token, rel_time, [&] { return token.stop_requested(); }); | ||
| 34 | } | ||
| 35 | |||
| 24 | } // namespace Common | 36 | } // namespace Common |
| 25 | 37 | ||
| 26 | #else | 38 | #else |
| 27 | 39 | ||
| 28 | #include <atomic> | 40 | #include <atomic> |
| 41 | #include <chrono> | ||
| 42 | #include <condition_variable> | ||
| 29 | #include <functional> | 43 | #include <functional> |
| 30 | #include <list> | 44 | #include <list> |
| 31 | #include <memory> | 45 | #include <memory> |
| @@ -318,6 +332,28 @@ void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred pred) { | |||
| 318 | cv.wait(lock, [&] { return pred() || token.stop_requested(); }); | 332 | cv.wait(lock, [&] { return pred() || token.stop_requested(); }); |
| 319 | } | 333 | } |
| 320 | 334 | ||
| 335 | template <typename Rep, typename Period> | ||
| 336 | bool StoppableTimedWait(std::stop_token token, const std::chrono::duration<Rep, Period>& rel_time) { | ||
| 337 | if (token.stop_requested()) { | ||
| 338 | return false; | ||
| 339 | } | ||
| 340 | |||
| 341 | bool stop_requested = false; | ||
| 342 | std::condition_variable cv; | ||
| 343 | std::mutex m; | ||
| 344 | |||
| 345 | std::stop_callback cb(token, [&] { | ||
| 346 | // Wake up the waiting thread. | ||
| 347 | std::unique_lock lk{m}; | ||
| 348 | stop_requested = true; | ||
| 349 | cv.notify_one(); | ||
| 350 | }); | ||
| 351 | |||
| 352 | // Perform the timed wait. | ||
| 353 | std::unique_lock lk{m}; | ||
| 354 | return !cv.wait_for(lk, rel_time, [&] { return stop_requested; }); | ||
| 355 | } | ||
| 356 | |||
| 321 | } // namespace Common | 357 | } // namespace Common |
| 322 | 358 | ||
| 323 | #endif | 359 | #endif |
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 124149697..0c6b20db3 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp | |||
| @@ -171,7 +171,7 @@ Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) | |||
| 171 | R_UNLESS(owner_thread != nullptr, ResultInvalidHandle); | 171 | R_UNLESS(owner_thread != nullptr, ResultInvalidHandle); |
| 172 | 172 | ||
| 173 | // Update the lock. | 173 | // Update the lock. |
| 174 | cur_thread->SetAddressKey(addr, value); | 174 | cur_thread->SetUserAddressKey(addr, value); |
| 175 | owner_thread->AddWaiter(cur_thread); | 175 | owner_thread->AddWaiter(cur_thread); |
| 176 | 176 | ||
| 177 | // Begin waiting. | 177 | // Begin waiting. |
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 43185320d..d791acbe3 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp | |||
| @@ -68,7 +68,7 @@ bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { | |||
| 68 | 68 | ||
| 69 | // Add the current thread as a waiter on the owner. | 69 | // Add the current thread as a waiter on the owner. |
| 70 | KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL); | 70 | KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL); |
| 71 | cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag))); | 71 | cur_thread->SetKernelAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag))); |
| 72 | owner_thread->AddWaiter(cur_thread); | 72 | owner_thread->AddWaiter(cur_thread); |
| 73 | 73 | ||
| 74 | // Begin waiting to hold the lock. | 74 | // Begin waiting to hold the lock. |
diff --git a/src/core/hle/kernel/k_memory_layout.h b/src/core/hle/kernel/k_memory_layout.h index fd6e1d3e6..17fa1a6ed 100644 --- a/src/core/hle/kernel/k_memory_layout.h +++ b/src/core/hle/kernel/k_memory_layout.h | |||
| @@ -67,9 +67,9 @@ constexpr size_t KernelPageBufferAdditionalSize = 0x33C000; | |||
| 67 | constexpr std::size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize + | 67 | constexpr std::size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize + |
| 68 | KernelSlabHeapSize + KernelPageBufferHeapSize; | 68 | KernelSlabHeapSize + KernelPageBufferHeapSize; |
| 69 | 69 | ||
| 70 | constexpr bool IsKernelAddressKey(VAddr key) { | 70 | //! NB: Use KThread::GetAddressKeyIsKernel(). |
| 71 | return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast; | 71 | //! See explanation for deviation of GetAddressKey. |
| 72 | } | 72 | bool IsKernelAddressKey(VAddr key) = delete; |
| 73 | 73 | ||
| 74 | constexpr bool IsKernelAddress(VAddr address) { | 74 | constexpr bool IsKernelAddress(VAddr address) { |
| 75 | return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; | 75 | return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 21207fe99..84ff3c64b 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -330,7 +330,7 @@ void KThread::Finalize() { | |||
| 330 | KThread* const waiter = std::addressof(*it); | 330 | KThread* const waiter = std::addressof(*it); |
| 331 | 331 | ||
| 332 | // The thread shouldn't be a kernel waiter. | 332 | // The thread shouldn't be a kernel waiter. |
| 333 | ASSERT(!IsKernelAddressKey(waiter->GetAddressKey())); | 333 | ASSERT(!waiter->GetAddressKeyIsKernel()); |
| 334 | 334 | ||
| 335 | // Clear the lock owner. | 335 | // Clear the lock owner. |
| 336 | waiter->SetLockOwner(nullptr); | 336 | waiter->SetLockOwner(nullptr); |
| @@ -763,19 +763,6 @@ void KThread::Continue() { | |||
| 763 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | 763 | KScheduler::OnThreadStateChanged(kernel, this, old_state); |
| 764 | } | 764 | } |
| 765 | 765 | ||
| 766 | void KThread::WaitUntilSuspended() { | ||
| 767 | // Make sure we have a suspend requested. | ||
| 768 | ASSERT(IsSuspendRequested()); | ||
| 769 | |||
| 770 | // Loop until the thread is not executing on any core. | ||
| 771 | for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) { | ||
| 772 | KThread* core_thread{}; | ||
| 773 | do { | ||
| 774 | core_thread = kernel.Scheduler(i).GetSchedulerCurrentThread(); | ||
| 775 | } while (core_thread == this); | ||
| 776 | } | ||
| 777 | } | ||
| 778 | |||
| 779 | Result KThread::SetActivity(Svc::ThreadActivity activity) { | 766 | Result KThread::SetActivity(Svc::ThreadActivity activity) { |
| 780 | // Lock ourselves. | 767 | // Lock ourselves. |
| 781 | KScopedLightLock lk(activity_pause_lock); | 768 | KScopedLightLock lk(activity_pause_lock); |
| @@ -897,7 +884,7 @@ void KThread::AddWaiterImpl(KThread* thread) { | |||
| 897 | } | 884 | } |
| 898 | 885 | ||
| 899 | // Keep track of how many kernel waiters we have. | 886 | // Keep track of how many kernel waiters we have. |
| 900 | if (IsKernelAddressKey(thread->GetAddressKey())) { | 887 | if (thread->GetAddressKeyIsKernel()) { |
| 901 | ASSERT((num_kernel_waiters++) >= 0); | 888 | ASSERT((num_kernel_waiters++) >= 0); |
| 902 | KScheduler::SetSchedulerUpdateNeeded(kernel); | 889 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 903 | } | 890 | } |
| @@ -911,7 +898,7 @@ void KThread::RemoveWaiterImpl(KThread* thread) { | |||
| 911 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 898 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 912 | 899 | ||
| 913 | // Keep track of how many kernel waiters we have. | 900 | // Keep track of how many kernel waiters we have. |
| 914 | if (IsKernelAddressKey(thread->GetAddressKey())) { | 901 | if (thread->GetAddressKeyIsKernel()) { |
| 915 | ASSERT((num_kernel_waiters--) > 0); | 902 | ASSERT((num_kernel_waiters--) > 0); |
| 916 | KScheduler::SetSchedulerUpdateNeeded(kernel); | 903 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 917 | } | 904 | } |
| @@ -987,7 +974,7 @@ KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) { | |||
| 987 | KThread* thread = std::addressof(*it); | 974 | KThread* thread = std::addressof(*it); |
| 988 | 975 | ||
| 989 | // Keep track of how many kernel waiters we have. | 976 | // Keep track of how many kernel waiters we have. |
| 990 | if (IsKernelAddressKey(thread->GetAddressKey())) { | 977 | if (thread->GetAddressKeyIsKernel()) { |
| 991 | ASSERT((num_kernel_waiters--) > 0); | 978 | ASSERT((num_kernel_waiters--) > 0); |
| 992 | KScheduler::SetSchedulerUpdateNeeded(kernel); | 979 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 993 | } | 980 | } |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 7cd94a340..9d771de0e 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -214,8 +214,6 @@ public: | |||
| 214 | 214 | ||
| 215 | void Continue(); | 215 | void Continue(); |
| 216 | 216 | ||
| 217 | void WaitUntilSuspended(); | ||
| 218 | |||
| 219 | constexpr void SetSyncedIndex(s32 index) { | 217 | constexpr void SetSyncedIndex(s32 index) { |
| 220 | synced_index = index; | 218 | synced_index = index; |
| 221 | } | 219 | } |
| @@ -607,13 +605,30 @@ public: | |||
| 607 | return address_key_value; | 605 | return address_key_value; |
| 608 | } | 606 | } |
| 609 | 607 | ||
| 610 | void SetAddressKey(VAddr key) { | 608 | [[nodiscard]] bool GetAddressKeyIsKernel() const { |
| 609 | return address_key_is_kernel; | ||
| 610 | } | ||
| 611 | |||
| 612 | //! NB: intentional deviation from official kernel. | ||
| 613 | // | ||
| 614 | // Separate SetAddressKey into user and kernel versions | ||
| 615 | // to cope with arbitrary host pointers making their way | ||
| 616 | // into things. | ||
| 617 | |||
| 618 | void SetUserAddressKey(VAddr key) { | ||
| 611 | address_key = key; | 619 | address_key = key; |
| 620 | address_key_is_kernel = false; | ||
| 612 | } | 621 | } |
| 613 | 622 | ||
| 614 | void SetAddressKey(VAddr key, u32 val) { | 623 | void SetUserAddressKey(VAddr key, u32 val) { |
| 615 | address_key = key; | 624 | address_key = key; |
| 616 | address_key_value = val; | 625 | address_key_value = val; |
| 626 | address_key_is_kernel = false; | ||
| 627 | } | ||
| 628 | |||
| 629 | void SetKernelAddressKey(VAddr key) { | ||
| 630 | address_key = key; | ||
| 631 | address_key_is_kernel = true; | ||
| 617 | } | 632 | } |
| 618 | 633 | ||
| 619 | void ClearWaitQueue() { | 634 | void ClearWaitQueue() { |
| @@ -772,6 +787,7 @@ private: | |||
| 772 | bool debug_attached{}; | 787 | bool debug_attached{}; |
| 773 | s8 priority_inheritance_count{}; | 788 | s8 priority_inheritance_count{}; |
| 774 | bool resource_limit_release_hint{}; | 789 | bool resource_limit_release_hint{}; |
| 790 | bool address_key_is_kernel{}; | ||
| 775 | StackParameters stack_parameters{}; | 791 | StackParameters stack_parameters{}; |
| 776 | Common::SpinLock context_guard{}; | 792 | Common::SpinLock context_guard{}; |
| 777 | 793 | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1fb25f221..d9eafe261 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -1198,28 +1198,35 @@ void KernelCore::Suspend(bool suspended) { | |||
| 1198 | const bool should_suspend{exception_exited || suspended}; | 1198 | const bool should_suspend{exception_exited || suspended}; |
| 1199 | const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable; | 1199 | const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable; |
| 1200 | 1200 | ||
| 1201 | std::vector<KScopedAutoObject<KThread>> process_threads; | 1201 | //! This refers to the application process, not the current process. |
| 1202 | { | 1202 | KScopedAutoObject<KProcess> process = CurrentProcess(); |
| 1203 | KScopedSchedulerLock sl{*this}; | 1203 | if (process.IsNull()) { |
| 1204 | return; | ||
| 1205 | } | ||
| 1204 | 1206 | ||
| 1205 | if (auto* process = CurrentProcess(); process != nullptr) { | 1207 | // Set the new activity. |
| 1206 | process->SetActivity(activity); | 1208 | process->SetActivity(activity); |
| 1207 | 1209 | ||
| 1208 | if (!should_suspend) { | 1210 | // Wait for process execution to stop. |
| 1209 | // Runnable now; no need to wait. | 1211 | bool must_wait{should_suspend}; |
| 1210 | return; | 1212 | |
| 1211 | } | 1213 | // KernelCore::Suspend must be called from locked context, or we |
| 1214 | // could race another call to SetActivity, interfering with waiting. | ||
| 1215 | while (must_wait) { | ||
| 1216 | KScopedSchedulerLock sl{*this}; | ||
| 1217 | |||
| 1218 | // Assume that all threads have finished running. | ||
| 1219 | must_wait = false; | ||
| 1212 | 1220 | ||
| 1213 | for (auto* thread : process->GetThreadList()) { | 1221 | for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { |
| 1214 | process_threads.emplace_back(thread); | 1222 | if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() == |
| 1223 | process.GetPointerUnsafe()) { | ||
| 1224 | // A thread has not finished running yet. | ||
| 1225 | // Continue waiting. | ||
| 1226 | must_wait = true; | ||
| 1215 | } | 1227 | } |
| 1216 | } | 1228 | } |
| 1217 | } | 1229 | } |
| 1218 | |||
| 1219 | // Wait for execution to stop. | ||
| 1220 | for (auto& thread : process_threads) { | ||
| 1221 | thread->WaitUntilSuspended(); | ||
| 1222 | } | ||
| 1223 | } | 1230 | } |
| 1224 | 1231 | ||
| 1225 | void KernelCore::ShutdownCores() { | 1232 | void KernelCore::ShutdownCores() { |
diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index ecb3e9dc2..d09ff178b 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "common/param_package.h" | 8 | #include "common/param_package.h" |
| 9 | #include "common/polyfill_thread.h" | ||
| 9 | #include "common/settings_input.h" | 10 | #include "common/settings_input.h" |
| 10 | #include "common/thread.h" | 11 | #include "common/thread.h" |
| 11 | #include "input_common/drivers/gc_adapter.h" | 12 | #include "input_common/drivers/gc_adapter.h" |
| @@ -217,8 +218,7 @@ void GCAdapter::AdapterScanThread(std::stop_token stop_token) { | |||
| 217 | Common::SetCurrentThreadName("ScanGCAdapter"); | 218 | Common::SetCurrentThreadName("ScanGCAdapter"); |
| 218 | usb_adapter_handle = nullptr; | 219 | usb_adapter_handle = nullptr; |
| 219 | pads = {}; | 220 | pads = {}; |
| 220 | while (!stop_token.stop_requested() && !Setup()) { | 221 | while (!Setup() && Common::StoppableTimedWait(stop_token, std::chrono::seconds{2})) { |
| 221 | std::this_thread::sleep_for(std::chrono::seconds(2)); | ||
| 222 | } | 222 | } |
| 223 | } | 223 | } |
| 224 | 224 | ||
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index 40cda400d..cedc94e63 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/param_package.h" | 6 | #include "common/param_package.h" |
| 7 | #include "common/polyfill_ranges.h" | 7 | #include "common/polyfill_ranges.h" |
| 8 | #include "common/polyfill_thread.h" | ||
| 8 | #include "common/settings.h" | 9 | #include "common/settings.h" |
| 9 | #include "common/thread.h" | 10 | #include "common/thread.h" |
| 10 | #include "input_common/drivers/joycon.h" | 11 | #include "input_common/drivers/joycon.h" |
| @@ -67,7 +68,8 @@ void Joycons::Setup() { | |||
| 67 | void Joycons::ScanThread(std::stop_token stop_token) { | 68 | void Joycons::ScanThread(std::stop_token stop_token) { |
| 68 | constexpr u16 nintendo_vendor_id = 0x057e; | 69 | constexpr u16 nintendo_vendor_id = 0x057e; |
| 69 | Common::SetCurrentThreadName("JoyconScanThread"); | 70 | Common::SetCurrentThreadName("JoyconScanThread"); |
| 70 | while (!stop_token.stop_requested()) { | 71 | |
| 72 | do { | ||
| 71 | SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0); | 73 | SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0); |
| 72 | SDL_hid_device_info* cur_dev = devs; | 74 | SDL_hid_device_info* cur_dev = devs; |
| 73 | 75 | ||
| @@ -81,8 +83,7 @@ void Joycons::ScanThread(std::stop_token stop_token) { | |||
| 81 | } | 83 | } |
| 82 | 84 | ||
| 83 | SDL_hid_free_enumeration(devs); | 85 | SDL_hid_free_enumeration(devs); |
| 84 | std::this_thread::sleep_for(std::chrono::seconds(5)); | 86 | } while (Common::StoppableTimedWait(stop_token, std::chrono::seconds{5})); |
| 85 | } | ||
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { | 89 | bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index 0cb1e193e..fd4a61a4d 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp | |||
| @@ -279,6 +279,8 @@ void SetupOptions(const IR::Program& program, const Profile& profile, | |||
| 279 | header += "OPTION NV_internal;" | 279 | header += "OPTION NV_internal;" |
| 280 | "OPTION NV_shader_storage_buffer;" | 280 | "OPTION NV_shader_storage_buffer;" |
| 281 | "OPTION NV_gpu_program_fp64;"; | 281 | "OPTION NV_gpu_program_fp64;"; |
| 282 | // TODO: Enable only when MS is used | ||
| 283 | header += "OPTION NV_texture_multisample;"; | ||
| 282 | if (info.uses_int64_bit_atomics) { | 284 | if (info.uses_int64_bit_atomics) { |
| 283 | header += "OPTION NV_shader_atomic_int64;"; | 285 | header += "OPTION NV_shader_atomic_int64;"; |
| 284 | } | 286 | } |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp index 5bfdecc09..2fc2a0ac6 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp | |||
| @@ -43,10 +43,6 @@ void EmitBitCastU64F64(EmitContext&, IR::Inst& inst, const IR::Value& value) { | |||
| 43 | Alias(inst, value); | 43 | Alias(inst, value); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void EmitBitCastS32F32(EmitContext&, IR::Inst& inst, const IR::Value& value) { | ||
| 47 | Alias(inst, value); | ||
| 48 | } | ||
| 49 | |||
| 50 | void EmitBitCastF16U16(EmitContext&, IR::Inst& inst, const IR::Value& value) { | 46 | void EmitBitCastF16U16(EmitContext&, IR::Inst& inst, const IR::Value& value) { |
| 51 | Alias(inst, value); | 47 | Alias(inst, value); |
| 52 | } | 48 | } |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp index e67e80fac..cf6065208 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp | |||
| @@ -59,7 +59,7 @@ std::string Image(EmitContext& ctx, IR::TextureInstInfo info, | |||
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | std::string_view TextureType(IR::TextureInstInfo info) { | 62 | std::string_view TextureType(IR::TextureInstInfo info, bool is_ms = false) { |
| 63 | if (info.is_depth) { | 63 | if (info.is_depth) { |
| 64 | switch (info.type) { | 64 | switch (info.type) { |
| 65 | case TextureType::Color1D: | 65 | case TextureType::Color1D: |
| @@ -88,9 +88,9 @@ std::string_view TextureType(IR::TextureInstInfo info) { | |||
| 88 | return "ARRAY1D"; | 88 | return "ARRAY1D"; |
| 89 | case TextureType::Color2D: | 89 | case TextureType::Color2D: |
| 90 | case TextureType::Color2DRect: | 90 | case TextureType::Color2DRect: |
| 91 | return "2D"; | 91 | return is_ms ? "2DMS" : "2D"; |
| 92 | case TextureType::ColorArray2D: | 92 | case TextureType::ColorArray2D: |
| 93 | return "ARRAY2D"; | 93 | return is_ms ? "ARRAY2DMS" : "ARRAY2D"; |
| 94 | case TextureType::Color3D: | 94 | case TextureType::Color3D: |
| 95 | return "3D"; | 95 | return "3D"; |
| 96 | case TextureType::ColorCube: | 96 | case TextureType::ColorCube: |
| @@ -510,15 +510,16 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | |||
| 510 | const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms) { | 510 | const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms) { |
| 511 | const auto info{inst.Flags<IR::TextureInstInfo>()}; | 511 | const auto info{inst.Flags<IR::TextureInstInfo>()}; |
| 512 | const auto sparse_inst{PrepareSparse(inst)}; | 512 | const auto sparse_inst{PrepareSparse(inst)}; |
| 513 | const bool is_multisample{ms.type != Type::Void}; | ||
| 513 | const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""}; | 514 | const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""}; |
| 514 | const std::string_view type{TextureType(info)}; | 515 | const std::string_view type{TextureType(info, is_multisample)}; |
| 515 | const std::string texture{Texture(ctx, info, index)}; | 516 | const std::string texture{Texture(ctx, info, index)}; |
| 516 | const std::string offset_vec{Offset(ctx, offset)}; | 517 | const std::string offset_vec{Offset(ctx, offset)}; |
| 517 | const auto [coord_vec, coord_alloc]{Coord(ctx, coord)}; | 518 | const auto [coord_vec, coord_alloc]{Coord(ctx, coord)}; |
| 518 | const Register ret{ctx.reg_alloc.Define(inst)}; | 519 | const Register ret{ctx.reg_alloc.Define(inst)}; |
| 519 | if (info.type == TextureType::Buffer) { | 520 | if (info.type == TextureType::Buffer) { |
| 520 | ctx.Add("TXF.F{} {},{},{},{}{};", sparse_mod, ret, coord_vec, texture, type, offset_vec); | 521 | ctx.Add("TXF.F{} {},{},{},{}{};", sparse_mod, ret, coord_vec, texture, type, offset_vec); |
| 521 | } else if (ms.type != Type::Void) { | 522 | } else if (is_multisample) { |
| 522 | ctx.Add("MOV.S {}.w,{};" | 523 | ctx.Add("MOV.S {}.w,{};" |
| 523 | "TXFMS.F{} {},{},{},{}{};", | 524 | "TXFMS.F{} {},{},{},{}{};", |
| 524 | coord_vec, ms, sparse_mod, ret, coord_vec, texture, type, offset_vec); | 525 | coord_vec, ms, sparse_mod, ret, coord_vec, texture, type, offset_vec); |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h index eaaf9ba39..415a249e4 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h +++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h | |||
| @@ -197,7 +197,6 @@ void EmitSelectF64(EmitContext& ctx, ScalarS32 cond, Register true_value, Regist | |||
| 197 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 197 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 198 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 198 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 199 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 199 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 200 | void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||
| 201 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 200 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 202 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 201 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 203 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 202 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp index 8e5e6cf1f..1be4a0f59 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp | |||
| @@ -48,10 +48,6 @@ void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value) | |||
| 48 | ctx.AddU64("{}=doubleBitsToUint64({});", inst, value); | 48 | ctx.AddU64("{}=doubleBitsToUint64({});", inst, value); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { | ||
| 52 | ctx.AddF32("{}=ftoi({});", inst, value); | ||
| 53 | } | ||
| 54 | |||
| 55 | void EmitBitCastF16U16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst) { | 51 | void EmitBitCastF16U16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst) { |
| 56 | NotImplemented(); | 52 | NotImplemented(); |
| 57 | } | 53 | } |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp index cecdbb9d6..d8874b0cc 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp | |||
| @@ -414,7 +414,7 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde | |||
| 414 | 414 | ||
| 415 | void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 415 | void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| 416 | std::string_view coords, std::string_view offset, std::string_view lod, | 416 | std::string_view coords, std::string_view offset, std::string_view lod, |
| 417 | [[maybe_unused]] std::string_view ms) { | 417 | std::string_view ms) { |
| 418 | const auto info{inst.Flags<IR::TextureInstInfo>()}; | 418 | const auto info{inst.Flags<IR::TextureInstInfo>()}; |
| 419 | if (info.has_bias) { | 419 | if (info.has_bias) { |
| 420 | throw NotImplementedException("EmitImageFetch Bias texture samples"); | 420 | throw NotImplementedException("EmitImageFetch Bias texture samples"); |
| @@ -431,19 +431,24 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | |||
| 431 | ctx.AddU1("{}=true;", *sparse_inst); | 431 | ctx.AddU1("{}=true;", *sparse_inst); |
| 432 | } | 432 | } |
| 433 | if (!sparse_inst || !supports_sparse) { | 433 | if (!sparse_inst || !supports_sparse) { |
| 434 | if (!offset.empty()) { | 434 | const auto int_coords{CoordsCastToInt(coords, info)}; |
| 435 | ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture, | 435 | if (!ms.empty()) { |
| 436 | CoordsCastToInt(coords, info), lod, CoordsCastToInt(offset, info)); | 436 | ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, ms); |
| 437 | } else if (!offset.empty()) { | ||
| 438 | ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture, int_coords, lod, | ||
| 439 | CoordsCastToInt(offset, info)); | ||
| 437 | } else { | 440 | } else { |
| 438 | if (info.type == TextureType::Buffer) { | 441 | if (info.type == TextureType::Buffer) { |
| 439 | ctx.Add("{}=texelFetch({},int({}));", texel, texture, coords); | 442 | ctx.Add("{}=texelFetch({},int({}));", texel, texture, coords); |
| 440 | } else { | 443 | } else { |
| 441 | ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, | 444 | ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, lod); |
| 442 | CoordsCastToInt(coords, info), lod); | ||
| 443 | } | 445 | } |
| 444 | } | 446 | } |
| 445 | return; | 447 | return; |
| 446 | } | 448 | } |
| 449 | if (!ms.empty()) { | ||
| 450 | throw NotImplementedException("EmitImageFetch Sparse MSAA samples"); | ||
| 451 | } | ||
| 447 | if (!offset.empty()) { | 452 | if (!offset.empty()) { |
| 448 | ctx.AddU1("{}=sparseTexelsResidentARB(sparseTexelFetchOffsetARB({},{},int({}),{},{}));", | 453 | ctx.AddU1("{}=sparseTexelsResidentARB(sparseTexelFetchOffsetARB({},{},int({}),{},{}));", |
| 449 | *sparse_inst, texture, CastToIntVec(coords, info), lod, | 454 | *sparse_inst, texture, CastToIntVec(coords, info), lod, |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h index 4151c89de..c6df1dba7 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h +++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h | |||
| @@ -231,7 +231,6 @@ void EmitSelectF64(EmitContext& ctx, IR::Inst& inst, std::string_view cond, | |||
| 231 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst); | 231 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst); |
| 232 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 232 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
| 233 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 233 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
| 234 | void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | ||
| 235 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst); | 234 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst); |
| 236 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 235 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
| 237 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 236 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index 5d01ec0cd..1b006e811 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp | |||
| @@ -61,24 +61,28 @@ std::string OutputDecorator(Stage stage, u32 size) { | |||
| 61 | } | 61 | } |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | std::string_view SamplerType(TextureType type, bool is_depth) { | 64 | std::string_view DepthSamplerType(TextureType type) { |
| 65 | if (is_depth) { | 65 | switch (type) { |
| 66 | switch (type) { | 66 | case TextureType::Color1D: |
| 67 | case TextureType::Color1D: | 67 | return "sampler1DShadow"; |
| 68 | return "sampler1DShadow"; | 68 | case TextureType::ColorArray1D: |
| 69 | case TextureType::ColorArray1D: | 69 | return "sampler1DArrayShadow"; |
| 70 | return "sampler1DArrayShadow"; | 70 | case TextureType::Color2D: |
| 71 | case TextureType::Color2D: | 71 | return "sampler2DShadow"; |
| 72 | return "sampler2DShadow"; | 72 | case TextureType::ColorArray2D: |
| 73 | case TextureType::ColorArray2D: | 73 | return "sampler2DArrayShadow"; |
| 74 | return "sampler2DArrayShadow"; | 74 | case TextureType::ColorCube: |
| 75 | case TextureType::ColorCube: | 75 | return "samplerCubeShadow"; |
| 76 | return "samplerCubeShadow"; | 76 | case TextureType::ColorArrayCube: |
| 77 | case TextureType::ColorArrayCube: | 77 | return "samplerCubeArrayShadow"; |
| 78 | return "samplerCubeArrayShadow"; | 78 | default: |
| 79 | default: | 79 | throw NotImplementedException("Texture type: {}", type); |
| 80 | throw NotImplementedException("Texture type: {}", type); | 80 | } |
| 81 | } | 81 | } |
| 82 | |||
| 83 | std::string_view ColorSamplerType(TextureType type, bool is_multisample = false) { | ||
| 84 | if (is_multisample) { | ||
| 85 | ASSERT(type == TextureType::Color2D || type == TextureType::ColorArray2D); | ||
| 82 | } | 86 | } |
| 83 | switch (type) { | 87 | switch (type) { |
| 84 | case TextureType::Color1D: | 88 | case TextureType::Color1D: |
| @@ -87,9 +91,9 @@ std::string_view SamplerType(TextureType type, bool is_depth) { | |||
| 87 | return "sampler1DArray"; | 91 | return "sampler1DArray"; |
| 88 | case TextureType::Color2D: | 92 | case TextureType::Color2D: |
| 89 | case TextureType::Color2DRect: | 93 | case TextureType::Color2DRect: |
| 90 | return "sampler2D"; | 94 | return is_multisample ? "sampler2DMS" : "sampler2D"; |
| 91 | case TextureType::ColorArray2D: | 95 | case TextureType::ColorArray2D: |
| 92 | return "sampler2DArray"; | 96 | return is_multisample ? "sampler2DMSArray" : "sampler2DArray"; |
| 93 | case TextureType::Color3D: | 97 | case TextureType::Color3D: |
| 94 | return "sampler3D"; | 98 | return "sampler3D"; |
| 95 | case TextureType::ColorCube: | 99 | case TextureType::ColorCube: |
| @@ -677,7 +681,7 @@ void EmitContext::SetupTextures(Bindings& bindings) { | |||
| 677 | texture_buffers.reserve(info.texture_buffer_descriptors.size()); | 681 | texture_buffers.reserve(info.texture_buffer_descriptors.size()); |
| 678 | for (const auto& desc : info.texture_buffer_descriptors) { | 682 | for (const auto& desc : info.texture_buffer_descriptors) { |
| 679 | texture_buffers.push_back({bindings.texture, desc.count}); | 683 | texture_buffers.push_back({bindings.texture, desc.count}); |
| 680 | const auto sampler_type{SamplerType(TextureType::Buffer, false)}; | 684 | const auto sampler_type{ColorSamplerType(TextureType::Buffer)}; |
| 681 | const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; | 685 | const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; |
| 682 | header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, | 686 | header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, |
| 683 | sampler_type, bindings.texture, array_decorator); | 687 | sampler_type, bindings.texture, array_decorator); |
| @@ -686,7 +690,8 @@ void EmitContext::SetupTextures(Bindings& bindings) { | |||
| 686 | textures.reserve(info.texture_descriptors.size()); | 690 | textures.reserve(info.texture_descriptors.size()); |
| 687 | for (const auto& desc : info.texture_descriptors) { | 691 | for (const auto& desc : info.texture_descriptors) { |
| 688 | textures.push_back({bindings.texture, desc.count}); | 692 | textures.push_back({bindings.texture, desc.count}); |
| 689 | const auto sampler_type{SamplerType(desc.type, desc.is_depth)}; | 693 | const auto sampler_type{desc.is_depth ? DepthSamplerType(desc.type) |
| 694 | : ColorSamplerType(desc.type, desc.is_multisample)}; | ||
| 690 | const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; | 695 | const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; |
| 691 | header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, | 696 | header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, |
| 692 | sampler_type, bindings.texture, array_decorator); | 697 | sampler_type, bindings.texture, array_decorator); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp index 50daacd95..c4ca28d11 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp | |||
| @@ -18,10 +18,6 @@ void EmitBitCastU64F64(EmitContext&) { | |||
| 18 | throw NotImplementedException("SPIR-V Instruction"); | 18 | throw NotImplementedException("SPIR-V Instruction"); |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | void EmitBitCastS32F32(EmitContext&) { | ||
| 22 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 23 | } | ||
| 24 | |||
| 25 | void EmitBitCastF16U16(EmitContext&) { | 21 | void EmitBitCastF16U16(EmitContext&) { |
| 26 | throw NotImplementedException("SPIR-V Instruction"); | 22 | throw NotImplementedException("SPIR-V Instruction"); |
| 27 | } | 23 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index e31cdc5e8..db12e8176 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h | |||
| @@ -179,7 +179,6 @@ Id EmitSelectF64(EmitContext& ctx, Id cond, Id true_value, Id false_value); | |||
| 179 | void EmitBitCastU16F16(EmitContext& ctx); | 179 | void EmitBitCastU16F16(EmitContext& ctx); |
| 180 | Id EmitBitCastU32F32(EmitContext& ctx, Id value); | 180 | Id EmitBitCastU32F32(EmitContext& ctx, Id value); |
| 181 | void EmitBitCastU64F64(EmitContext& ctx); | 181 | void EmitBitCastU64F64(EmitContext& ctx); |
| 182 | void EmitBitCastS32F32(EmitContext& ctx); | ||
| 183 | void EmitBitCastF16U16(EmitContext&); | 182 | void EmitBitCastF16U16(EmitContext&); |
| 184 | Id EmitBitCastF32U32(EmitContext& ctx, Id value); | 183 | Id EmitBitCastF32U32(EmitContext& ctx, Id value); |
| 185 | void EmitBitCastF64U64(EmitContext& ctx); | 184 | void EmitBitCastF64U64(EmitContext& ctx); |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index eb2e49a68..430797d23 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -704,11 +704,6 @@ IR::U32 IREmitter::BitCast<IR::U32, IR::F32>(const IR::F32& value) { | |||
| 704 | } | 704 | } |
| 705 | 705 | ||
| 706 | template <> | 706 | template <> |
| 707 | IR::S32 IREmitter::BitCast<IR::S32, IR::F32>(const IR::F32& value) { | ||
| 708 | return Inst<IR::S32>(Opcode::BitCastS32F32, value); | ||
| 709 | } | ||
| 710 | |||
| 711 | template <> | ||
| 712 | IR::F32 IREmitter::BitCast<IR::F32, IR::U32>(const IR::U32& value) { | 707 | IR::F32 IREmitter::BitCast<IR::F32, IR::U32>(const IR::U32& value) { |
| 713 | return Inst<IR::F32>(Opcode::BitCastF32U32, value); | 708 | return Inst<IR::F32>(Opcode::BitCastF32U32, value); |
| 714 | } | 709 | } |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.h b/src/shader_recompiler/frontend/ir/opcodes.h index d155afd0f..e300714f3 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.h +++ b/src/shader_recompiler/frontend/ir/opcodes.h | |||
| @@ -38,7 +38,6 @@ constexpr Type U8{Type::U8}; | |||
| 38 | constexpr Type U16{Type::U16}; | 38 | constexpr Type U16{Type::U16}; |
| 39 | constexpr Type U32{Type::U32}; | 39 | constexpr Type U32{Type::U32}; |
| 40 | constexpr Type U64{Type::U64}; | 40 | constexpr Type U64{Type::U64}; |
| 41 | constexpr Type S32{Type::S32}; | ||
| 42 | constexpr Type F16{Type::F16}; | 41 | constexpr Type F16{Type::F16}; |
| 43 | constexpr Type F32{Type::F32}; | 42 | constexpr Type F32{Type::F32}; |
| 44 | constexpr Type F64{Type::F64}; | 43 | constexpr Type F64{Type::F64}; |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 1fe3749cc..24e82f802 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -175,7 +175,6 @@ OPCODE(SelectF64, F64, U1, | |||
| 175 | OPCODE(BitCastU16F16, U16, F16, ) | 175 | OPCODE(BitCastU16F16, U16, F16, ) |
| 176 | OPCODE(BitCastU32F32, U32, F32, ) | 176 | OPCODE(BitCastU32F32, U32, F32, ) |
| 177 | OPCODE(BitCastU64F64, U64, F64, ) | 177 | OPCODE(BitCastU64F64, U64, F64, ) |
| 178 | OPCODE(BitCastS32F32, S32, F32, ) | ||
| 179 | OPCODE(BitCastF16U16, F16, U16, ) | 178 | OPCODE(BitCastF16U16, F16, U16, ) |
| 180 | OPCODE(BitCastF32U32, F32, U32, ) | 179 | OPCODE(BitCastF32U32, F32, U32, ) |
| 181 | OPCODE(BitCastF64U64, F64, U64, ) | 180 | OPCODE(BitCastF64U64, F64, U64, ) |
diff --git a/src/shader_recompiler/frontend/ir/type.h b/src/shader_recompiler/frontend/ir/type.h index 5a7c706ad..04c8c4ddb 100644 --- a/src/shader_recompiler/frontend/ir/type.h +++ b/src/shader_recompiler/frontend/ir/type.h | |||
| @@ -24,22 +24,21 @@ enum class Type { | |||
| 24 | U16 = 1 << 7, | 24 | U16 = 1 << 7, |
| 25 | U32 = 1 << 8, | 25 | U32 = 1 << 8, |
| 26 | U64 = 1 << 9, | 26 | U64 = 1 << 9, |
| 27 | S32 = 1 << 10, | 27 | F16 = 1 << 10, |
| 28 | F16 = 1 << 11, | 28 | F32 = 1 << 11, |
| 29 | F32 = 1 << 12, | 29 | F64 = 1 << 12, |
| 30 | F64 = 1 << 13, | 30 | U32x2 = 1 << 13, |
| 31 | U32x2 = 1 << 14, | 31 | U32x3 = 1 << 14, |
| 32 | U32x3 = 1 << 15, | 32 | U32x4 = 1 << 15, |
| 33 | U32x4 = 1 << 16, | 33 | F16x2 = 1 << 16, |
| 34 | F16x2 = 1 << 17, | 34 | F16x3 = 1 << 17, |
| 35 | F16x3 = 1 << 18, | 35 | F16x4 = 1 << 18, |
| 36 | F16x4 = 1 << 19, | 36 | F32x2 = 1 << 19, |
| 37 | F32x2 = 1 << 20, | 37 | F32x3 = 1 << 20, |
| 38 | F32x3 = 1 << 21, | 38 | F32x4 = 1 << 21, |
| 39 | F32x4 = 1 << 22, | 39 | F64x2 = 1 << 22, |
| 40 | F64x2 = 1 << 23, | 40 | F64x3 = 1 << 23, |
| 41 | F64x3 = 1 << 24, | 41 | F64x4 = 1 << 24, |
| 42 | F64x4 = 1 << 25, | ||
| 43 | }; | 42 | }; |
| 44 | DECLARE_ENUM_FLAG_OPERATORS(Type) | 43 | DECLARE_ENUM_FLAG_OPERATORS(Type) |
| 45 | 44 | ||
diff --git a/src/shader_recompiler/frontend/ir/value.cpp b/src/shader_recompiler/frontend/ir/value.cpp index 30ba12316..346169328 100644 --- a/src/shader_recompiler/frontend/ir/value.cpp +++ b/src/shader_recompiler/frontend/ir/value.cpp | |||
| @@ -23,8 +23,6 @@ Value::Value(u16 value) noexcept : type{Type::U16}, imm_u16{value} {} | |||
| 23 | 23 | ||
| 24 | Value::Value(u32 value) noexcept : type{Type::U32}, imm_u32{value} {} | 24 | Value::Value(u32 value) noexcept : type{Type::U32}, imm_u32{value} {} |
| 25 | 25 | ||
| 26 | Value::Value(s32 value) noexcept : type{Type::S32}, imm_s32{value} {} | ||
| 27 | |||
| 28 | Value::Value(f32 value) noexcept : type{Type::F32}, imm_f32{value} {} | 26 | Value::Value(f32 value) noexcept : type{Type::F32}, imm_f32{value} {} |
| 29 | 27 | ||
| 30 | Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {} | 28 | Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {} |
| @@ -71,7 +69,6 @@ bool Value::operator==(const Value& other) const { | |||
| 71 | return imm_u16 == other.imm_u16; | 69 | return imm_u16 == other.imm_u16; |
| 72 | case Type::U32: | 70 | case Type::U32: |
| 73 | case Type::F32: | 71 | case Type::F32: |
| 74 | case Type::S32: | ||
| 75 | return imm_u32 == other.imm_u32; | 72 | return imm_u32 == other.imm_u32; |
| 76 | case Type::U64: | 73 | case Type::U64: |
| 77 | case Type::F64: | 74 | case Type::F64: |
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index 8b34356fd..883dfa24e 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h | |||
| @@ -268,7 +268,6 @@ using U8 = TypedValue<Type::U8>; | |||
| 268 | using U16 = TypedValue<Type::U16>; | 268 | using U16 = TypedValue<Type::U16>; |
| 269 | using U32 = TypedValue<Type::U32>; | 269 | using U32 = TypedValue<Type::U32>; |
| 270 | using U64 = TypedValue<Type::U64>; | 270 | using U64 = TypedValue<Type::U64>; |
| 271 | using S32 = TypedValue<Type::S32>; | ||
| 272 | using F16 = TypedValue<Type::F16>; | 271 | using F16 = TypedValue<Type::F16>; |
| 273 | using F32 = TypedValue<Type::F32>; | 272 | using F32 = TypedValue<Type::F32>; |
| 274 | using F64 = TypedValue<Type::F64>; | 273 | using F64 = TypedValue<Type::F64>; |
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index 9718c6921..70b620dcb 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -486,10 +486,10 @@ void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_ | |||
| 486 | const IR::F32 w(ir.CompositeExtract(new_inst, 3)); | 486 | const IR::F32 w(ir.CompositeExtract(new_inst, 3)); |
| 487 | const IR::F16F32F64 max_value(ir.Imm32(get_max_value())); | 487 | const IR::F16F32F64 max_value(ir.Imm32(get_max_value())); |
| 488 | const IR::Value converted = | 488 | const IR::Value converted = |
| 489 | ir.CompositeConstruct(ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(x)), max_value), | 489 | ir.CompositeConstruct(ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::U32>(x)), max_value), |
| 490 | ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(y)), max_value), | 490 | ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::U32>(y)), max_value), |
| 491 | ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(z)), max_value), | 491 | ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::U32>(z)), max_value), |
| 492 | ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(w)), max_value)); | 492 | ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::U32>(w)), max_value)); |
| 493 | inst.ReplaceUsesWith(converted); | 493 | inst.ReplaceUsesWith(converted); |
| 494 | } | 494 | } |
| 495 | } // Anonymous namespace | 495 | } // Anonymous namespace |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index b474eb363..4742bcbe9 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -52,6 +52,8 @@ add_library(video_core STATIC | |||
| 52 | engines/puller.cpp | 52 | engines/puller.cpp |
| 53 | engines/puller.h | 53 | engines/puller.h |
| 54 | framebuffer_config.h | 54 | framebuffer_config.h |
| 55 | fsr.cpp | ||
| 56 | fsr.h | ||
| 55 | host1x/codecs/codec.cpp | 57 | host1x/codecs/codec.cpp |
| 56 | host1x/codecs/codec.h | 58 | host1x/codecs/codec.h |
| 57 | host1x/codecs/h264.cpp | 59 | host1x/codecs/h264.cpp |
| @@ -110,6 +112,8 @@ add_library(video_core STATIC | |||
| 110 | renderer_opengl/gl_device.h | 112 | renderer_opengl/gl_device.h |
| 111 | renderer_opengl/gl_fence_manager.cpp | 113 | renderer_opengl/gl_fence_manager.cpp |
| 112 | renderer_opengl/gl_fence_manager.h | 114 | renderer_opengl/gl_fence_manager.h |
| 115 | renderer_opengl/gl_fsr.cpp | ||
| 116 | renderer_opengl/gl_fsr.h | ||
| 113 | renderer_opengl/gl_graphics_pipeline.cpp | 117 | renderer_opengl/gl_graphics_pipeline.cpp |
| 114 | renderer_opengl/gl_graphics_pipeline.h | 118 | renderer_opengl/gl_graphics_pipeline.h |
| 115 | renderer_opengl/gl_rasterizer.cpp | 119 | renderer_opengl/gl_rasterizer.cpp |
diff --git a/src/video_core/fsr.cpp b/src/video_core/fsr.cpp new file mode 100644 index 000000000..5653c64fc --- /dev/null +++ b/src/video_core/fsr.cpp | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <cmath> | ||
| 5 | #include "video_core/fsr.h" | ||
| 6 | |||
| 7 | namespace FSR { | ||
| 8 | namespace { | ||
| 9 | // Reimplementations of the constant generating functions in ffx_fsr1.h | ||
| 10 | // GCC generated a lot of warnings when using the official header. | ||
| 11 | u32 AU1_AH1_AF1(f32 f) { | ||
| 12 | static constexpr u32 base[512]{ | ||
| 13 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 14 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 15 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 16 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 17 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 18 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 19 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 20 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 21 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 22 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, | ||
| 23 | 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, 0x2000, | ||
| 24 | 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x4400, 0x4800, 0x4c00, | ||
| 25 | 0x5000, 0x5400, 0x5800, 0x5c00, 0x6000, 0x6400, 0x6800, 0x6c00, 0x7000, 0x7400, 0x7800, | ||
| 26 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 27 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 28 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 29 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 30 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 31 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 32 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 33 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 34 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 35 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 36 | 0x7bff, 0x7bff, 0x7bff, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 37 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 38 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 39 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 40 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 41 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 42 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 43 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 44 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 45 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001, 0x8002, 0x8004, 0x8008, | ||
| 46 | 0x8010, 0x8020, 0x8040, 0x8080, 0x8100, 0x8200, 0x8400, 0x8800, 0x8c00, 0x9000, 0x9400, | ||
| 47 | 0x9800, 0x9c00, 0xa000, 0xa400, 0xa800, 0xac00, 0xb000, 0xb400, 0xb800, 0xbc00, 0xc000, | ||
| 48 | 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, 0xd800, 0xdc00, 0xe000, 0xe400, 0xe800, 0xec00, | ||
| 49 | 0xf000, 0xf400, 0xf800, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 50 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 51 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 52 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 53 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 54 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 55 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 56 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 57 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 58 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 59 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 60 | }; | ||
| 61 | static constexpr s8 shift[512]{ | ||
| 62 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 63 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 64 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 65 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 66 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 67 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 68 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x16, | ||
| 69 | 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
| 70 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
| 71 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 72 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 73 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 74 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 75 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 76 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 77 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 78 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 79 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 80 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 81 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 82 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 83 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 84 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 85 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, | ||
| 86 | 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
| 87 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
| 88 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 89 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 90 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 91 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 92 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 93 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 94 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 95 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 96 | 0x18, 0x18, | ||
| 97 | }; | ||
| 98 | const u32 u = Common::BitCast<u32>(f); | ||
| 99 | const u32 i = u >> 23; | ||
| 100 | return base[i] + ((u & 0x7fffff) >> shift[i]); | ||
| 101 | } | ||
| 102 | |||
| 103 | u32 AU1_AH2_AF2(f32 a[2]) { | ||
| 104 | return AU1_AH1_AF1(a[0]) + (AU1_AH1_AF1(a[1]) << 16); | ||
| 105 | } | ||
| 106 | |||
| 107 | void FsrEasuCon(u32 con0[4], u32 con1[4], u32 con2[4], u32 con3[4], f32 inputViewportInPixelsX, | ||
| 108 | f32 inputViewportInPixelsY, f32 inputSizeInPixelsX, f32 inputSizeInPixelsY, | ||
| 109 | f32 outputSizeInPixelsX, f32 outputSizeInPixelsY) { | ||
| 110 | con0[0] = Common::BitCast<u32>(inputViewportInPixelsX / outputSizeInPixelsX); | ||
| 111 | con0[1] = Common::BitCast<u32>(inputViewportInPixelsY / outputSizeInPixelsY); | ||
| 112 | con0[2] = Common::BitCast<u32>(0.5f * inputViewportInPixelsX / outputSizeInPixelsX - 0.5f); | ||
| 113 | con0[3] = Common::BitCast<u32>(0.5f * inputViewportInPixelsY / outputSizeInPixelsY - 0.5f); | ||
| 114 | con1[0] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX); | ||
| 115 | con1[1] = Common::BitCast<u32>(1.0f / inputSizeInPixelsY); | ||
| 116 | con1[2] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX); | ||
| 117 | con1[3] = Common::BitCast<u32>(-1.0f / inputSizeInPixelsY); | ||
| 118 | con2[0] = Common::BitCast<u32>(-1.0f / inputSizeInPixelsX); | ||
| 119 | con2[1] = Common::BitCast<u32>(2.0f / inputSizeInPixelsY); | ||
| 120 | con2[2] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX); | ||
| 121 | con2[3] = Common::BitCast<u32>(2.0f / inputSizeInPixelsY); | ||
| 122 | con3[0] = Common::BitCast<u32>(0.0f / inputSizeInPixelsX); | ||
| 123 | con3[1] = Common::BitCast<u32>(4.0f / inputSizeInPixelsY); | ||
| 124 | con3[2] = con3[3] = 0; | ||
| 125 | } | ||
| 126 | } // Anonymous namespace | ||
| 127 | |||
| 128 | void FsrEasuConOffset(u32 con0[4], u32 con1[4], u32 con2[4], u32 con3[4], | ||
| 129 | f32 inputViewportInPixelsX, f32 inputViewportInPixelsY, | ||
| 130 | f32 inputSizeInPixelsX, f32 inputSizeInPixelsY, f32 outputSizeInPixelsX, | ||
| 131 | f32 outputSizeInPixelsY, f32 inputOffsetInPixelsX, f32 inputOffsetInPixelsY) { | ||
| 132 | FsrEasuCon(con0, con1, con2, con3, inputViewportInPixelsX, inputViewportInPixelsY, | ||
| 133 | inputSizeInPixelsX, inputSizeInPixelsY, outputSizeInPixelsX, outputSizeInPixelsY); | ||
| 134 | con0[2] = Common::BitCast<u32>(0.5f * inputViewportInPixelsX / outputSizeInPixelsX - 0.5f + | ||
| 135 | inputOffsetInPixelsX); | ||
| 136 | con0[3] = Common::BitCast<u32>(0.5f * inputViewportInPixelsY / outputSizeInPixelsY - 0.5f + | ||
| 137 | inputOffsetInPixelsY); | ||
| 138 | } | ||
| 139 | |||
| 140 | void FsrRcasCon(u32* con, f32 sharpness) { | ||
| 141 | sharpness = std::exp2f(-sharpness); | ||
| 142 | f32 hSharp[2]{sharpness, sharpness}; | ||
| 143 | con[0] = Common::BitCast<u32>(sharpness); | ||
| 144 | con[1] = AU1_AH2_AF2(hSharp); | ||
| 145 | con[2] = 0; | ||
| 146 | con[3] = 0; | ||
| 147 | } | ||
| 148 | } // namespace FSR | ||
diff --git a/src/video_core/fsr.h b/src/video_core/fsr.h new file mode 100644 index 000000000..db0d4ec6f --- /dev/null +++ b/src/video_core/fsr.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/bit_cast.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace FSR { | ||
| 10 | // Reimplementations of the constant generating functions in ffx_fsr1.h | ||
| 11 | // GCC generated a lot of warnings when using the official header. | ||
| 12 | void FsrEasuConOffset(u32 con0[4], u32 con1[4], u32 con2[4], u32 con3[4], | ||
| 13 | f32 inputViewportInPixelsX, f32 inputViewportInPixelsY, | ||
| 14 | f32 inputSizeInPixelsX, f32 inputSizeInPixelsY, f32 outputSizeInPixelsX, | ||
| 15 | f32 outputSizeInPixelsY, f32 inputOffsetInPixelsX, f32 inputOffsetInPixelsY); | ||
| 16 | |||
| 17 | void FsrRcasCon(u32* con, f32 sharpness); | ||
| 18 | |||
| 19 | } // namespace FSR | ||
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index e968ae220..dad7b07d4 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt | |||
| @@ -3,12 +3,16 @@ | |||
| 3 | 3 | ||
| 4 | set(FIDELITYFX_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/externals/FidelityFX-FSR/ffx-fsr) | 4 | set(FIDELITYFX_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/externals/FidelityFX-FSR/ffx-fsr) |
| 5 | 5 | ||
| 6 | set(GLSL_INCLUDES | 6 | set(FIDELITYFX_FILES |
| 7 | fidelityfx_fsr.comp | ||
| 8 | ${FIDELITYFX_INCLUDE_DIR}/ffx_a.h | 7 | ${FIDELITYFX_INCLUDE_DIR}/ffx_a.h |
| 9 | ${FIDELITYFX_INCLUDE_DIR}/ffx_fsr1.h | 8 | ${FIDELITYFX_INCLUDE_DIR}/ffx_fsr1.h |
| 10 | ) | 9 | ) |
| 11 | 10 | ||
| 11 | set(GLSL_INCLUDES | ||
| 12 | fidelityfx_fsr.comp | ||
| 13 | ${FIDELITYFX_FILES} | ||
| 14 | ) | ||
| 15 | |||
| 12 | set(SHADER_FILES | 16 | set(SHADER_FILES |
| 13 | astc_decoder.comp | 17 | astc_decoder.comp |
| 14 | blit_color_float.frag | 18 | blit_color_float.frag |
| @@ -24,6 +28,9 @@ set(SHADER_FILES | |||
| 24 | fxaa.vert | 28 | fxaa.vert |
| 25 | opengl_convert_s8d24.comp | 29 | opengl_convert_s8d24.comp |
| 26 | opengl_copy_bc4.comp | 30 | opengl_copy_bc4.comp |
| 31 | opengl_fidelityfx_fsr.frag | ||
| 32 | opengl_fidelityfx_fsr_easu.frag | ||
| 33 | opengl_fidelityfx_fsr_rcas.frag | ||
| 27 | opengl_present.frag | 34 | opengl_present.frag |
| 28 | opengl_present.vert | 35 | opengl_present.vert |
| 29 | opengl_present_scaleforce.frag | 36 | opengl_present_scaleforce.frag |
| @@ -118,6 +125,25 @@ foreach(FILENAME IN ITEMS ${SHADER_FILES}) | |||
| 118 | endif() | 125 | endif() |
| 119 | endforeach() | 126 | endforeach() |
| 120 | 127 | ||
| 128 | foreach(FILEPATH IN ITEMS ${FIDELITYFX_FILES}) | ||
| 129 | get_filename_component(FILENAME ${FILEPATH} NAME) | ||
| 130 | string(REPLACE "." "_" HEADER_NAME ${FILENAME}) | ||
| 131 | set(SOURCE_FILE ${FILEPATH}) | ||
| 132 | set(SOURCE_HEADER_FILE ${SHADER_DIR}/${HEADER_NAME}.h) | ||
| 133 | add_custom_command( | ||
| 134 | OUTPUT | ||
| 135 | ${SOURCE_HEADER_FILE} | ||
| 136 | COMMAND | ||
| 137 | ${CMAKE_COMMAND} -P ${HEADER_GENERATOR} ${SOURCE_FILE} ${SOURCE_HEADER_FILE} ${INPUT_FILE} | ||
| 138 | MAIN_DEPENDENCY | ||
| 139 | ${SOURCE_FILE} | ||
| 140 | DEPENDS | ||
| 141 | ${INPUT_FILE} | ||
| 142 | # HEADER_GENERATOR should be included here but msbuild seems to assume it's always modified | ||
| 143 | ) | ||
| 144 | set(SHADER_HEADERS ${SHADER_HEADERS} ${SOURCE_HEADER_FILE}) | ||
| 145 | endforeach() | ||
| 146 | |||
| 121 | set(SHADER_SOURCES ${SHADER_FILES}) | 147 | set(SHADER_SOURCES ${SHADER_FILES}) |
| 122 | list(APPEND SHADER_SOURCES ${GLSL_INCLUDES}) | 148 | list(APPEND SHADER_SOURCES ${GLSL_INCLUDES}) |
| 123 | 149 | ||
diff --git a/src/video_core/host_shaders/opengl_fidelityfx_fsr.frag b/src/video_core/host_shaders/opengl_fidelityfx_fsr.frag new file mode 100644 index 000000000..16d22f58e --- /dev/null +++ b/src/video_core/host_shaders/opengl_fidelityfx_fsr.frag | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | //!#version 460 core | ||
| 5 | #extension GL_ARB_separate_shader_objects : enable | ||
| 6 | #extension GL_ARB_shading_language_420pack : enable | ||
| 7 | |||
| 8 | #extension GL_AMD_gpu_shader_half_float : enable | ||
| 9 | #extension GL_NV_gpu_shader5 : enable | ||
| 10 | |||
| 11 | // FidelityFX Super Resolution Sample | ||
| 12 | // | ||
| 13 | // Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. | ||
| 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 15 | // of this software and associated documentation files(the "Software"), to deal | ||
| 16 | // in the Software without restriction, including without limitation the rights | ||
| 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell | ||
| 18 | // copies of the Software, and to permit persons to whom the Software is | ||
| 19 | // furnished to do so, subject to the following conditions : | ||
| 20 | // The above copyright notice and this permission notice shall be included in | ||
| 21 | // all copies or substantial portions of the Software. | ||
| 22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 23 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 24 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE | ||
| 25 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 26 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 27 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 28 | // THE SOFTWARE. | ||
| 29 | |||
| 30 | layout (location = 0) uniform uvec4 constants[4]; | ||
| 31 | |||
| 32 | #define A_GPU 1 | ||
| 33 | #define A_GLSL 1 | ||
| 34 | |||
| 35 | #ifdef YUZU_USE_FP16 | ||
| 36 | #define A_HALF | ||
| 37 | #endif | ||
| 38 | #include "ffx_a.h" | ||
| 39 | |||
| 40 | #ifndef YUZU_USE_FP16 | ||
| 41 | layout (binding=0) uniform sampler2D InputTexture; | ||
| 42 | #if USE_EASU | ||
| 43 | #define FSR_EASU_F 1 | ||
| 44 | AF4 FsrEasuRF(AF2 p) { AF4 res = textureGather(InputTexture, p, 0); return res; } | ||
| 45 | AF4 FsrEasuGF(AF2 p) { AF4 res = textureGather(InputTexture, p, 1); return res; } | ||
| 46 | AF4 FsrEasuBF(AF2 p) { AF4 res = textureGather(InputTexture, p, 2); return res; } | ||
| 47 | #endif | ||
| 48 | #if USE_RCAS | ||
| 49 | #define FSR_RCAS_F | ||
| 50 | AF4 FsrRcasLoadF(ASU2 p) { return texelFetch(InputTexture, ASU2(p), 0); } | ||
| 51 | void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {} | ||
| 52 | #endif | ||
| 53 | #else | ||
| 54 | layout (binding=0) uniform sampler2D InputTexture; | ||
| 55 | #if USE_EASU | ||
| 56 | #define FSR_EASU_H 1 | ||
| 57 | AH4 FsrEasuRH(AF2 p) { AH4 res = AH4(textureGather(InputTexture, p, 0)); return res; } | ||
| 58 | AH4 FsrEasuGH(AF2 p) { AH4 res = AH4(textureGather(InputTexture, p, 1)); return res; } | ||
| 59 | AH4 FsrEasuBH(AF2 p) { AH4 res = AH4(textureGather(InputTexture, p, 2)); return res; } | ||
| 60 | #endif | ||
| 61 | #if USE_RCAS | ||
| 62 | #define FSR_RCAS_H | ||
| 63 | AH4 FsrRcasLoadH(ASW2 p) { return AH4(texelFetch(InputTexture, ASU2(p), 0)); } | ||
| 64 | void FsrRcasInputH(inout AH1 r,inout AH1 g,inout AH1 b){} | ||
| 65 | #endif | ||
| 66 | #endif | ||
| 67 | |||
| 68 | #include "ffx_fsr1.h" | ||
| 69 | |||
| 70 | #if USE_RCAS | ||
| 71 | layout(location = 0) in vec2 frag_texcoord; | ||
| 72 | #endif | ||
| 73 | layout (location = 0) out vec4 frag_color; | ||
| 74 | |||
| 75 | void CurrFilter(AU2 pos) | ||
| 76 | { | ||
| 77 | #if USE_EASU | ||
| 78 | #ifndef YUZU_USE_FP16 | ||
| 79 | AF3 c; | ||
| 80 | FsrEasuF(c, pos, constants[0], constants[1], constants[2], constants[3]); | ||
| 81 | frag_color = AF4(c, 1.0); | ||
| 82 | #else | ||
| 83 | AH3 c; | ||
| 84 | FsrEasuH(c, pos, constants[0], constants[1], constants[2], constants[3]); | ||
| 85 | frag_color = AH4(c, 1.0); | ||
| 86 | #endif | ||
| 87 | #endif | ||
| 88 | #if USE_RCAS | ||
| 89 | #ifndef YUZU_USE_FP16 | ||
| 90 | AF3 c; | ||
| 91 | FsrRcasF(c.r, c.g, c.b, pos, constants[0]); | ||
| 92 | frag_color = AF4(c, 1.0); | ||
| 93 | #else | ||
| 94 | AH3 c; | ||
| 95 | FsrRcasH(c.r, c.g, c.b, pos, constants[0]); | ||
| 96 | frag_color = AH4(c, 1.0); | ||
| 97 | #endif | ||
| 98 | #endif | ||
| 99 | } | ||
| 100 | |||
| 101 | void main() | ||
| 102 | { | ||
| 103 | #if USE_RCAS | ||
| 104 | CurrFilter(AU2(frag_texcoord * vec2(textureSize(InputTexture, 0)))); | ||
| 105 | #else | ||
| 106 | CurrFilter(AU2(gl_FragCoord.xy)); | ||
| 107 | #endif | ||
| 108 | } | ||
diff --git a/src/video_core/host_shaders/opengl_fidelityfx_fsr_easu.frag b/src/video_core/host_shaders/opengl_fidelityfx_fsr_easu.frag new file mode 100644 index 000000000..d39f80ac1 --- /dev/null +++ b/src/video_core/host_shaders/opengl_fidelityfx_fsr_easu.frag | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #version 460 core | ||
| 5 | #extension GL_GOOGLE_include_directive : enable | ||
| 6 | |||
| 7 | #define USE_EASU 1 | ||
| 8 | |||
| 9 | #include "opengl_fidelityfx_fsr.frag" | ||
diff --git a/src/video_core/host_shaders/opengl_fidelityfx_fsr_rcas.frag b/src/video_core/host_shaders/opengl_fidelityfx_fsr_rcas.frag new file mode 100644 index 000000000..cfa78ddc7 --- /dev/null +++ b/src/video_core/host_shaders/opengl_fidelityfx_fsr_rcas.frag | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #version 460 core | ||
| 5 | #extension GL_GOOGLE_include_directive : enable | ||
| 6 | |||
| 7 | #define USE_RCAS 1 | ||
| 8 | |||
| 9 | #include "opengl_fidelityfx_fsr.frag" | ||
diff --git a/src/video_core/renderer_opengl/gl_fsr.cpp b/src/video_core/renderer_opengl/gl_fsr.cpp new file mode 100644 index 000000000..77262dcf1 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_fsr.cpp | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/settings.h" | ||
| 5 | #include "video_core/fsr.h" | ||
| 6 | #include "video_core/renderer_opengl/gl_fsr.h" | ||
| 7 | #include "video_core/renderer_opengl/gl_shader_manager.h" | ||
| 8 | #include "video_core/renderer_opengl/gl_shader_util.h" | ||
| 9 | |||
| 10 | namespace OpenGL { | ||
| 11 | using namespace FSR; | ||
| 12 | |||
| 13 | using FsrConstants = std::array<u32, 4 * 4>; | ||
| 14 | |||
| 15 | FSR::FSR(std::string_view fsr_vertex_source, std::string_view fsr_easu_source, | ||
| 16 | std::string_view fsr_rcas_source) | ||
| 17 | : fsr_vertex{CreateProgram(fsr_vertex_source, GL_VERTEX_SHADER)}, | ||
| 18 | fsr_easu_frag{CreateProgram(fsr_easu_source, GL_FRAGMENT_SHADER)}, | ||
| 19 | fsr_rcas_frag{CreateProgram(fsr_rcas_source, GL_FRAGMENT_SHADER)} { | ||
| 20 | glProgramUniform2f(fsr_vertex.handle, 0, 1.0f, 1.0f); | ||
| 21 | glProgramUniform2f(fsr_vertex.handle, 1, 0.0f, 0.0f); | ||
| 22 | } | ||
| 23 | |||
| 24 | FSR::~FSR() = default; | ||
| 25 | |||
| 26 | void FSR::Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& screen, | ||
| 27 | u32 input_image_width, u32 input_image_height, | ||
| 28 | const Common::Rectangle<int>& crop_rect) { | ||
| 29 | |||
| 30 | const auto output_image_width = screen.GetWidth(); | ||
| 31 | const auto output_image_height = screen.GetHeight(); | ||
| 32 | |||
| 33 | if (fsr_intermediate_tex.handle) { | ||
| 34 | GLint fsr_tex_width, fsr_tex_height; | ||
| 35 | glGetTextureLevelParameteriv(fsr_intermediate_tex.handle, 0, GL_TEXTURE_WIDTH, | ||
| 36 | &fsr_tex_width); | ||
| 37 | glGetTextureLevelParameteriv(fsr_intermediate_tex.handle, 0, GL_TEXTURE_HEIGHT, | ||
| 38 | &fsr_tex_height); | ||
| 39 | if (static_cast<u32>(fsr_tex_width) != output_image_width || | ||
| 40 | static_cast<u32>(fsr_tex_height) != output_image_height) { | ||
| 41 | fsr_intermediate_tex.Release(); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | if (!fsr_intermediate_tex.handle) { | ||
| 45 | fsr_intermediate_tex.Create(GL_TEXTURE_2D); | ||
| 46 | glTextureStorage2D(fsr_intermediate_tex.handle, 1, GL_RGB16F, output_image_width, | ||
| 47 | output_image_height); | ||
| 48 | glNamedFramebufferTexture(fsr_framebuffer.handle, GL_COLOR_ATTACHMENT0, | ||
| 49 | fsr_intermediate_tex.handle, 0); | ||
| 50 | } | ||
| 51 | |||
| 52 | GLint old_draw_fb; | ||
| 53 | glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); | ||
| 54 | |||
| 55 | glFrontFace(GL_CW); | ||
| 56 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fsr_framebuffer.handle); | ||
| 57 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(output_image_width), | ||
| 58 | static_cast<GLfloat>(output_image_height)); | ||
| 59 | |||
| 60 | FsrConstants constants; | ||
| 61 | FsrEasuConOffset( | ||
| 62 | constants.data() + 0, constants.data() + 4, constants.data() + 8, constants.data() + 12, | ||
| 63 | |||
| 64 | static_cast<f32>(crop_rect.GetWidth()), static_cast<f32>(crop_rect.GetHeight()), | ||
| 65 | static_cast<f32>(input_image_width), static_cast<f32>(input_image_height), | ||
| 66 | static_cast<f32>(output_image_width), static_cast<f32>(output_image_height), | ||
| 67 | static_cast<f32>(crop_rect.left), static_cast<f32>(crop_rect.top)); | ||
| 68 | |||
| 69 | glProgramUniform4uiv(fsr_easu_frag.handle, 0, sizeof(constants), std::data(constants)); | ||
| 70 | |||
| 71 | program_manager.BindPresentPrograms(fsr_vertex.handle, fsr_easu_frag.handle); | ||
| 72 | glDrawArrays(GL_TRIANGLES, 0, 3); | ||
| 73 | |||
| 74 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); | ||
| 75 | glBindTextureUnit(0, fsr_intermediate_tex.handle); | ||
| 76 | |||
| 77 | const float sharpening = | ||
| 78 | static_cast<float>(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f; | ||
| 79 | |||
| 80 | FsrRcasCon(constants.data(), sharpening); | ||
| 81 | glProgramUniform4uiv(fsr_rcas_frag.handle, 0, sizeof(constants), std::data(constants)); | ||
| 82 | } | ||
| 83 | |||
| 84 | void FSR::InitBuffers() { | ||
| 85 | fsr_framebuffer.Create(); | ||
| 86 | } | ||
| 87 | |||
| 88 | void FSR::ReleaseBuffers() { | ||
| 89 | fsr_framebuffer.Release(); | ||
| 90 | fsr_intermediate_tex.Release(); | ||
| 91 | } | ||
| 92 | |||
| 93 | const OGLProgram& FSR::GetPresentFragmentProgram() const noexcept { | ||
| 94 | return fsr_rcas_frag; | ||
| 95 | } | ||
| 96 | |||
| 97 | bool FSR::AreBuffersInitialized() const noexcept { | ||
| 98 | return fsr_framebuffer.handle; | ||
| 99 | } | ||
| 100 | |||
| 101 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/gl_fsr.h b/src/video_core/renderer_opengl/gl_fsr.h new file mode 100644 index 000000000..1f6ae3115 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_fsr.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <string_view> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/math_util.h" | ||
| 10 | #include "video_core/fsr.h" | ||
| 11 | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||
| 12 | |||
| 13 | namespace OpenGL { | ||
| 14 | |||
| 15 | class ProgramManager; | ||
| 16 | |||
| 17 | class FSR { | ||
| 18 | public: | ||
| 19 | explicit FSR(std::string_view fsr_vertex_source, std::string_view fsr_easu_source, | ||
| 20 | std::string_view fsr_rcas_source); | ||
| 21 | ~FSR(); | ||
| 22 | |||
| 23 | void Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& screen, | ||
| 24 | u32 input_image_width, u32 input_image_height, | ||
| 25 | const Common::Rectangle<int>& crop_rect); | ||
| 26 | |||
| 27 | void InitBuffers(); | ||
| 28 | |||
| 29 | void ReleaseBuffers(); | ||
| 30 | |||
| 31 | [[nodiscard]] const OGLProgram& GetPresentFragmentProgram() const noexcept; | ||
| 32 | |||
| 33 | [[nodiscard]] bool AreBuffersInitialized() const noexcept; | ||
| 34 | |||
| 35 | private: | ||
| 36 | OGLFramebuffer fsr_framebuffer; | ||
| 37 | OGLProgram fsr_vertex; | ||
| 38 | OGLProgram fsr_easu_frag; | ||
| 39 | OGLProgram fsr_rcas_frag; | ||
| 40 | OGLTexture fsr_intermediate_tex; | ||
| 41 | }; | ||
| 42 | |||
| 43 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index de95f2634..2a74c1d05 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -17,8 +17,14 @@ | |||
| 17 | #include "core/frontend/emu_window.h" | 17 | #include "core/frontend/emu_window.h" |
| 18 | #include "core/memory.h" | 18 | #include "core/memory.h" |
| 19 | #include "core/telemetry_session.h" | 19 | #include "core/telemetry_session.h" |
| 20 | #include "video_core/host_shaders/ffx_a_h.h" | ||
| 21 | #include "video_core/host_shaders/ffx_fsr1_h.h" | ||
| 22 | #include "video_core/host_shaders/full_screen_triangle_vert.h" | ||
| 20 | #include "video_core/host_shaders/fxaa_frag.h" | 23 | #include "video_core/host_shaders/fxaa_frag.h" |
| 21 | #include "video_core/host_shaders/fxaa_vert.h" | 24 | #include "video_core/host_shaders/fxaa_vert.h" |
| 25 | #include "video_core/host_shaders/opengl_fidelityfx_fsr_easu_frag.h" | ||
| 26 | #include "video_core/host_shaders/opengl_fidelityfx_fsr_frag.h" | ||
| 27 | #include "video_core/host_shaders/opengl_fidelityfx_fsr_rcas_frag.h" | ||
| 22 | #include "video_core/host_shaders/opengl_present_frag.h" | 28 | #include "video_core/host_shaders/opengl_present_frag.h" |
| 23 | #include "video_core/host_shaders/opengl_present_scaleforce_frag.h" | 29 | #include "video_core/host_shaders/opengl_present_scaleforce_frag.h" |
| 24 | #include "video_core/host_shaders/opengl_present_vert.h" | 30 | #include "video_core/host_shaders/opengl_present_vert.h" |
| @@ -31,6 +37,7 @@ | |||
| 31 | #include "video_core/host_shaders/smaa_edge_detection_vert.h" | 37 | #include "video_core/host_shaders/smaa_edge_detection_vert.h" |
| 32 | #include "video_core/host_shaders/smaa_neighborhood_blending_frag.h" | 38 | #include "video_core/host_shaders/smaa_neighborhood_blending_frag.h" |
| 33 | #include "video_core/host_shaders/smaa_neighborhood_blending_vert.h" | 39 | #include "video_core/host_shaders/smaa_neighborhood_blending_vert.h" |
| 40 | #include "video_core/renderer_opengl/gl_fsr.h" | ||
| 34 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 41 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 35 | #include "video_core/renderer_opengl/gl_shader_manager.h" | 42 | #include "video_core/renderer_opengl/gl_shader_manager.h" |
| 36 | #include "video_core/renderer_opengl/gl_shader_util.h" | 43 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| @@ -268,12 +275,17 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 268 | fxaa_vertex = CreateProgram(HostShaders::FXAA_VERT, GL_VERTEX_SHADER); | 275 | fxaa_vertex = CreateProgram(HostShaders::FXAA_VERT, GL_VERTEX_SHADER); |
| 269 | fxaa_fragment = CreateProgram(HostShaders::FXAA_FRAG, GL_FRAGMENT_SHADER); | 276 | fxaa_fragment = CreateProgram(HostShaders::FXAA_FRAG, GL_FRAGMENT_SHADER); |
| 270 | 277 | ||
| 271 | const auto SmaaShader = [](std::string_view specialized_source, GLenum stage) { | 278 | const auto replace_include = [](std::string& shader_source, std::string_view include_name, |
| 272 | std::string shader_source{specialized_source}; | 279 | std::string_view include_content) { |
| 273 | constexpr std::string_view include_string = "#include \"opengl_smaa.glsl\""; | 280 | const std::string include_string = fmt::format("#include \"{}\"", include_name); |
| 274 | const std::size_t pos = shader_source.find(include_string); | 281 | const std::size_t pos = shader_source.find(include_string); |
| 275 | ASSERT(pos != std::string::npos); | 282 | ASSERT(pos != std::string::npos); |
| 276 | shader_source.replace(pos, include_string.size(), HostShaders::OPENGL_SMAA_GLSL); | 283 | shader_source.replace(pos, include_string.size(), include_content); |
| 284 | }; | ||
| 285 | |||
| 286 | const auto SmaaShader = [&](std::string_view specialized_source, GLenum stage) { | ||
| 287 | std::string shader_source{specialized_source}; | ||
| 288 | replace_include(shader_source, "opengl_smaa.glsl", HostShaders::OPENGL_SMAA_GLSL); | ||
| 277 | return CreateProgram(shader_source, stage); | 289 | return CreateProgram(shader_source, stage); |
| 278 | }; | 290 | }; |
| 279 | 291 | ||
| @@ -298,14 +310,32 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 298 | CreateProgram(fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG), | 310 | CreateProgram(fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG), |
| 299 | GL_FRAGMENT_SHADER); | 311 | GL_FRAGMENT_SHADER); |
| 300 | 312 | ||
| 313 | std::string fsr_source{HostShaders::OPENGL_FIDELITYFX_FSR_FRAG}; | ||
| 314 | replace_include(fsr_source, "ffx_a.h", HostShaders::FFX_A_H); | ||
| 315 | replace_include(fsr_source, "ffx_fsr1.h", HostShaders::FFX_FSR1_H); | ||
| 316 | |||
| 317 | std::string fsr_easu_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_EASU_FRAG}; | ||
| 318 | std::string fsr_rcas_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_RCAS_FRAG}; | ||
| 319 | replace_include(fsr_easu_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source); | ||
| 320 | replace_include(fsr_rcas_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source); | ||
| 321 | |||
| 322 | fsr = std::make_unique<FSR>(HostShaders::FULL_SCREEN_TRIANGLE_VERT, fsr_easu_frag_source, | ||
| 323 | fsr_rcas_frag_source); | ||
| 324 | |||
| 301 | // Generate presentation sampler | 325 | // Generate presentation sampler |
| 302 | present_sampler.Create(); | 326 | present_sampler.Create(); |
| 303 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 327 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 304 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 328 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 329 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
| 330 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
| 331 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); | ||
| 305 | 332 | ||
| 306 | present_sampler_nn.Create(); | 333 | present_sampler_nn.Create(); |
| 307 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 334 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 308 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 335 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 336 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
| 337 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
| 338 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); | ||
| 309 | 339 | ||
| 310 | // Generate VBO handle for drawing | 340 | // Generate VBO handle for drawing |
| 311 | vertex_buffer.Create(); | 341 | vertex_buffer.Create(); |
| @@ -525,6 +555,31 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 525 | 555 | ||
| 526 | glBindTextureUnit(0, aa_texture.handle); | 556 | glBindTextureUnit(0, aa_texture.handle); |
| 527 | } | 557 | } |
| 558 | glDisablei(GL_SCISSOR_TEST, 0); | ||
| 559 | |||
| 560 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 561 | if (!fsr->AreBuffersInitialized()) { | ||
| 562 | fsr->InitBuffers(); | ||
| 563 | } | ||
| 564 | |||
| 565 | auto crop_rect = framebuffer_crop_rect; | ||
| 566 | if (crop_rect.GetWidth() == 0) { | ||
| 567 | crop_rect.right = framebuffer_width; | ||
| 568 | } | ||
| 569 | if (crop_rect.GetHeight() == 0) { | ||
| 570 | crop_rect.bottom = framebuffer_height; | ||
| 571 | } | ||
| 572 | crop_rect = crop_rect.Scale(Settings::values.resolution_info.up_factor); | ||
| 573 | const auto fsr_input_width = Settings::values.resolution_info.ScaleUp(framebuffer_width); | ||
| 574 | const auto fsr_input_height = Settings::values.resolution_info.ScaleUp(framebuffer_height); | ||
| 575 | glBindSampler(0, present_sampler.handle); | ||
| 576 | fsr->Draw(program_manager, layout.screen, fsr_input_width, fsr_input_height, crop_rect); | ||
| 577 | } else { | ||
| 578 | if (fsr->AreBuffersInitialized()) { | ||
| 579 | fsr->ReleaseBuffers(); | ||
| 580 | } | ||
| 581 | } | ||
| 582 | |||
| 528 | const std::array ortho_matrix = | 583 | const std::array ortho_matrix = |
| 529 | MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); | 584 | MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); |
| 530 | 585 | ||
| @@ -540,10 +595,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 540 | case Settings::ScalingFilter::ScaleForce: | 595 | case Settings::ScalingFilter::ScaleForce: |
| 541 | return present_scaleforce_fragment.handle; | 596 | return present_scaleforce_fragment.handle; |
| 542 | case Settings::ScalingFilter::Fsr: | 597 | case Settings::ScalingFilter::Fsr: |
| 543 | LOG_WARNING( | 598 | return fsr->GetPresentFragmentProgram().handle; |
| 544 | Render_OpenGL, | ||
| 545 | "FidelityFX Super Resolution is not supported in OpenGL, changing to ScaleForce"); | ||
| 546 | return present_scaleforce_fragment.handle; | ||
| 547 | default: | 599 | default: |
| 548 | return present_bilinear_fragment.handle; | 600 | return present_bilinear_fragment.handle; |
| 549 | } | 601 | } |
| @@ -578,15 +630,18 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 578 | f32 scale_u = static_cast<f32>(framebuffer_width) / static_cast<f32>(screen_info.texture.width); | 630 | f32 scale_u = static_cast<f32>(framebuffer_width) / static_cast<f32>(screen_info.texture.width); |
| 579 | f32 scale_v = | 631 | f32 scale_v = |
| 580 | static_cast<f32>(framebuffer_height) / static_cast<f32>(screen_info.texture.height); | 632 | static_cast<f32>(framebuffer_height) / static_cast<f32>(screen_info.texture.height); |
| 581 | // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering | 633 | |
| 582 | // (e.g. handheld mode) on a 1920x1080 framebuffer. | 634 | if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::Fsr) { |
| 583 | if (framebuffer_crop_rect.GetWidth() > 0) { | 635 | // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering |
| 584 | scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) / | 636 | // (e.g. handheld mode) on a 1920x1080 framebuffer. |
| 585 | static_cast<f32>(screen_info.texture.width); | 637 | if (framebuffer_crop_rect.GetWidth() > 0) { |
| 586 | } | 638 | scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) / |
| 587 | if (framebuffer_crop_rect.GetHeight() > 0) { | 639 | static_cast<f32>(screen_info.texture.width); |
| 588 | scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) / | 640 | } |
| 589 | static_cast<f32>(screen_info.texture.height); | 641 | if (framebuffer_crop_rect.GetHeight() > 0) { |
| 642 | scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) / | ||
| 643 | static_cast<f32>(screen_info.texture.height); | ||
| 644 | } | ||
| 590 | } | 645 | } |
| 591 | if (Settings::values.anti_aliasing.GetValue() == Settings::AntiAliasing::Fxaa && | 646 | if (Settings::values.anti_aliasing.GetValue() == Settings::AntiAliasing::Fxaa && |
| 592 | !screen_info.was_accelerated) { | 647 | !screen_info.was_accelerated) { |
| @@ -612,7 +667,6 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 612 | } else { | 667 | } else { |
| 613 | glDisable(GL_FRAMEBUFFER_SRGB); | 668 | glDisable(GL_FRAMEBUFFER_SRGB); |
| 614 | } | 669 | } |
| 615 | glDisablei(GL_SCISSOR_TEST, 0); | ||
| 616 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), | 670 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), |
| 617 | static_cast<GLfloat>(layout.height)); | 671 | static_cast<GLfloat>(layout.height)); |
| 618 | 672 | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index cc97d7b26..f1d5fd954 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | #include "video_core/renderer_base.h" | 11 | #include "video_core/renderer_base.h" |
| 12 | #include "video_core/renderer_opengl/gl_device.h" | 12 | #include "video_core/renderer_opengl/gl_device.h" |
| 13 | #include "video_core/renderer_opengl/gl_fsr.h" | ||
| 13 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 14 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 14 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 15 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 15 | #include "video_core/renderer_opengl/gl_shader_manager.h" | 16 | #include "video_core/renderer_opengl/gl_shader_manager.h" |
| @@ -141,6 +142,8 @@ private: | |||
| 141 | OGLTexture smaa_edges_tex; | 142 | OGLTexture smaa_edges_tex; |
| 142 | OGLTexture smaa_blend_tex; | 143 | OGLTexture smaa_blend_tex; |
| 143 | 144 | ||
| 145 | std::unique_ptr<FSR> fsr; | ||
| 146 | |||
| 144 | /// OpenGL framebuffer data | 147 | /// OpenGL framebuffer data |
| 145 | std::vector<u8> gl_framebuffer_data; | 148 | std::vector<u8> gl_framebuffer_data; |
| 146 | 149 | ||
diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp index 33daa8c1c..df972cd54 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.cpp +++ b/src/video_core/renderer_vulkan/vk_fsr.cpp | |||
| @@ -1,12 +1,11 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <cmath> | ||
| 5 | #include "common/bit_cast.h" | ||
| 6 | #include "common/common_types.h" | 4 | #include "common/common_types.h" |
| 7 | #include "common/div_ceil.h" | 5 | #include "common/div_ceil.h" |
| 8 | #include "common/settings.h" | 6 | #include "common/settings.h" |
| 9 | 7 | ||
| 8 | #include "video_core/fsr.h" | ||
| 10 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp16_comp_spv.h" | 9 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp16_comp_spv.h" |
| 11 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32_comp_spv.h" | 10 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32_comp_spv.h" |
| 12 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16_comp_spv.h" | 11 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16_comp_spv.h" |
| @@ -17,146 +16,7 @@ | |||
| 17 | #include "video_core/vulkan_common/vulkan_device.h" | 16 | #include "video_core/vulkan_common/vulkan_device.h" |
| 18 | 17 | ||
| 19 | namespace Vulkan { | 18 | namespace Vulkan { |
| 20 | namespace { | 19 | using namespace FSR; |
| 21 | // Reimplementations of the constant generating functions in ffx_fsr1.h | ||
| 22 | // GCC generated a lot of warnings when using the official header. | ||
| 23 | u32 AU1_AH1_AF1(f32 f) { | ||
| 24 | static constexpr u32 base[512]{ | ||
| 25 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 26 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 27 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 28 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 29 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 30 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 31 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 32 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 33 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 34 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, | ||
| 35 | 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, 0x2000, | ||
| 36 | 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x4400, 0x4800, 0x4c00, | ||
| 37 | 0x5000, 0x5400, 0x5800, 0x5c00, 0x6000, 0x6400, 0x6800, 0x6c00, 0x7000, 0x7400, 0x7800, | ||
| 38 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 39 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 40 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 41 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 42 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 43 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 44 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 45 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 46 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 47 | 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, | ||
| 48 | 0x7bff, 0x7bff, 0x7bff, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 49 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 50 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 51 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 52 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 53 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 54 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 55 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 56 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, | ||
| 57 | 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001, 0x8002, 0x8004, 0x8008, | ||
| 58 | 0x8010, 0x8020, 0x8040, 0x8080, 0x8100, 0x8200, 0x8400, 0x8800, 0x8c00, 0x9000, 0x9400, | ||
| 59 | 0x9800, 0x9c00, 0xa000, 0xa400, 0xa800, 0xac00, 0xb000, 0xb400, 0xb800, 0xbc00, 0xc000, | ||
| 60 | 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, 0xd800, 0xdc00, 0xe000, 0xe400, 0xe800, 0xec00, | ||
| 61 | 0xf000, 0xf400, 0xf800, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 62 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 63 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 64 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 65 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 66 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 67 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 68 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 69 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 70 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 71 | 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, | ||
| 72 | }; | ||
| 73 | static constexpr s8 shift[512]{ | ||
| 74 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 75 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 76 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 77 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 78 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 79 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 80 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x16, | ||
| 81 | 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
| 82 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
| 83 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 84 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 85 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 86 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 87 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 88 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 89 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 90 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 91 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 92 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 93 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 94 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 95 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 96 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 97 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, | ||
| 98 | 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
| 99 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
| 100 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 101 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 102 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 103 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 104 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 105 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 106 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 107 | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, | ||
| 108 | 0x18, 0x18, | ||
| 109 | }; | ||
| 110 | const u32 u = Common::BitCast<u32>(f); | ||
| 111 | const u32 i = u >> 23; | ||
| 112 | return base[i] + ((u & 0x7fffff) >> shift[i]); | ||
| 113 | } | ||
| 114 | |||
| 115 | u32 AU1_AH2_AF2(f32 a[2]) { | ||
| 116 | return AU1_AH1_AF1(a[0]) + (AU1_AH1_AF1(a[1]) << 16); | ||
| 117 | } | ||
| 118 | |||
| 119 | void FsrEasuCon(u32 con0[4], u32 con1[4], u32 con2[4], u32 con3[4], f32 inputViewportInPixelsX, | ||
| 120 | f32 inputViewportInPixelsY, f32 inputSizeInPixelsX, f32 inputSizeInPixelsY, | ||
| 121 | f32 outputSizeInPixelsX, f32 outputSizeInPixelsY) { | ||
| 122 | con0[0] = Common::BitCast<u32>(inputViewportInPixelsX / outputSizeInPixelsX); | ||
| 123 | con0[1] = Common::BitCast<u32>(inputViewportInPixelsY / outputSizeInPixelsY); | ||
| 124 | con0[2] = Common::BitCast<u32>(0.5f * inputViewportInPixelsX / outputSizeInPixelsX - 0.5f); | ||
| 125 | con0[3] = Common::BitCast<u32>(0.5f * inputViewportInPixelsY / outputSizeInPixelsY - 0.5f); | ||
| 126 | con1[0] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX); | ||
| 127 | con1[1] = Common::BitCast<u32>(1.0f / inputSizeInPixelsY); | ||
| 128 | con1[2] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX); | ||
| 129 | con1[3] = Common::BitCast<u32>(-1.0f / inputSizeInPixelsY); | ||
| 130 | con2[0] = Common::BitCast<u32>(-1.0f / inputSizeInPixelsX); | ||
| 131 | con2[1] = Common::BitCast<u32>(2.0f / inputSizeInPixelsY); | ||
| 132 | con2[2] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX); | ||
| 133 | con2[3] = Common::BitCast<u32>(2.0f / inputSizeInPixelsY); | ||
| 134 | con3[0] = Common::BitCast<u32>(0.0f / inputSizeInPixelsX); | ||
| 135 | con3[1] = Common::BitCast<u32>(4.0f / inputSizeInPixelsY); | ||
| 136 | con3[2] = con3[3] = 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | void FsrEasuConOffset(u32 con0[4], u32 con1[4], u32 con2[4], u32 con3[4], | ||
| 140 | f32 inputViewportInPixelsX, f32 inputViewportInPixelsY, | ||
| 141 | f32 inputSizeInPixelsX, f32 inputSizeInPixelsY, f32 outputSizeInPixelsX, | ||
| 142 | f32 outputSizeInPixelsY, f32 inputOffsetInPixelsX, f32 inputOffsetInPixelsY) { | ||
| 143 | FsrEasuCon(con0, con1, con2, con3, inputViewportInPixelsX, inputViewportInPixelsY, | ||
| 144 | inputSizeInPixelsX, inputSizeInPixelsY, outputSizeInPixelsX, outputSizeInPixelsY); | ||
| 145 | con0[2] = Common::BitCast<u32>(0.5f * inputViewportInPixelsX / outputSizeInPixelsX - 0.5f + | ||
| 146 | inputOffsetInPixelsX); | ||
| 147 | con0[3] = Common::BitCast<u32>(0.5f * inputViewportInPixelsY / outputSizeInPixelsY - 0.5f + | ||
| 148 | inputOffsetInPixelsY); | ||
| 149 | } | ||
| 150 | |||
| 151 | void FsrRcasCon(u32* con, f32 sharpness) { | ||
| 152 | sharpness = std::exp2f(-sharpness); | ||
| 153 | f32 hSharp[2]{sharpness, sharpness}; | ||
| 154 | con[0] = Common::BitCast<u32>(sharpness); | ||
| 155 | con[1] = AU1_AH2_AF2(hSharp); | ||
| 156 | con[2] = 0; | ||
| 157 | con[3] = 0; | ||
| 158 | } | ||
| 159 | } // Anonymous namespace | ||
| 160 | 20 | ||
| 161 | FSR::FSR(const Device& device_, MemoryAllocator& memory_allocator_, size_t image_count_, | 21 | FSR::FSR(const Device& device_, MemoryAllocator& memory_allocator_, size_t image_count_, |
| 162 | VkExtent2D output_size_) | 22 | VkExtent2D output_size_) |
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index bb9910a53..a45ec69ec 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui | |||
| @@ -460,7 +460,7 @@ | |||
| 460 | </item> | 460 | </item> |
| 461 | <item> | 461 | <item> |
| 462 | <property name="text"> | 462 | <property name="text"> |
| 463 | <string>AMD FidelityFX™️ Super Resolution (Vulkan Only)</string> | 463 | <string>AMD FidelityFX™️ Super Resolution</string> |
| 464 | </property> | 464 | </property> |
| 465 | </item> | 465 | </item> |
| 466 | </widget> | 466 | </widget> |
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp index 9bb69cab1..41ef4250a 100644 --- a/src/yuzu/configuration/input_profiles.cpp +++ b/src/yuzu/configuration/input_profiles.cpp | |||
| @@ -58,13 +58,16 @@ std::vector<std::string> InputProfiles::GetInputProfileNames() { | |||
| 58 | std::vector<std::string> profile_names; | 58 | std::vector<std::string> profile_names; |
| 59 | profile_names.reserve(map_profiles.size()); | 59 | profile_names.reserve(map_profiles.size()); |
| 60 | 60 | ||
| 61 | for (const auto& [profile_name, config] : map_profiles) { | 61 | auto it = map_profiles.cbegin(); |
| 62 | while (it != map_profiles.cend()) { | ||
| 63 | const auto& [profile_name, config] = *it; | ||
| 62 | if (!ProfileExistsInFilesystem(profile_name)) { | 64 | if (!ProfileExistsInFilesystem(profile_name)) { |
| 63 | DeleteProfile(profile_name); | 65 | it = map_profiles.erase(it); |
| 64 | continue; | 66 | continue; |
| 65 | } | 67 | } |
| 66 | 68 | ||
| 67 | profile_names.push_back(profile_name); | 69 | profile_names.push_back(profile_name); |
| 70 | ++it; | ||
| 68 | } | 71 | } |
| 69 | 72 | ||
| 70 | std::stable_sort(profile_names.begin(), profile_names.end()); | 73 | std::stable_sort(profile_names.begin(), profile_names.end()); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 62aaf41bf..42b7b64c8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -983,11 +983,6 @@ void GMainWindow::InitializeWidgets() { | |||
| 983 | filter_status_button->setFocusPolicy(Qt::NoFocus); | 983 | filter_status_button->setFocusPolicy(Qt::NoFocus); |
| 984 | connect(filter_status_button, &QPushButton::clicked, this, | 984 | connect(filter_status_button, &QPushButton::clicked, this, |
| 985 | &GMainWindow::OnToggleAdaptingFilter); | 985 | &GMainWindow::OnToggleAdaptingFilter); |
| 986 | auto filter = Settings::values.scaling_filter.GetValue(); | ||
| 987 | if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL && | ||
| 988 | filter == Settings::ScalingFilter::Fsr) { | ||
| 989 | Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::NearestNeighbor); | ||
| 990 | } | ||
| 991 | UpdateFilterText(); | 986 | UpdateFilterText(); |
| 992 | filter_status_button->setCheckable(true); | 987 | filter_status_button->setCheckable(true); |
| 993 | filter_status_button->setChecked(true); | 988 | filter_status_button->setChecked(true); |
| @@ -3468,10 +3463,6 @@ void GMainWindow::OnToggleAdaptingFilter() { | |||
| 3468 | } else { | 3463 | } else { |
| 3469 | filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1); | 3464 | filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1); |
| 3470 | } | 3465 | } |
| 3471 | if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL && | ||
| 3472 | filter == Settings::ScalingFilter::Fsr) { | ||
| 3473 | filter = Settings::ScalingFilter::NearestNeighbor; | ||
| 3474 | } | ||
| 3475 | Settings::values.scaling_filter.SetValue(filter); | 3466 | Settings::values.scaling_filter.SetValue(filter); |
| 3476 | filter_status_button->setChecked(true); | 3467 | filter_status_button->setChecked(true); |
| 3477 | UpdateFilterText(); | 3468 | UpdateFilterText(); |
diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp index cbd52da85..d71cc23a7 100644 --- a/src/yuzu/multiplayer/direct_connect.cpp +++ b/src/yuzu/multiplayer/direct_connect.cpp | |||
| @@ -81,20 +81,13 @@ void DirectConnectWindow::Connect() { | |||
| 81 | } | 81 | } |
| 82 | } | 82 | } |
| 83 | } | 83 | } |
| 84 | switch (static_cast<ConnectionType>(ui->connection_type->currentIndex())) { | 84 | if (!ui->ip->hasAcceptableInput()) { |
| 85 | case ConnectionType::TraversalServer: | 85 | NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::IP_ADDRESS_NOT_VALID); |
| 86 | break; | 86 | return; |
| 87 | case ConnectionType::IP: | 87 | } |
| 88 | if (!ui->ip->hasAcceptableInput()) { | 88 | if (!ui->port->hasAcceptableInput()) { |
| 89 | NetworkMessage::ErrorManager::ShowError( | 89 | NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::PORT_NOT_VALID); |
| 90 | NetworkMessage::ErrorManager::IP_ADDRESS_NOT_VALID); | 90 | return; |
| 91 | return; | ||
| 92 | } | ||
| 93 | if (!ui->port->hasAcceptableInput()) { | ||
| 94 | NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::PORT_NOT_VALID); | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | break; | ||
| 98 | } | 91 | } |
| 99 | 92 | ||
| 100 | // Store settings | 93 | // Store settings |
diff --git a/src/yuzu/multiplayer/direct_connect.ui b/src/yuzu/multiplayer/direct_connect.ui index 57d6ec25a..0dd4e6829 100644 --- a/src/yuzu/multiplayer/direct_connect.ui +++ b/src/yuzu/multiplayer/direct_connect.ui | |||
| @@ -27,19 +27,10 @@ | |||
| 27 | <number>0</number> | 27 | <number>0</number> |
| 28 | </property> | 28 | </property> |
| 29 | <item> | 29 | <item> |
| 30 | <widget class="QComboBox" name="connection_type"> | ||
| 31 | <item> | ||
| 32 | <property name="text"> | ||
| 33 | <string>IP Address</string> | ||
| 34 | </property> | ||
| 35 | </item> | ||
| 36 | </widget> | ||
| 37 | </item> | ||
| 38 | <item> | ||
| 39 | <widget class="QWidget" name="ip_container" native="true"> | 30 | <widget class="QWidget" name="ip_container" native="true"> |
| 40 | <layout class="QHBoxLayout" name="ip_layout"> | 31 | <layout class="QHBoxLayout" name="ip_layout"> |
| 41 | <property name="leftMargin"> | 32 | <property name="leftMargin"> |
| 42 | <number>5</number> | 33 | <number>0</number> |
| 43 | </property> | 34 | </property> |
| 44 | <property name="topMargin"> | 35 | <property name="topMargin"> |
| 45 | <number>0</number> | 36 | <number>0</number> |
| @@ -53,17 +44,17 @@ | |||
| 53 | <item> | 44 | <item> |
| 54 | <widget class="QLabel" name="label_2"> | 45 | <widget class="QLabel" name="label_2"> |
| 55 | <property name="text"> | 46 | <property name="text"> |
| 56 | <string>IP</string> | 47 | <string>Server Address</string> |
| 57 | </property> | 48 | </property> |
| 58 | </widget> | 49 | </widget> |
| 59 | </item> | 50 | </item> |
| 60 | <item> | 51 | <item> |
| 61 | <widget class="QLineEdit" name="ip"> | 52 | <widget class="QLineEdit" name="ip"> |
| 62 | <property name="toolTip"> | 53 | <property name="toolTip"> |
| 63 | <string><html><head/><body><p>IPv4 address of the host</p></body></html></string> | 54 | <string><html><head/><body><p>Server address of the host</p></body></html></string> |
| 64 | </property> | 55 | </property> |
| 65 | <property name="maxLength"> | 56 | <property name="maxLength"> |
| 66 | <number>16</number> | 57 | <number>253</number> |
| 67 | </property> | 58 | </property> |
| 68 | </widget> | 59 | </widget> |
| 69 | </item> | 60 | </item> |
| @@ -85,6 +76,12 @@ | |||
| 85 | <property name="placeholderText"> | 76 | <property name="placeholderText"> |
| 86 | <string notr="true" extracomment="placeholder string that tells user default port">24872</string> | 77 | <string notr="true" extracomment="placeholder string that tells user default port">24872</string> |
| 87 | </property> | 78 | </property> |
| 79 | <property name="maximumSize"> | ||
| 80 | <size> | ||
| 81 | <width>65</width> | ||
| 82 | <height>50</height> | ||
| 83 | </size> | ||
| 84 | </property> | ||
| 88 | </widget> | 85 | </widget> |
| 89 | </item> | 86 | </item> |
| 90 | </layout> | 87 | </layout> |
diff --git a/src/yuzu/multiplayer/validation.h b/src/yuzu/multiplayer/validation.h index dd25af280..cbbe6757b 100644 --- a/src/yuzu/multiplayer/validation.h +++ b/src/yuzu/multiplayer/validation.h | |||
| @@ -38,11 +38,28 @@ private: | |||
| 38 | QRegularExpression(QStringLiteral("^[a-zA-Z0-9._ -]{4,20}")); | 38 | QRegularExpression(QStringLiteral("^[a-zA-Z0-9._ -]{4,20}")); |
| 39 | QRegularExpressionValidator nickname; | 39 | QRegularExpressionValidator nickname; |
| 40 | 40 | ||
| 41 | /// ipv4 address only | 41 | /// ipv4 / ipv6 / hostnames |
| 42 | // TODO remove this when we support hostnames in direct connect | ||
| 43 | QRegularExpression ip_regex = QRegularExpression(QStringLiteral( | 42 | QRegularExpression ip_regex = QRegularExpression(QStringLiteral( |
| 44 | "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|" | 43 | // IPv4 regex |
| 45 | "2[0-4][0-9]|25[0-5])")); | 44 | "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|" |
| 45 | // IPv6 regex | ||
| 46 | "^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|" | ||
| 47 | "(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-" | ||
| 48 | "5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|" | ||
| 49 | "(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)" | ||
| 50 | "(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|" | ||
| 51 | "(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]" | ||
| 52 | "\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|" | ||
| 53 | "(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[" | ||
| 54 | "0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|" | ||
| 55 | "(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[" | ||
| 56 | "0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|" | ||
| 57 | "(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[" | ||
| 58 | "0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|" | ||
| 59 | "(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?" | ||
| 60 | "\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?$|" | ||
| 61 | // Hostname regex | ||
| 62 | "^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\\.)+[a-zA-Z]{2,}$")); | ||
| 46 | QRegularExpressionValidator ip; | 63 | QRegularExpressionValidator ip; |
| 47 | 64 | ||
| 48 | /// port must be between 0 and 65535 | 65 | /// port must be between 0 and 65535 |