diff options
42 files changed, 668 insertions, 290 deletions
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index b209f52fc..3e3029cd1 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/fiber.h" | 6 | #include "common/fiber.h" |
| 7 | #include "common/spin_lock.h" | ||
| 8 | |||
| 7 | #if defined(_WIN32) || defined(WIN32) | 9 | #if defined(_WIN32) || defined(WIN32) |
| 8 | #include <windows.h> | 10 | #include <windows.h> |
| 9 | #else | 11 | #else |
| @@ -14,18 +16,45 @@ namespace Common { | |||
| 14 | 16 | ||
| 15 | constexpr std::size_t default_stack_size = 256 * 1024; // 256kb | 17 | constexpr std::size_t default_stack_size = 256 * 1024; // 256kb |
| 16 | 18 | ||
| 17 | #if defined(_WIN32) || defined(WIN32) | ||
| 18 | |||
| 19 | struct Fiber::FiberImpl { | 19 | struct Fiber::FiberImpl { |
| 20 | SpinLock guard{}; | ||
| 21 | std::function<void(void*)> entry_point; | ||
| 22 | std::function<void(void*)> rewind_point; | ||
| 23 | void* rewind_parameter{}; | ||
| 24 | void* start_parameter{}; | ||
| 25 | std::shared_ptr<Fiber> previous_fiber; | ||
| 26 | bool is_thread_fiber{}; | ||
| 27 | bool released{}; | ||
| 28 | |||
| 29 | #if defined(_WIN32) || defined(WIN32) | ||
| 20 | LPVOID handle = nullptr; | 30 | LPVOID handle = nullptr; |
| 21 | LPVOID rewind_handle = nullptr; | 31 | LPVOID rewind_handle = nullptr; |
| 32 | #else | ||
| 33 | alignas(64) std::array<u8, default_stack_size> stack; | ||
| 34 | alignas(64) std::array<u8, default_stack_size> rewind_stack; | ||
| 35 | u8* stack_limit; | ||
| 36 | u8* rewind_stack_limit; | ||
| 37 | boost::context::detail::fcontext_t context; | ||
| 38 | boost::context::detail::fcontext_t rewind_context; | ||
| 39 | #endif | ||
| 22 | }; | 40 | }; |
| 23 | 41 | ||
| 42 | void Fiber::SetStartParameter(void* new_parameter) { | ||
| 43 | impl->start_parameter = new_parameter; | ||
| 44 | } | ||
| 45 | |||
| 46 | void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) { | ||
| 47 | impl->rewind_point = std::move(rewind_func); | ||
| 48 | impl->rewind_parameter = rewind_param; | ||
| 49 | } | ||
| 50 | |||
| 51 | #if defined(_WIN32) || defined(WIN32) | ||
| 52 | |||
| 24 | void Fiber::Start() { | 53 | void Fiber::Start() { |
| 25 | ASSERT(previous_fiber != nullptr); | 54 | ASSERT(impl->previous_fiber != nullptr); |
| 26 | previous_fiber->guard.unlock(); | 55 | impl->previous_fiber->impl->guard.unlock(); |
| 27 | previous_fiber.reset(); | 56 | impl->previous_fiber.reset(); |
| 28 | entry_point(start_parameter); | 57 | impl->entry_point(impl->start_parameter); |
| 29 | UNREACHABLE(); | 58 | UNREACHABLE(); |
| 30 | } | 59 | } |
| 31 | 60 | ||
| @@ -34,58 +63,54 @@ void Fiber::OnRewind() { | |||
| 34 | DeleteFiber(impl->handle); | 63 | DeleteFiber(impl->handle); |
| 35 | impl->handle = impl->rewind_handle; | 64 | impl->handle = impl->rewind_handle; |
| 36 | impl->rewind_handle = nullptr; | 65 | impl->rewind_handle = nullptr; |
| 37 | rewind_point(rewind_parameter); | 66 | impl->rewind_point(impl->rewind_parameter); |
| 38 | UNREACHABLE(); | 67 | UNREACHABLE(); |
| 39 | } | 68 | } |
| 40 | 69 | ||
| 41 | void Fiber::FiberStartFunc(void* fiber_parameter) { | 70 | void Fiber::FiberStartFunc(void* fiber_parameter) { |
| 42 | auto fiber = static_cast<Fiber*>(fiber_parameter); | 71 | auto* fiber = static_cast<Fiber*>(fiber_parameter); |
| 43 | fiber->Start(); | 72 | fiber->Start(); |
| 44 | } | 73 | } |
| 45 | 74 | ||
| 46 | void Fiber::RewindStartFunc(void* fiber_parameter) { | 75 | void Fiber::RewindStartFunc(void* fiber_parameter) { |
| 47 | auto fiber = static_cast<Fiber*>(fiber_parameter); | 76 | auto* fiber = static_cast<Fiber*>(fiber_parameter); |
| 48 | fiber->OnRewind(); | 77 | fiber->OnRewind(); |
| 49 | } | 78 | } |
| 50 | 79 | ||
| 51 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) | 80 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) |
| 52 | : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { | 81 | : impl{std::make_unique<FiberImpl>()} { |
| 53 | impl = std::make_unique<FiberImpl>(); | 82 | impl->entry_point = std::move(entry_point_func); |
| 83 | impl->start_parameter = start_parameter; | ||
| 54 | impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this); | 84 | impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this); |
| 55 | } | 85 | } |
| 56 | 86 | ||
| 57 | Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} | 87 | Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} |
| 58 | 88 | ||
| 59 | Fiber::~Fiber() { | 89 | Fiber::~Fiber() { |
| 60 | if (released) { | 90 | if (impl->released) { |
| 61 | return; | 91 | return; |
| 62 | } | 92 | } |
| 63 | // Make sure the Fiber is not being used | 93 | // Make sure the Fiber is not being used |
| 64 | const bool locked = guard.try_lock(); | 94 | const bool locked = impl->guard.try_lock(); |
| 65 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); | 95 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); |
| 66 | if (locked) { | 96 | if (locked) { |
| 67 | guard.unlock(); | 97 | impl->guard.unlock(); |
| 68 | } | 98 | } |
| 69 | DeleteFiber(impl->handle); | 99 | DeleteFiber(impl->handle); |
| 70 | } | 100 | } |
| 71 | 101 | ||
| 72 | void Fiber::Exit() { | 102 | void Fiber::Exit() { |
| 73 | ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); | 103 | ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber"); |
| 74 | if (!is_thread_fiber) { | 104 | if (!impl->is_thread_fiber) { |
| 75 | return; | 105 | return; |
| 76 | } | 106 | } |
| 77 | ConvertFiberToThread(); | 107 | ConvertFiberToThread(); |
| 78 | guard.unlock(); | 108 | impl->guard.unlock(); |
| 79 | released = true; | 109 | impl->released = true; |
| 80 | } | ||
| 81 | |||
| 82 | void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) { | ||
| 83 | rewind_point = std::move(rewind_func); | ||
| 84 | rewind_parameter = rewind_param; | ||
| 85 | } | 110 | } |
| 86 | 111 | ||
| 87 | void Fiber::Rewind() { | 112 | void Fiber::Rewind() { |
| 88 | ASSERT(rewind_point); | 113 | ASSERT(impl->rewind_point); |
| 89 | ASSERT(impl->rewind_handle == nullptr); | 114 | ASSERT(impl->rewind_handle == nullptr); |
| 90 | impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this); | 115 | impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this); |
| 91 | SwitchToFiber(impl->rewind_handle); | 116 | SwitchToFiber(impl->rewind_handle); |
| @@ -94,39 +119,30 @@ void Fiber::Rewind() { | |||
| 94 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { | 119 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { |
| 95 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); | 120 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); |
| 96 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); | 121 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); |
| 97 | to->guard.lock(); | 122 | to->impl->guard.lock(); |
| 98 | to->previous_fiber = from; | 123 | to->impl->previous_fiber = from; |
| 99 | SwitchToFiber(to->impl->handle); | 124 | SwitchToFiber(to->impl->handle); |
| 100 | ASSERT(from->previous_fiber != nullptr); | 125 | ASSERT(from->impl->previous_fiber != nullptr); |
| 101 | from->previous_fiber->guard.unlock(); | 126 | from->impl->previous_fiber->impl->guard.unlock(); |
| 102 | from->previous_fiber.reset(); | 127 | from->impl->previous_fiber.reset(); |
| 103 | } | 128 | } |
| 104 | 129 | ||
| 105 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { | 130 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { |
| 106 | std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; | 131 | std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; |
| 107 | fiber->guard.lock(); | 132 | fiber->impl->guard.lock(); |
| 108 | fiber->impl->handle = ConvertThreadToFiber(nullptr); | 133 | fiber->impl->handle = ConvertThreadToFiber(nullptr); |
| 109 | fiber->is_thread_fiber = true; | 134 | fiber->impl->is_thread_fiber = true; |
| 110 | return fiber; | 135 | return fiber; |
| 111 | } | 136 | } |
| 112 | 137 | ||
| 113 | #else | 138 | #else |
| 114 | 139 | ||
| 115 | struct Fiber::FiberImpl { | ||
| 116 | alignas(64) std::array<u8, default_stack_size> stack; | ||
| 117 | alignas(64) std::array<u8, default_stack_size> rewind_stack; | ||
| 118 | u8* stack_limit; | ||
| 119 | u8* rewind_stack_limit; | ||
| 120 | boost::context::detail::fcontext_t context; | ||
| 121 | boost::context::detail::fcontext_t rewind_context; | ||
| 122 | }; | ||
| 123 | |||
| 124 | void Fiber::Start(boost::context::detail::transfer_t& transfer) { | 140 | void Fiber::Start(boost::context::detail::transfer_t& transfer) { |
| 125 | ASSERT(previous_fiber != nullptr); | 141 | ASSERT(impl->previous_fiber != nullptr); |
| 126 | previous_fiber->impl->context = transfer.fctx; | 142 | impl->previous_fiber->impl->context = transfer.fctx; |
| 127 | previous_fiber->guard.unlock(); | 143 | impl->previous_fiber->impl->guard.unlock(); |
| 128 | previous_fiber.reset(); | 144 | impl->previous_fiber.reset(); |
| 129 | entry_point(start_parameter); | 145 | impl->entry_point(impl->start_parameter); |
| 130 | UNREACHABLE(); | 146 | UNREACHABLE(); |
| 131 | } | 147 | } |
| 132 | 148 | ||
| @@ -137,23 +153,24 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf | |||
| 137 | u8* tmp = impl->stack_limit; | 153 | u8* tmp = impl->stack_limit; |
| 138 | impl->stack_limit = impl->rewind_stack_limit; | 154 | impl->stack_limit = impl->rewind_stack_limit; |
| 139 | impl->rewind_stack_limit = tmp; | 155 | impl->rewind_stack_limit = tmp; |
| 140 | rewind_point(rewind_parameter); | 156 | impl->rewind_point(impl->rewind_parameter); |
| 141 | UNREACHABLE(); | 157 | UNREACHABLE(); |
| 142 | } | 158 | } |
| 143 | 159 | ||
| 144 | void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { | 160 | void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { |
| 145 | auto fiber = static_cast<Fiber*>(transfer.data); | 161 | auto* fiber = static_cast<Fiber*>(transfer.data); |
| 146 | fiber->Start(transfer); | 162 | fiber->Start(transfer); |
| 147 | } | 163 | } |
| 148 | 164 | ||
| 149 | void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { | 165 | void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { |
| 150 | auto fiber = static_cast<Fiber*>(transfer.data); | 166 | auto* fiber = static_cast<Fiber*>(transfer.data); |
| 151 | fiber->OnRewind(transfer); | 167 | fiber->OnRewind(transfer); |
| 152 | } | 168 | } |
| 153 | 169 | ||
| 154 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) | 170 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) |
| 155 | : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { | 171 | : impl{std::make_unique<FiberImpl>()} { |
| 156 | impl = std::make_unique<FiberImpl>(); | 172 | impl->entry_point = std::move(entry_point_func); |
| 173 | impl->start_parameter = start_parameter; | ||
| 157 | impl->stack_limit = impl->stack.data(); | 174 | impl->stack_limit = impl->stack.data(); |
| 158 | impl->rewind_stack_limit = impl->rewind_stack.data(); | 175 | impl->rewind_stack_limit = impl->rewind_stack.data(); |
| 159 | u8* stack_base = impl->stack_limit + default_stack_size; | 176 | u8* stack_base = impl->stack_limit + default_stack_size; |
| @@ -161,37 +178,31 @@ Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_paramete | |||
| 161 | boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc); | 178 | boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc); |
| 162 | } | 179 | } |
| 163 | 180 | ||
| 164 | void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) { | ||
| 165 | rewind_point = std::move(rewind_func); | ||
| 166 | rewind_parameter = rewind_param; | ||
| 167 | } | ||
| 168 | |||
| 169 | Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} | 181 | Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} |
| 170 | 182 | ||
| 171 | Fiber::~Fiber() { | 183 | Fiber::~Fiber() { |
| 172 | if (released) { | 184 | if (impl->released) { |
| 173 | return; | 185 | return; |
| 174 | } | 186 | } |
| 175 | // Make sure the Fiber is not being used | 187 | // Make sure the Fiber is not being used |
| 176 | const bool locked = guard.try_lock(); | 188 | const bool locked = impl->guard.try_lock(); |
| 177 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); | 189 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); |
| 178 | if (locked) { | 190 | if (locked) { |
| 179 | guard.unlock(); | 191 | impl->guard.unlock(); |
| 180 | } | 192 | } |
| 181 | } | 193 | } |
| 182 | 194 | ||
| 183 | void Fiber::Exit() { | 195 | void Fiber::Exit() { |
| 184 | 196 | ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber"); | |
| 185 | ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); | 197 | if (!impl->is_thread_fiber) { |
| 186 | if (!is_thread_fiber) { | ||
| 187 | return; | 198 | return; |
| 188 | } | 199 | } |
| 189 | guard.unlock(); | 200 | impl->guard.unlock(); |
| 190 | released = true; | 201 | impl->released = true; |
| 191 | } | 202 | } |
| 192 | 203 | ||
| 193 | void Fiber::Rewind() { | 204 | void Fiber::Rewind() { |
| 194 | ASSERT(rewind_point); | 205 | ASSERT(impl->rewind_point); |
| 195 | ASSERT(impl->rewind_context == nullptr); | 206 | ASSERT(impl->rewind_context == nullptr); |
| 196 | u8* stack_base = impl->rewind_stack_limit + default_stack_size; | 207 | u8* stack_base = impl->rewind_stack_limit + default_stack_size; |
| 197 | impl->rewind_context = | 208 | impl->rewind_context = |
| @@ -202,19 +213,19 @@ void Fiber::Rewind() { | |||
| 202 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { | 213 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { |
| 203 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); | 214 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); |
| 204 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); | 215 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); |
| 205 | to->guard.lock(); | 216 | to->impl->guard.lock(); |
| 206 | to->previous_fiber = from; | 217 | to->impl->previous_fiber = from; |
| 207 | auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); | 218 | auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); |
| 208 | ASSERT(from->previous_fiber != nullptr); | 219 | ASSERT(from->impl->previous_fiber != nullptr); |
| 209 | from->previous_fiber->impl->context = transfer.fctx; | 220 | from->impl->previous_fiber->impl->context = transfer.fctx; |
| 210 | from->previous_fiber->guard.unlock(); | 221 | from->impl->previous_fiber->impl->guard.unlock(); |
| 211 | from->previous_fiber.reset(); | 222 | from->impl->previous_fiber.reset(); |
| 212 | } | 223 | } |
| 213 | 224 | ||
| 214 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { | 225 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { |
| 215 | std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; | 226 | std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; |
| 216 | fiber->guard.lock(); | 227 | fiber->impl->guard.lock(); |
| 217 | fiber->is_thread_fiber = true; | 228 | fiber->impl->is_thread_fiber = true; |
| 218 | return fiber; | 229 | return fiber; |
| 219 | } | 230 | } |
| 220 | 231 | ||
diff --git a/src/common/fiber.h b/src/common/fiber.h index 699286ee2..5323e8579 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h | |||
| @@ -7,9 +7,6 @@ | |||
| 7 | #include <functional> | 7 | #include <functional> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/spin_lock.h" | ||
| 12 | |||
| 13 | #if !defined(_WIN32) && !defined(WIN32) | 10 | #if !defined(_WIN32) && !defined(WIN32) |
| 14 | namespace boost::context::detail { | 11 | namespace boost::context::detail { |
| 15 | struct transfer_t; | 12 | struct transfer_t; |
| @@ -57,9 +54,7 @@ public: | |||
| 57 | void Exit(); | 54 | void Exit(); |
| 58 | 55 | ||
| 59 | /// Changes the start parameter of the fiber. Has no effect if the fiber already started | 56 | /// Changes the start parameter of the fiber. Has no effect if the fiber already started |
| 60 | void SetStartParameter(void* new_parameter) { | 57 | void SetStartParameter(void* new_parameter); |
| 61 | start_parameter = new_parameter; | ||
| 62 | } | ||
| 63 | 58 | ||
| 64 | private: | 59 | private: |
| 65 | Fiber(); | 60 | Fiber(); |
| @@ -77,16 +72,7 @@ private: | |||
| 77 | #endif | 72 | #endif |
| 78 | 73 | ||
| 79 | struct FiberImpl; | 74 | struct FiberImpl; |
| 80 | |||
| 81 | SpinLock guard{}; | ||
| 82 | std::function<void(void*)> entry_point; | ||
| 83 | std::function<void(void*)> rewind_point; | ||
| 84 | void* rewind_parameter{}; | ||
| 85 | void* start_parameter{}; | ||
| 86 | std::shared_ptr<Fiber> previous_fiber; | ||
| 87 | std::unique_ptr<FiberImpl> impl; | 75 | std::unique_ptr<FiberImpl> impl; |
| 88 | bool is_thread_fiber{}; | ||
| 89 | bool released{}; | ||
| 90 | }; | 76 | }; |
| 91 | 77 | ||
| 92 | } // namespace Common | 78 | } // namespace Common |
diff --git a/src/common/spin_lock.h b/src/common/spin_lock.h index 4f946a258..06ac2f5bb 100644 --- a/src/common/spin_lock.h +++ b/src/common/spin_lock.h | |||
| @@ -15,6 +15,14 @@ namespace Common { | |||
| 15 | */ | 15 | */ |
| 16 | class SpinLock { | 16 | class SpinLock { |
| 17 | public: | 17 | public: |
| 18 | SpinLock() = default; | ||
| 19 | |||
| 20 | SpinLock(const SpinLock&) = delete; | ||
| 21 | SpinLock& operator=(const SpinLock&) = delete; | ||
| 22 | |||
| 23 | SpinLock(SpinLock&&) = delete; | ||
| 24 | SpinLock& operator=(SpinLock&&) = delete; | ||
| 25 | |||
| 18 | void lock(); | 26 | void lock(); |
| 19 | void unlock(); | 27 | void unlock(); |
| 20 | [[nodiscard]] bool try_lock(); | 28 | [[nodiscard]] bool try_lock(); |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 19c926662..a1d8dcfa5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -452,6 +452,8 @@ add_library(core STATIC | |||
| 452 | hle/service/nvdrv/nvdrv.h | 452 | hle/service/nvdrv/nvdrv.h |
| 453 | hle/service/nvdrv/nvmemp.cpp | 453 | hle/service/nvdrv/nvmemp.cpp |
| 454 | hle/service/nvdrv/nvmemp.h | 454 | hle/service/nvdrv/nvmemp.h |
| 455 | hle/service/nvdrv/syncpoint_manager.cpp | ||
| 456 | hle/service/nvdrv/syncpoint_manager.h | ||
| 455 | hle/service/nvflinger/buffer_queue.cpp | 457 | hle/service/nvflinger/buffer_queue.cpp |
| 456 | hle/service/nvflinger/buffer_queue.h | 458 | hle/service/nvflinger/buffer_queue.h |
| 457 | hle/service/nvflinger/nvflinger.cpp | 459 | hle/service/nvflinger/nvflinger.cpp |
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index d2295ed90..0951e1976 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp | |||
| @@ -147,10 +147,18 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContex | |||
| 147 | auto fp = ctx.cpu_registers[29]; | 147 | auto fp = ctx.cpu_registers[29]; |
| 148 | auto lr = ctx.cpu_registers[30]; | 148 | auto lr = ctx.cpu_registers[30]; |
| 149 | while (true) { | 149 | while (true) { |
| 150 | out.push_back({"", 0, lr, 0}); | 150 | out.push_back({ |
| 151 | if (!fp) { | 151 | .module = "", |
| 152 | .address = 0, | ||
| 153 | .original_address = lr, | ||
| 154 | .offset = 0, | ||
| 155 | .name = {}, | ||
| 156 | }); | ||
| 157 | |||
| 158 | if (fp == 0) { | ||
| 152 | break; | 159 | break; |
| 153 | } | 160 | } |
| 161 | |||
| 154 | lr = memory.Read64(fp + 8) - 4; | 162 | lr = memory.Read64(fp + 8) - 4; |
| 155 | fp = memory.Read64(fp); | 163 | fp = memory.Read64(fp); |
| 156 | } | 164 | } |
diff --git a/src/core/core.cpp b/src/core/core.cpp index fde2ccc09..242796008 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -179,16 +179,18 @@ struct System::Impl { | |||
| 179 | arp_manager.ResetAll(); | 179 | arp_manager.ResetAll(); |
| 180 | 180 | ||
| 181 | telemetry_session = std::make_unique<Core::TelemetrySession>(); | 181 | telemetry_session = std::make_unique<Core::TelemetrySession>(); |
| 182 | |||
| 183 | gpu_core = VideoCore::CreateGPU(emu_window, system); | ||
| 184 | if (!gpu_core) { | ||
| 185 | return ResultStatus::ErrorVideoCore; | ||
| 186 | } | ||
| 187 | |||
| 182 | service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); | 188 | service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); |
| 183 | 189 | ||
| 184 | Service::Init(service_manager, system); | 190 | Service::Init(service_manager, system); |
| 185 | GDBStub::DeferStart(); | 191 | GDBStub::DeferStart(); |
| 186 | 192 | ||
| 187 | interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); | 193 | interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); |
| 188 | gpu_core = VideoCore::CreateGPU(emu_window, system); | ||
| 189 | if (!gpu_core) { | ||
| 190 | return ResultStatus::ErrorVideoCore; | ||
| 191 | } | ||
| 192 | 194 | ||
| 193 | // Initialize time manager, which must happen after kernel is created | 195 | // Initialize time manager, which must happen after kernel is created |
| 194 | time_manager.Initialize(); | 196 | time_manager.Initialize(); |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 75d9191ff..8356a8139 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -15,8 +15,9 @@ | |||
| 15 | 15 | ||
| 16 | namespace Service::Nvidia::Devices { | 16 | namespace Service::Nvidia::Devices { |
| 17 | 17 | ||
| 18 | nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface) | 18 | nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface, |
| 19 | : nvdevice(system), events_interface{events_interface} {} | 19 | SyncpointManager& syncpoint_manager) |
| 20 | : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {} | ||
| 20 | nvhost_ctrl::~nvhost_ctrl() = default; | 21 | nvhost_ctrl::~nvhost_ctrl() = default; |
| 21 | 22 | ||
| 22 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 23 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| @@ -70,19 +71,33 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& | |||
| 70 | return NvResult::BadParameter; | 71 | return NvResult::BadParameter; |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 74 | if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { | ||
| 75 | params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id); | ||
| 76 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 77 | return NvResult::Success; | ||
| 78 | } | ||
| 79 | |||
| 80 | if (const auto new_value = syncpoint_manager.RefreshSyncpoint(params.syncpt_id); | ||
| 81 | syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { | ||
| 82 | params.value = new_value; | ||
| 83 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 84 | return NvResult::Success; | ||
| 85 | } | ||
| 86 | |||
| 73 | auto event = events_interface.events[event_id]; | 87 | auto event = events_interface.events[event_id]; |
| 74 | auto& gpu = system.GPU(); | 88 | auto& gpu = system.GPU(); |
| 89 | |||
| 75 | // This is mostly to take into account unimplemented features. As synced | 90 | // This is mostly to take into account unimplemented features. As synced |
| 76 | // gpu is always synced. | 91 | // gpu is always synced. |
| 77 | if (!gpu.IsAsync()) { | 92 | if (!gpu.IsAsync()) { |
| 78 | event.writable->Signal(); | 93 | event.event.writable->Signal(); |
| 79 | return NvResult::Success; | 94 | return NvResult::Success; |
| 80 | } | 95 | } |
| 81 | auto lock = gpu.LockSync(); | 96 | auto lock = gpu.LockSync(); |
| 82 | const u32 current_syncpoint_value = gpu.GetSyncpointValue(params.syncpt_id); | 97 | const u32 current_syncpoint_value = event.fence.value; |
| 83 | const s32 diff = current_syncpoint_value - params.threshold; | 98 | const s32 diff = current_syncpoint_value - params.threshold; |
| 84 | if (diff >= 0) { | 99 | if (diff >= 0) { |
| 85 | event.writable->Signal(); | 100 | event.event.writable->Signal(); |
| 86 | params.value = current_syncpoint_value; | 101 | params.value = current_syncpoint_value; |
| 87 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 102 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 88 | return NvResult::Success; | 103 | return NvResult::Success; |
| @@ -109,7 +124,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& | |||
| 109 | params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; | 124 | params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; |
| 110 | } | 125 | } |
| 111 | params.value |= event_id; | 126 | params.value |= event_id; |
| 112 | event.writable->Clear(); | 127 | event.event.writable->Clear(); |
| 113 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); | 128 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); |
| 114 | if (!is_async && ctrl.fresh_call) { | 129 | if (!is_async && ctrl.fresh_call) { |
| 115 | ctrl.must_delay = true; | 130 | ctrl.must_delay = true; |
| @@ -157,15 +172,19 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto | |||
| 157 | u32 nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { | 172 | u32 nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { |
| 158 | IocCtrlEventSignalParams params{}; | 173 | IocCtrlEventSignalParams params{}; |
| 159 | std::memcpy(¶ms, input.data(), sizeof(params)); | 174 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 175 | |||
| 160 | u32 event_id = params.event_id & 0x00FF; | 176 | u32 event_id = params.event_id & 0x00FF; |
| 161 | LOG_WARNING(Service_NVDRV, "cleared event wait on, event_id: {:X}", event_id); | 177 | LOG_WARNING(Service_NVDRV, "cleared event wait on, event_id: {:X}", event_id); |
| 178 | |||
| 162 | if (event_id >= MaxNvEvents) { | 179 | if (event_id >= MaxNvEvents) { |
| 163 | return NvResult::BadParameter; | 180 | return NvResult::BadParameter; |
| 164 | } | 181 | } |
| 165 | if (events_interface.status[event_id] == EventState::Waiting) { | 182 | if (events_interface.status[event_id] == EventState::Waiting) { |
| 166 | events_interface.LiberateEvent(event_id); | 183 | events_interface.LiberateEvent(event_id); |
| 167 | events_interface.events[event_id].writable->Signal(); | ||
| 168 | } | 184 | } |
| 185 | |||
| 186 | syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id); | ||
| 187 | |||
| 169 | return NvResult::Success; | 188 | return NvResult::Success; |
| 170 | } | 189 | } |
| 171 | 190 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index f7b04d9f1..24ad96cb9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | |||
| @@ -14,7 +14,8 @@ namespace Service::Nvidia::Devices { | |||
| 14 | 14 | ||
| 15 | class nvhost_ctrl final : public nvdevice { | 15 | class nvhost_ctrl final : public nvdevice { |
| 16 | public: | 16 | public: |
| 17 | explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface); | 17 | explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface, |
| 18 | SyncpointManager& syncpoint_manager); | ||
| 18 | ~nvhost_ctrl() override; | 19 | ~nvhost_ctrl() override; |
| 19 | 20 | ||
| 20 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 21 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| @@ -145,6 +146,7 @@ private: | |||
| 145 | u32 IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); | 146 | u32 IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); |
| 146 | 147 | ||
| 147 | EventInterface& events_interface; | 148 | EventInterface& events_interface; |
| 149 | SyncpointManager& syncpoint_manager; | ||
| 148 | }; | 150 | }; |
| 149 | 151 | ||
| 150 | } // namespace Service::Nvidia::Devices | 152 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index f1966ac0e..152019548 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -7,14 +7,20 @@ | |||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" | 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" |
| 10 | #include "core/hle/service/nvdrv/syncpoint_manager.h" | ||
| 10 | #include "core/memory.h" | 11 | #include "core/memory.h" |
| 11 | #include "video_core/gpu.h" | 12 | #include "video_core/gpu.h" |
| 12 | #include "video_core/memory_manager.h" | 13 | #include "video_core/memory_manager.h" |
| 13 | 14 | ||
| 14 | namespace Service::Nvidia::Devices { | 15 | namespace Service::Nvidia::Devices { |
| 15 | 16 | ||
| 16 | nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | 17 | nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 17 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 18 | SyncpointManager& syncpoint_manager) |
| 19 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager{syncpoint_manager} { | ||
| 20 | channel_fence.id = syncpoint_manager.AllocateSyncpoint(); | ||
| 21 | channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id); | ||
| 22 | } | ||
| 23 | |||
| 18 | nvhost_gpu::~nvhost_gpu() = default; | 24 | nvhost_gpu::~nvhost_gpu() = default; |
| 19 | 25 | ||
| 20 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 26 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| @@ -126,10 +132,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 126 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, | 132 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, |
| 127 | params.unk3); | 133 | params.unk3); |
| 128 | 134 | ||
| 129 | auto& gpu = system.GPU(); | 135 | channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id); |
| 130 | params.fence_out.id = assigned_syncpoints; | 136 | |
| 131 | params.fence_out.value = gpu.GetSyncpointValue(assigned_syncpoints); | 137 | params.fence_out = channel_fence; |
| 132 | assigned_syncpoints++; | 138 | |
| 133 | std::memcpy(output.data(), ¶ms, output.size()); | 139 | std::memcpy(output.data(), ¶ms, output.size()); |
| 134 | return 0; | 140 | return 0; |
| 135 | } | 141 | } |
| @@ -145,39 +151,100 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector< | |||
| 145 | return 0; | 151 | return 0; |
| 146 | } | 152 | } |
| 147 | 153 | ||
| 148 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | 154 | static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { |
| 149 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 155 | return { |
| 150 | UNIMPLEMENTED(); | 156 | Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, |
| 157 | Tegra::SubmissionMode::Increasing), | ||
| 158 | {fence.value}, | ||
| 159 | Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, | ||
| 160 | Tegra::SubmissionMode::Increasing), | ||
| 161 | Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Acquire, fence.id), | ||
| 162 | }; | ||
| 163 | } | ||
| 164 | |||
| 165 | static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(Fence fence, u32 add_increment) { | ||
| 166 | std::vector<Tegra::CommandHeader> result{ | ||
| 167 | Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, | ||
| 168 | Tegra::SubmissionMode::Increasing), | ||
| 169 | {}}; | ||
| 170 | |||
| 171 | for (u32 count = 0; count < add_increment; ++count) { | ||
| 172 | result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, | ||
| 173 | Tegra::SubmissionMode::Increasing)); | ||
| 174 | result.emplace_back( | ||
| 175 | Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Increment, fence.id)); | ||
| 151 | } | 176 | } |
| 152 | IoctlSubmitGpfifo params{}; | 177 | |
| 153 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 178 | return result; |
| 179 | } | ||
| 180 | |||
| 181 | static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence fence, | ||
| 182 | u32 add_increment) { | ||
| 183 | std::vector<Tegra::CommandHeader> result{ | ||
| 184 | Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1, | ||
| 185 | Tegra::SubmissionMode::Increasing), | ||
| 186 | {}}; | ||
| 187 | const std::vector<Tegra::CommandHeader> increment{ | ||
| 188 | BuildIncrementCommandList(fence, add_increment)}; | ||
| 189 | |||
| 190 | result.insert(result.end(), increment.begin(), increment.end()); | ||
| 191 | |||
| 192 | return result; | ||
| 193 | } | ||
| 194 | |||
| 195 | u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, | ||
| 196 | Tegra::CommandList&& entries) { | ||
| 154 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, | 197 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, |
| 155 | params.num_entries, params.flags.raw); | 198 | params.num_entries, params.flags.raw); |
| 156 | 199 | ||
| 157 | ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) + | 200 | auto& gpu = system.GPU(); |
| 158 | params.num_entries * sizeof(Tegra::CommandListHeader), | ||
| 159 | "Incorrect input size"); | ||
| 160 | 201 | ||
| 161 | Tegra::CommandList entries(params.num_entries); | 202 | params.fence_out.id = channel_fence.id; |
| 162 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], | ||
| 163 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 164 | 203 | ||
| 165 | UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); | 204 | if (params.flags.add_wait.Value() && |
| 166 | UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); | 205 | !syncpoint_manager.IsSyncpointExpired(params.fence_out.id, params.fence_out.value)) { |
| 206 | gpu.PushGPUEntries(Tegra::CommandList{BuildWaitCommandList(params.fence_out)}); | ||
| 207 | } | ||
| 167 | 208 | ||
| 168 | auto& gpu = system.GPU(); | 209 | if (params.flags.add_increment.Value() || params.flags.increment.Value()) { |
| 169 | u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id); | 210 | const u32 increment_value = params.flags.increment.Value() ? params.fence_out.value : 0; |
| 170 | if (params.flags.increment.Value()) { | 211 | params.fence_out.value = syncpoint_manager.IncreaseSyncpoint( |
| 171 | params.fence_out.value += current_syncpoint_value; | 212 | params.fence_out.id, params.AddIncrementValue() + increment_value); |
| 172 | } else { | 213 | } else { |
| 173 | params.fence_out.value = current_syncpoint_value; | 214 | params.fence_out.value = syncpoint_manager.GetSyncpointMax(params.fence_out.id); |
| 174 | } | 215 | } |
| 216 | |||
| 217 | entries.RefreshIntegrityChecks(gpu); | ||
| 175 | gpu.PushGPUEntries(std::move(entries)); | 218 | gpu.PushGPUEntries(std::move(entries)); |
| 176 | 219 | ||
| 220 | if (params.flags.add_increment.Value()) { | ||
| 221 | if (params.flags.suppress_wfi) { | ||
| 222 | gpu.PushGPUEntries(Tegra::CommandList{ | ||
| 223 | BuildIncrementCommandList(params.fence_out, params.AddIncrementValue())}); | ||
| 224 | } else { | ||
| 225 | gpu.PushGPUEntries(Tegra::CommandList{ | ||
| 226 | BuildIncrementWithWfiCommandList(params.fence_out, params.AddIncrementValue())}); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 177 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); | 230 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); |
| 178 | return 0; | 231 | return 0; |
| 179 | } | 232 | } |
| 180 | 233 | ||
| 234 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 235 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | ||
| 236 | UNIMPLEMENTED(); | ||
| 237 | } | ||
| 238 | IoctlSubmitGpfifo params{}; | ||
| 239 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | ||
| 240 | |||
| 241 | Tegra::CommandList entries(params.num_entries); | ||
| 242 | std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], | ||
| 243 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 244 | |||
| 245 | return SubmitGPFIFOImpl(params, output, std::move(entries)); | ||
| 246 | } | ||
| 247 | |||
| 181 | u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | 248 | u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, |
| 182 | const std::vector<u8>& input2, IoctlVersion version) { | 249 | const std::vector<u8>& input2, IoctlVersion version) { |
| 183 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 250 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| @@ -185,31 +252,17 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | |||
| 185 | } | 252 | } |
| 186 | IoctlSubmitGpfifo params{}; | 253 | IoctlSubmitGpfifo params{}; |
| 187 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 254 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); |
| 188 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, | ||
| 189 | params.num_entries, params.flags.raw); | ||
| 190 | 255 | ||
| 191 | Tegra::CommandList entries(params.num_entries); | 256 | Tegra::CommandList entries(params.num_entries); |
| 192 | if (version == IoctlVersion::Version2) { | 257 | if (version == IoctlVersion::Version2) { |
| 193 | std::memcpy(entries.data(), input2.data(), | 258 | std::memcpy(entries.command_lists.data(), input2.data(), |
| 194 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 259 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 195 | } else { | 260 | } else { |
| 196 | system.Memory().ReadBlock(params.address, entries.data(), | 261 | system.Memory().ReadBlock(params.address, entries.command_lists.data(), |
| 197 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 262 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 198 | } | 263 | } |
| 199 | UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); | ||
| 200 | UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); | ||
| 201 | |||
| 202 | auto& gpu = system.GPU(); | ||
| 203 | u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id); | ||
| 204 | if (params.flags.increment.Value()) { | ||
| 205 | params.fence_out.value += current_syncpoint_value; | ||
| 206 | } else { | ||
| 207 | params.fence_out.value = current_syncpoint_value; | ||
| 208 | } | ||
| 209 | gpu.PushGPUEntries(std::move(entries)); | ||
| 210 | 264 | ||
| 211 | std::memcpy(output.data(), ¶ms, output.size()); | 265 | return SubmitGPFIFOImpl(params, output, std::move(entries)); |
| 212 | return 0; | ||
| 213 | } | 266 | } |
| 214 | 267 | ||
| 215 | u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | 268 | u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 2ac74743f..a252fc06d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h | |||
| @@ -11,6 +11,11 @@ | |||
| 11 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | 12 | #include "core/hle/service/nvdrv/devices/nvdevice.h" |
| 13 | #include "core/hle/service/nvdrv/nvdata.h" | 13 | #include "core/hle/service/nvdrv/nvdata.h" |
| 14 | #include "video_core/dma_pusher.h" | ||
| 15 | |||
| 16 | namespace Service::Nvidia { | ||
| 17 | class SyncpointManager; | ||
| 18 | } | ||
| 14 | 19 | ||
| 15 | namespace Service::Nvidia::Devices { | 20 | namespace Service::Nvidia::Devices { |
| 16 | 21 | ||
| @@ -21,7 +26,8 @@ constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b); | |||
| 21 | 26 | ||
| 22 | class nvhost_gpu final : public nvdevice { | 27 | class nvhost_gpu final : public nvdevice { |
| 23 | public: | 28 | public: |
| 24 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 29 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 30 | SyncpointManager& syncpoint_manager); | ||
| 25 | ~nvhost_gpu() override; | 31 | ~nvhost_gpu() override; |
| 26 | 32 | ||
| 27 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 33 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| @@ -162,10 +168,15 @@ private: | |||
| 162 | u32_le raw; | 168 | u32_le raw; |
| 163 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list | 169 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list |
| 164 | BitField<1, 1, u32_le> add_increment; // append an increment to the list | 170 | BitField<1, 1, u32_le> add_increment; // append an increment to the list |
| 165 | BitField<2, 1, u32_le> new_hw_format; // Mostly ignored | 171 | BitField<2, 1, u32_le> new_hw_format; // mostly ignored |
| 172 | BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt | ||
| 166 | BitField<8, 1, u32_le> increment; // increment the returned fence | 173 | BitField<8, 1, u32_le> increment; // increment the returned fence |
| 167 | } flags; | 174 | } flags; |
| 168 | Fence fence_out; // returned new fence object for others to wait on | 175 | Fence fence_out; // returned new fence object for others to wait on |
| 176 | |||
| 177 | u32 AddIncrementValue() const { | ||
| 178 | return flags.add_increment.Value() << 1; | ||
| 179 | } | ||
| 169 | }; | 180 | }; |
| 170 | static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), | 181 | static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), |
| 171 | "IoctlSubmitGpfifo is incorrect size"); | 182 | "IoctlSubmitGpfifo is incorrect size"); |
| @@ -190,6 +201,8 @@ private: | |||
| 190 | u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); | 201 | u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); |
| 191 | u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); | 202 | u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); |
| 192 | u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); | 203 | u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); |
| 204 | u32 SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, | ||
| 205 | Tegra::CommandList&& entries); | ||
| 193 | u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); | 206 | u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); |
| 194 | u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | 207 | u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, |
| 195 | const std::vector<u8>& input2, IoctlVersion version); | 208 | const std::vector<u8>& input2, IoctlVersion version); |
| @@ -198,7 +211,8 @@ private: | |||
| 198 | u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); | 211 | u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); |
| 199 | 212 | ||
| 200 | std::shared_ptr<nvmap> nvmap_dev; | 213 | std::shared_ptr<nvmap> nvmap_dev; |
| 201 | u32 assigned_syncpoints{}; | 214 | SyncpointManager& syncpoint_manager; |
| 215 | Fence channel_fence; | ||
| 202 | }; | 216 | }; |
| 203 | 217 | ||
| 204 | } // namespace Service::Nvidia::Devices | 218 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 803c1a984..a46755cdc 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include "core/hle/service/nvdrv/interface.h" | 21 | #include "core/hle/service/nvdrv/interface.h" |
| 22 | #include "core/hle/service/nvdrv/nvdrv.h" | 22 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 23 | #include "core/hle/service/nvdrv/nvmemp.h" | 23 | #include "core/hle/service/nvdrv/nvmemp.h" |
| 24 | #include "core/hle/service/nvdrv/syncpoint_manager.h" | ||
| 24 | #include "core/hle/service/nvflinger/nvflinger.h" | 25 | #include "core/hle/service/nvflinger/nvflinger.h" |
| 25 | 26 | ||
| 26 | namespace Service::Nvidia { | 27 | namespace Service::Nvidia { |
| @@ -36,21 +37,23 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger | |||
| 36 | nvflinger.SetNVDrvInstance(module_); | 37 | nvflinger.SetNVDrvInstance(module_); |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | Module::Module(Core::System& system) { | 40 | Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { |
| 40 | auto& kernel = system.Kernel(); | 41 | auto& kernel = system.Kernel(); |
| 41 | for (u32 i = 0; i < MaxNvEvents; i++) { | 42 | for (u32 i = 0; i < MaxNvEvents; i++) { |
| 42 | std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); | 43 | std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); |
| 43 | events_interface.events[i] = Kernel::WritableEvent::CreateEventPair(kernel, event_label); | 44 | events_interface.events[i] = {Kernel::WritableEvent::CreateEventPair(kernel, event_label)}; |
| 44 | events_interface.status[i] = EventState::Free; | 45 | events_interface.status[i] = EventState::Free; |
| 45 | events_interface.registered[i] = false; | 46 | events_interface.registered[i] = false; |
| 46 | } | 47 | } |
| 47 | auto nvmap_dev = std::make_shared<Devices::nvmap>(system); | 48 | auto nvmap_dev = std::make_shared<Devices::nvmap>(system); |
| 48 | devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev); | 49 | devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev); |
| 49 | devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev); | 50 | devices["/dev/nvhost-gpu"] = |
| 51 | std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev, syncpoint_manager); | ||
| 50 | devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system); | 52 | devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system); |
| 51 | devices["/dev/nvmap"] = nvmap_dev; | 53 | devices["/dev/nvmap"] = nvmap_dev; |
| 52 | devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev); | 54 | devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev); |
| 53 | devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(system, events_interface); | 55 | devices["/dev/nvhost-ctrl"] = |
| 56 | std::make_shared<Devices::nvhost_ctrl>(system, events_interface, syncpoint_manager); | ||
| 54 | devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system, nvmap_dev); | 57 | devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system, nvmap_dev); |
| 55 | devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); | 58 | devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); |
| 56 | devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system, nvmap_dev); | 59 | devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system, nvmap_dev); |
| @@ -95,17 +98,17 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { | |||
| 95 | if (events_interface.assigned_syncpt[i] == syncpoint_id && | 98 | if (events_interface.assigned_syncpt[i] == syncpoint_id && |
| 96 | events_interface.assigned_value[i] == value) { | 99 | events_interface.assigned_value[i] == value) { |
| 97 | events_interface.LiberateEvent(i); | 100 | events_interface.LiberateEvent(i); |
| 98 | events_interface.events[i].writable->Signal(); | 101 | events_interface.events[i].event.writable->Signal(); |
| 99 | } | 102 | } |
| 100 | } | 103 | } |
| 101 | } | 104 | } |
| 102 | 105 | ||
| 103 | std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const { | 106 | std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const { |
| 104 | return events_interface.events[event_id].readable; | 107 | return events_interface.events[event_id].event.readable; |
| 105 | } | 108 | } |
| 106 | 109 | ||
| 107 | std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const { | 110 | std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const { |
| 108 | return events_interface.events[event_id].writable; | 111 | return events_interface.events[event_id].event.writable; |
| 109 | } | 112 | } |
| 110 | 113 | ||
| 111 | } // namespace Service::Nvidia | 114 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 7706a5590..f3d863dac 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/kernel/writable_event.h" | 11 | #include "core/hle/kernel/writable_event.h" |
| 12 | #include "core/hle/service/nvdrv/nvdata.h" | 12 | #include "core/hle/service/nvdrv/nvdata.h" |
| 13 | #include "core/hle/service/nvdrv/syncpoint_manager.h" | ||
| 13 | #include "core/hle/service/service.h" | 14 | #include "core/hle/service/service.h" |
| 14 | 15 | ||
| 15 | namespace Core { | 16 | namespace Core { |
| @@ -22,15 +23,23 @@ class NVFlinger; | |||
| 22 | 23 | ||
| 23 | namespace Service::Nvidia { | 24 | namespace Service::Nvidia { |
| 24 | 25 | ||
| 26 | class SyncpointManager; | ||
| 27 | |||
| 25 | namespace Devices { | 28 | namespace Devices { |
| 26 | class nvdevice; | 29 | class nvdevice; |
| 27 | } | 30 | } |
| 28 | 31 | ||
| 32 | /// Represents an Nvidia event | ||
| 33 | struct NvEvent { | ||
| 34 | Kernel::EventPair event; | ||
| 35 | Fence fence{}; | ||
| 36 | }; | ||
| 37 | |||
| 29 | struct EventInterface { | 38 | struct EventInterface { |
| 30 | // Mask representing currently busy events | 39 | // Mask representing currently busy events |
| 31 | u64 events_mask{}; | 40 | u64 events_mask{}; |
| 32 | // Each kernel event associated to an NV event | 41 | // Each kernel event associated to an NV event |
| 33 | std::array<Kernel::EventPair, MaxNvEvents> events; | 42 | std::array<NvEvent, MaxNvEvents> events; |
| 34 | // The status of the current NVEvent | 43 | // The status of the current NVEvent |
| 35 | std::array<EventState, MaxNvEvents> status{}; | 44 | std::array<EventState, MaxNvEvents> status{}; |
| 36 | // Tells if an NVEvent is registered or not | 45 | // Tells if an NVEvent is registered or not |
| @@ -119,6 +128,9 @@ public: | |||
| 119 | std::shared_ptr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const; | 128 | std::shared_ptr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const; |
| 120 | 129 | ||
| 121 | private: | 130 | private: |
| 131 | /// Manages syncpoints on the host | ||
| 132 | SyncpointManager syncpoint_manager; | ||
| 133 | |||
| 122 | /// Id to use for the next open file descriptor. | 134 | /// Id to use for the next open file descriptor. |
| 123 | u32 next_fd = 1; | 135 | u32 next_fd = 1; |
| 124 | 136 | ||
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/syncpoint_manager.cpp new file mode 100644 index 000000000..0151a03b7 --- /dev/null +++ b/src/core/hle/service/nvdrv/syncpoint_manager.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "core/hle/service/nvdrv/syncpoint_manager.h" | ||
| 7 | #include "video_core/gpu.h" | ||
| 8 | |||
| 9 | namespace Service::Nvidia { | ||
| 10 | |||
| 11 | SyncpointManager::SyncpointManager(Tegra::GPU& gpu) : gpu{gpu} {} | ||
| 12 | |||
| 13 | SyncpointManager::~SyncpointManager() = default; | ||
| 14 | |||
| 15 | u32 SyncpointManager::RefreshSyncpoint(u32 syncpoint_id) { | ||
| 16 | syncpoints[syncpoint_id].min = gpu.GetSyncpointValue(syncpoint_id); | ||
| 17 | return GetSyncpointMin(syncpoint_id); | ||
| 18 | } | ||
| 19 | |||
| 20 | u32 SyncpointManager::AllocateSyncpoint() { | ||
| 21 | for (u32 syncpoint_id = 1; syncpoint_id < MaxSyncPoints; syncpoint_id++) { | ||
| 22 | if (!syncpoints[syncpoint_id].is_allocated) { | ||
| 23 | syncpoints[syncpoint_id].is_allocated = true; | ||
| 24 | return syncpoint_id; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | UNREACHABLE_MSG("No more available syncpoints!"); | ||
| 28 | return {}; | ||
| 29 | } | ||
| 30 | |||
| 31 | u32 SyncpointManager::IncreaseSyncpoint(u32 syncpoint_id, u32 value) { | ||
| 32 | for (u32 index = 0; index < value; ++index) { | ||
| 33 | syncpoints[syncpoint_id].max.fetch_add(1, std::memory_order_relaxed); | ||
| 34 | } | ||
| 35 | |||
| 36 | return GetSyncpointMax(syncpoint_id); | ||
| 37 | } | ||
| 38 | |||
| 39 | } // namespace Service::Nvidia | ||
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.h b/src/core/hle/service/nvdrv/syncpoint_manager.h new file mode 100644 index 000000000..4168b6c7e --- /dev/null +++ b/src/core/hle/service/nvdrv/syncpoint_manager.h | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <atomic> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hle/service/nvdrv/nvdata.h" | ||
| 12 | |||
| 13 | namespace Tegra { | ||
| 14 | class GPU; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace Service::Nvidia { | ||
| 18 | |||
| 19 | class SyncpointManager final { | ||
| 20 | public: | ||
| 21 | explicit SyncpointManager(Tegra::GPU& gpu); | ||
| 22 | ~SyncpointManager(); | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Returns true if the specified syncpoint is expired for the given value. | ||
| 26 | * @param syncpoint_id Syncpoint ID to check. | ||
| 27 | * @param value Value to check against the specified syncpoint. | ||
| 28 | * @returns True if the specified syncpoint is expired for the given value, otherwise False. | ||
| 29 | */ | ||
| 30 | bool IsSyncpointExpired(u32 syncpoint_id, u32 value) const { | ||
| 31 | return (GetSyncpointMax(syncpoint_id) - value) >= (GetSyncpointMin(syncpoint_id) - value); | ||
| 32 | } | ||
| 33 | |||
| 34 | /** | ||
| 35 | * Gets the lower bound for the specified syncpoint. | ||
| 36 | * @param syncpoint_id Syncpoint ID to get the lower bound for. | ||
| 37 | * @returns The lower bound for the specified syncpoint. | ||
| 38 | */ | ||
| 39 | u32 GetSyncpointMin(u32 syncpoint_id) const { | ||
| 40 | return syncpoints[syncpoint_id].min.load(std::memory_order_relaxed); | ||
| 41 | } | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Gets the uper bound for the specified syncpoint. | ||
| 45 | * @param syncpoint_id Syncpoint ID to get the upper bound for. | ||
| 46 | * @returns The upper bound for the specified syncpoint. | ||
| 47 | */ | ||
| 48 | u32 GetSyncpointMax(u32 syncpoint_id) const { | ||
| 49 | return syncpoints[syncpoint_id].max.load(std::memory_order_relaxed); | ||
| 50 | } | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Refreshes the minimum value for the specified syncpoint. | ||
| 54 | * @param syncpoint_id Syncpoint ID to be refreshed. | ||
| 55 | * @returns The new syncpoint minimum value. | ||
| 56 | */ | ||
| 57 | u32 RefreshSyncpoint(u32 syncpoint_id); | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Allocates a new syncoint. | ||
| 61 | * @returns The syncpoint ID for the newly allocated syncpoint. | ||
| 62 | */ | ||
| 63 | u32 AllocateSyncpoint(); | ||
| 64 | |||
| 65 | /** | ||
| 66 | * Increases the maximum value for the specified syncpoint. | ||
| 67 | * @param syncpoint_id Syncpoint ID to be increased. | ||
| 68 | * @param value Value to increase the specified syncpoint by. | ||
| 69 | * @returns The new syncpoint maximum value. | ||
| 70 | */ | ||
| 71 | u32 IncreaseSyncpoint(u32 syncpoint_id, u32 value); | ||
| 72 | |||
| 73 | private: | ||
| 74 | struct Syncpoint { | ||
| 75 | std::atomic<u32> min; | ||
| 76 | std::atomic<u32> max; | ||
| 77 | std::atomic<bool> is_allocated; | ||
| 78 | }; | ||
| 79 | |||
| 80 | std::array<Syncpoint, MaxSyncPoints> syncpoints{}; | ||
| 81 | |||
| 82 | Tegra::GPU& gpu; | ||
| 83 | }; | ||
| 84 | |||
| 85 | } // namespace Service::Nvidia | ||
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 4f1e210b1..b89a2d41b 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -29,6 +29,10 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) | |||
| 29 | .slot = slot, | 29 | .slot = slot, |
| 30 | .status = Buffer::Status::Free, | 30 | .status = Buffer::Status::Free, |
| 31 | .igbp_buffer = igbp_buffer, | 31 | .igbp_buffer = igbp_buffer, |
| 32 | .transform = {}, | ||
| 33 | .crop_rect = {}, | ||
| 34 | .swap_interval = 0, | ||
| 35 | .multi_fence = {}, | ||
| 32 | }); | 36 | }); |
| 33 | 37 | ||
| 34 | buffer_wait_event.writable->Signal(); | 38 | buffer_wait_event.writable->Signal(); |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index c64673dba..44aa2bdae 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -242,6 +242,10 @@ void NVFlinger::Compose() { | |||
| 242 | 242 | ||
| 243 | const auto& igbp_buffer = buffer->get().igbp_buffer; | 243 | const auto& igbp_buffer = buffer->get().igbp_buffer; |
| 244 | 244 | ||
| 245 | if (!system.IsPoweredOn()) { | ||
| 246 | return; // We are likely shutting down | ||
| 247 | } | ||
| 248 | |||
| 245 | auto& gpu = system.GPU(); | 249 | auto& gpu = system.GPU(); |
| 246 | const auto& multi_fence = buffer->get().multi_fence; | 250 | const auto& multi_fence = buffer->get().multi_fence; |
| 247 | guard->unlock(); | 251 | guard->unlock(); |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index e14c02045..a99d3cf5a 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | namespace Settings { | 14 | namespace Settings { |
| 15 | 15 | ||
| 16 | Values values = {}; | 16 | Values values = {}; |
| 17 | bool configuring_global = true; | 17 | static bool configuring_global = true; |
| 18 | 18 | ||
| 19 | std::string GetTimeZoneString() { | 19 | std::string GetTimeZoneString() { |
| 20 | static constexpr std::array timezones{ | 20 | static constexpr std::array timezones{ |
| @@ -81,11 +81,12 @@ void LogSettings() { | |||
| 81 | log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local); | 81 | log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | float Volume() { | 84 | bool IsConfiguringGlobal() { |
| 85 | if (values.audio_muted) { | 85 | return configuring_global; |
| 86 | return 0.0f; | 86 | } |
| 87 | } | 87 | |
| 88 | return values.volume.GetValue(); | 88 | void SetConfiguringGlobal(bool is_global) { |
| 89 | configuring_global = is_global; | ||
| 89 | } | 90 | } |
| 90 | 91 | ||
| 91 | bool IsGPULevelExtreme() { | 92 | bool IsGPULevelExtreme() { |
| @@ -97,6 +98,13 @@ bool IsGPULevelHigh() { | |||
| 97 | values.gpu_accuracy.GetValue() == GPUAccuracy::High; | 98 | values.gpu_accuracy.GetValue() == GPUAccuracy::High; |
| 98 | } | 99 | } |
| 99 | 100 | ||
| 101 | float Volume() { | ||
| 102 | if (values.audio_muted) { | ||
| 103 | return 0.0f; | ||
| 104 | } | ||
| 105 | return values.volume.GetValue(); | ||
| 106 | } | ||
| 107 | |||
| 100 | void RestoreGlobalState() { | 108 | void RestoreGlobalState() { |
| 101 | // If a game is running, DO NOT restore the global settings state | 109 | // If a game is running, DO NOT restore the global settings state |
| 102 | if (Core::System::GetInstance().IsPoweredOn()) { | 110 | if (Core::System::GetInstance().IsPoweredOn()) { |
diff --git a/src/core/settings.h b/src/core/settings.h index 604805615..28616a574 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -33,8 +33,6 @@ enum class CPUAccuracy { | |||
| 33 | DebugMode = 2, | 33 | DebugMode = 2, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | extern bool configuring_global; | ||
| 37 | |||
| 38 | template <typename Type> | 36 | template <typename Type> |
| 39 | class Setting final { | 37 | class Setting final { |
| 40 | public: | 38 | public: |
| @@ -103,7 +101,7 @@ struct Values { | |||
| 103 | bool renderer_debug; | 101 | bool renderer_debug; |
| 104 | Setting<int> vulkan_device; | 102 | Setting<int> vulkan_device; |
| 105 | 103 | ||
| 106 | Setting<u16> resolution_factor = Setting(static_cast<u16>(1)); | 104 | Setting<u16> resolution_factor{1}; |
| 107 | Setting<int> aspect_ratio; | 105 | Setting<int> aspect_ratio; |
| 108 | Setting<int> max_anisotropy; | 106 | Setting<int> max_anisotropy; |
| 109 | Setting<bool> use_frame_limit; | 107 | Setting<bool> use_frame_limit; |
| @@ -198,13 +196,18 @@ struct Values { | |||
| 198 | 196 | ||
| 199 | // Add-Ons | 197 | // Add-Ons |
| 200 | std::map<u64, std::vector<std::string>> disabled_addons; | 198 | std::map<u64, std::vector<std::string>> disabled_addons; |
| 201 | } extern values; | 199 | }; |
| 202 | 200 | ||
| 203 | float Volume(); | 201 | extern Values values; |
| 202 | |||
| 203 | bool IsConfiguringGlobal(); | ||
| 204 | void SetConfiguringGlobal(bool is_global); | ||
| 204 | 205 | ||
| 205 | bool IsGPULevelExtreme(); | 206 | bool IsGPULevelExtreme(); |
| 206 | bool IsGPULevelHigh(); | 207 | bool IsGPULevelHigh(); |
| 207 | 208 | ||
| 209 | float Volume(); | ||
| 210 | |||
| 208 | std::string GetTimeZoneString(); | 211 | std::string GetTimeZoneString(); |
| 209 | 212 | ||
| 210 | void Apply(); | 213 | void Apply(); |
diff --git a/src/video_core/command_classes/codecs/codec.h b/src/video_core/command_classes/codecs/codec.h index cb67094f6..5bbe6a332 100644 --- a/src/video_core/command_classes/codecs/codec.h +++ b/src/video_core/command_classes/codecs/codec.h | |||
| @@ -42,11 +42,11 @@ public: | |||
| 42 | void Decode(); | 42 | void Decode(); |
| 43 | 43 | ||
| 44 | /// Returns most recently decoded frame | 44 | /// Returns most recently decoded frame |
| 45 | AVFrame* GetCurrentFrame(); | 45 | [[nodiscard]] AVFrame* GetCurrentFrame(); |
| 46 | const AVFrame* GetCurrentFrame() const; | 46 | [[nodiscard]] const AVFrame* GetCurrentFrame() const; |
| 47 | 47 | ||
| 48 | /// Returns the value of current_codec | 48 | /// Returns the value of current_codec |
| 49 | NvdecCommon::VideoCodec GetCurrentCodec() const; | 49 | [[nodiscard]] NvdecCommon::VideoCodec GetCurrentCodec() const; |
| 50 | 50 | ||
| 51 | private: | 51 | private: |
| 52 | bool initialized{}; | 52 | bool initialized{}; |
diff --git a/src/video_core/command_classes/codecs/h264.cpp b/src/video_core/command_classes/codecs/h264.cpp index 549a40f52..33e063e20 100644 --- a/src/video_core/command_classes/codecs/h264.cpp +++ b/src/video_core/command_classes/codecs/h264.cpp | |||
| @@ -43,7 +43,8 @@ H264::H264(GPU& gpu_) : gpu(gpu_) {} | |||
| 43 | 43 | ||
| 44 | H264::~H264() = default; | 44 | H264::~H264() = default; |
| 45 | 45 | ||
| 46 | std::vector<u8>& H264::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, bool is_first_frame) { | 46 | const std::vector<u8>& H264::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, |
| 47 | bool is_first_frame) { | ||
| 47 | H264DecoderContext context{}; | 48 | H264DecoderContext context{}; |
| 48 | gpu.MemoryManager().ReadBlock(state.picture_info_offset, &context, sizeof(H264DecoderContext)); | 49 | gpu.MemoryManager().ReadBlock(state.picture_info_offset, &context, sizeof(H264DecoderContext)); |
| 49 | 50 | ||
diff --git a/src/video_core/command_classes/codecs/h264.h b/src/video_core/command_classes/codecs/h264.h index f2292fd2f..273449495 100644 --- a/src/video_core/command_classes/codecs/h264.h +++ b/src/video_core/command_classes/codecs/h264.h | |||
| @@ -51,14 +51,14 @@ public: | |||
| 51 | void WriteScalingList(const std::vector<u8>& list, s32 start, s32 count); | 51 | void WriteScalingList(const std::vector<u8>& list, s32 start, s32 count); |
| 52 | 52 | ||
| 53 | /// Return the bitstream as a vector. | 53 | /// Return the bitstream as a vector. |
| 54 | std::vector<u8>& GetByteArray(); | 54 | [[nodiscard]] std::vector<u8>& GetByteArray(); |
| 55 | const std::vector<u8>& GetByteArray() const; | 55 | [[nodiscard]] const std::vector<u8>& GetByteArray() const; |
| 56 | 56 | ||
| 57 | private: | 57 | private: |
| 58 | void WriteBits(s32 value, s32 bit_count); | 58 | void WriteBits(s32 value, s32 bit_count); |
| 59 | void WriteExpGolombCodedInt(s32 value); | 59 | void WriteExpGolombCodedInt(s32 value); |
| 60 | void WriteExpGolombCodedUInt(u32 value); | 60 | void WriteExpGolombCodedUInt(u32 value); |
| 61 | s32 GetFreeBufferBits(); | 61 | [[nodiscard]] s32 GetFreeBufferBits(); |
| 62 | void Flush(); | 62 | void Flush(); |
| 63 | 63 | ||
| 64 | s32 buffer_size{8}; | 64 | s32 buffer_size{8}; |
| @@ -74,8 +74,8 @@ public: | |||
| 74 | ~H264(); | 74 | ~H264(); |
| 75 | 75 | ||
| 76 | /// Compose the H264 header of the frame for FFmpeg decoding | 76 | /// Compose the H264 header of the frame for FFmpeg decoding |
| 77 | std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, | 77 | [[nodiscard]] const std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, |
| 78 | bool is_first_frame = false); | 78 | bool is_first_frame = false); |
| 79 | 79 | ||
| 80 | private: | 80 | private: |
| 81 | struct H264ParameterSet { | 81 | struct H264ParameterSet { |
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp index 42520f856..ab44fdc9e 100644 --- a/src/video_core/command_classes/codecs/vp9.cpp +++ b/src/video_core/command_classes/codecs/vp9.cpp | |||
| @@ -854,7 +854,7 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() { | |||
| 854 | return uncomp_writer; | 854 | return uncomp_writer; |
| 855 | } | 855 | } |
| 856 | 856 | ||
| 857 | std::vector<u8>& VP9::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state) { | 857 | const std::vector<u8>& VP9::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state) { |
| 858 | std::vector<u8> bitstream; | 858 | std::vector<u8> bitstream; |
| 859 | { | 859 | { |
| 860 | Vp9FrameContainer curr_frame = GetCurrentFrame(state); | 860 | Vp9FrameContainer curr_frame = GetCurrentFrame(state); |
diff --git a/src/video_core/command_classes/codecs/vp9.h b/src/video_core/command_classes/codecs/vp9.h index 05c9682fa..e2504512c 100644 --- a/src/video_core/command_classes/codecs/vp9.h +++ b/src/video_core/command_classes/codecs/vp9.h | |||
| @@ -119,7 +119,7 @@ public: | |||
| 119 | 119 | ||
| 120 | /// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec | 120 | /// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec |
| 121 | /// documentation | 121 | /// documentation |
| 122 | std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state); | 122 | [[nodiscard]] const std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state); |
| 123 | 123 | ||
| 124 | /// Returns true if the most recent frame was a hidden frame. | 124 | /// Returns true if the most recent frame was a hidden frame. |
| 125 | [[nodiscard]] bool WasFrameHidden() const { | 125 | [[nodiscard]] bool WasFrameHidden() const { |
diff --git a/src/video_core/command_classes/codecs/vp9_types.h b/src/video_core/command_classes/codecs/vp9_types.h index a50acf6e8..4f0b05d22 100644 --- a/src/video_core/command_classes/codecs/vp9_types.h +++ b/src/video_core/command_classes/codecs/vp9_types.h | |||
| @@ -231,9 +231,8 @@ struct PictureInfo { | |||
| 231 | u32 surface_params{}; | 231 | u32 surface_params{}; |
| 232 | INSERT_PADDING_WORDS(3); | 232 | INSERT_PADDING_WORDS(3); |
| 233 | 233 | ||
| 234 | Vp9PictureInfo Convert() const { | 234 | [[nodiscard]] Vp9PictureInfo Convert() const { |
| 235 | 235 | return { | |
| 236 | return Vp9PictureInfo{ | ||
| 237 | .is_key_frame = (vp9_flags & FrameFlags::IsKeyFrame) != 0, | 236 | .is_key_frame = (vp9_flags & FrameFlags::IsKeyFrame) != 0, |
| 238 | .intra_only = (vp9_flags & FrameFlags::IntraOnly) != 0, | 237 | .intra_only = (vp9_flags & FrameFlags::IntraOnly) != 0, |
| 239 | .last_frame_was_key = (vp9_flags & FrameFlags::LastFrameIsKeyFrame) != 0, | 238 | .last_frame_was_key = (vp9_flags & FrameFlags::LastFrameIsKeyFrame) != 0, |
diff --git a/src/video_core/command_classes/nvdec.h b/src/video_core/command_classes/nvdec.h index af14f9857..eec4443f9 100644 --- a/src/video_core/command_classes/nvdec.h +++ b/src/video_core/command_classes/nvdec.h | |||
| @@ -26,8 +26,8 @@ public: | |||
| 26 | void ProcessMethod(Method method, const std::vector<u32>& arguments); | 26 | void ProcessMethod(Method method, const std::vector<u32>& arguments); |
| 27 | 27 | ||
| 28 | /// Return most recently decoded frame | 28 | /// Return most recently decoded frame |
| 29 | AVFrame* GetFrame(); | 29 | [[nodiscard]] AVFrame* GetFrame(); |
| 30 | const AVFrame* GetFrame() const; | 30 | [[nodiscard]] const AVFrame* GetFrame() const; |
| 31 | 31 | ||
| 32 | private: | 32 | private: |
| 33 | /// Invoke codec to decode a frame | 33 | /// Invoke codec to decode a frame |
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp index f2f96ac33..105b85a92 100644 --- a/src/video_core/dma_pusher.cpp +++ b/src/video_core/dma_pusher.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/cityhash.h" | ||
| 5 | #include "common/microprofile.h" | 6 | #include "common/microprofile.h" |
| 6 | #include "core/core.h" | 7 | #include "core/core.h" |
| 7 | #include "core/memory.h" | 8 | #include "core/memory.h" |
| @@ -12,6 +13,20 @@ | |||
| 12 | 13 | ||
| 13 | namespace Tegra { | 14 | namespace Tegra { |
| 14 | 15 | ||
| 16 | void CommandList::RefreshIntegrityChecks(GPU& gpu) { | ||
| 17 | command_list_hashes.resize(command_lists.size()); | ||
| 18 | |||
| 19 | for (std::size_t index = 0; index < command_lists.size(); ++index) { | ||
| 20 | const CommandListHeader command_list_header = command_lists[index]; | ||
| 21 | std::vector<CommandHeader> command_headers(command_list_header.size); | ||
| 22 | gpu.MemoryManager().ReadBlockUnsafe(command_list_header.addr, command_headers.data(), | ||
| 23 | command_list_header.size * sizeof(u32)); | ||
| 24 | command_list_hashes[index] = | ||
| 25 | Common::CityHash64(reinterpret_cast<char*>(command_headers.data()), | ||
| 26 | command_list_header.size * sizeof(u32)); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 15 | DmaPusher::DmaPusher(Core::System& system, GPU& gpu) : gpu{gpu}, system{system} {} | 30 | DmaPusher::DmaPusher(Core::System& system, GPU& gpu) : gpu{gpu}, system{system} {} |
| 16 | 31 | ||
| 17 | DmaPusher::~DmaPusher() = default; | 32 | DmaPusher::~DmaPusher() = default; |
| @@ -45,32 +60,51 @@ bool DmaPusher::Step() { | |||
| 45 | return false; | 60 | return false; |
| 46 | } | 61 | } |
| 47 | 62 | ||
| 48 | const CommandList& command_list{dma_pushbuffer.front()}; | 63 | CommandList& command_list{dma_pushbuffer.front()}; |
| 49 | ASSERT_OR_EXECUTE(!command_list.empty(), { | ||
| 50 | // Somehow the command_list is empty, in order to avoid a crash | ||
| 51 | // We ignore it and assume its size is 0. | ||
| 52 | dma_pushbuffer.pop(); | ||
| 53 | dma_pushbuffer_subindex = 0; | ||
| 54 | return true; | ||
| 55 | }); | ||
| 56 | const CommandListHeader command_list_header{command_list[dma_pushbuffer_subindex++]}; | ||
| 57 | const GPUVAddr dma_get = command_list_header.addr; | ||
| 58 | |||
| 59 | if (dma_pushbuffer_subindex >= command_list.size()) { | ||
| 60 | // We've gone through the current list, remove it from the queue | ||
| 61 | dma_pushbuffer.pop(); | ||
| 62 | dma_pushbuffer_subindex = 0; | ||
| 63 | } | ||
| 64 | 64 | ||
| 65 | if (command_list_header.size == 0) { | 65 | ASSERT_OR_EXECUTE( |
| 66 | return true; | 66 | command_list.command_lists.size() || command_list.prefetch_command_list.size(), { |
| 67 | } | 67 | // Somehow the command_list is empty, in order to avoid a crash |
| 68 | // We ignore it and assume its size is 0. | ||
| 69 | dma_pushbuffer.pop(); | ||
| 70 | dma_pushbuffer_subindex = 0; | ||
| 71 | return true; | ||
| 72 | }); | ||
| 68 | 73 | ||
| 69 | // Push buffer non-empty, read a word | 74 | if (command_list.prefetch_command_list.size()) { |
| 70 | command_headers.resize(command_list_header.size); | 75 | // Prefetched command list from nvdrv, used for things like synchronization |
| 71 | gpu.MemoryManager().ReadBlockUnsafe(dma_get, command_headers.data(), | 76 | command_headers = std::move(command_list.prefetch_command_list); |
| 72 | command_list_header.size * sizeof(u32)); | 77 | dma_pushbuffer.pop(); |
| 78 | } else { | ||
| 79 | const CommandListHeader command_list_header{ | ||
| 80 | command_list.command_lists[dma_pushbuffer_subindex]}; | ||
| 81 | const u64 next_hash = command_list.command_list_hashes[dma_pushbuffer_subindex++]; | ||
| 82 | const GPUVAddr dma_get = command_list_header.addr; | ||
| 83 | |||
| 84 | if (dma_pushbuffer_subindex >= command_list.command_lists.size()) { | ||
| 85 | // We've gone through the current list, remove it from the queue | ||
| 86 | dma_pushbuffer.pop(); | ||
| 87 | dma_pushbuffer_subindex = 0; | ||
| 88 | } | ||
| 73 | 89 | ||
| 90 | if (command_list_header.size == 0) { | ||
| 91 | return true; | ||
| 92 | } | ||
| 93 | |||
| 94 | // Push buffer non-empty, read a word | ||
| 95 | command_headers.resize(command_list_header.size); | ||
| 96 | gpu.MemoryManager().ReadBlockUnsafe(dma_get, command_headers.data(), | ||
| 97 | command_list_header.size * sizeof(u32)); | ||
| 98 | |||
| 99 | // Integrity check | ||
| 100 | const u64 new_hash = Common::CityHash64(reinterpret_cast<char*>(command_headers.data()), | ||
| 101 | command_list_header.size * sizeof(u32)); | ||
| 102 | if (new_hash != next_hash) { | ||
| 103 | LOG_CRITICAL(HW_GPU, "CommandList at addr=0x{:X} is corrupt, skipping!", dma_get); | ||
| 104 | dma_pushbuffer.pop(); | ||
| 105 | return true; | ||
| 106 | } | ||
| 107 | } | ||
| 74 | for (std::size_t index = 0; index < command_headers.size();) { | 108 | for (std::size_t index = 0; index < command_headers.size();) { |
| 75 | const CommandHeader& command_header = command_headers[index]; | 109 | const CommandHeader& command_header = command_headers[index]; |
| 76 | 110 | ||
diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h index efa90d170..9d9a750d9 100644 --- a/src/video_core/dma_pusher.h +++ b/src/video_core/dma_pusher.h | |||
| @@ -18,6 +18,8 @@ class System; | |||
| 18 | 18 | ||
| 19 | namespace Tegra { | 19 | namespace Tegra { |
| 20 | 20 | ||
| 21 | class GPU; | ||
| 22 | |||
| 21 | enum class SubmissionMode : u32 { | 23 | enum class SubmissionMode : u32 { |
| 22 | IncreasingOld = 0, | 24 | IncreasingOld = 0, |
| 23 | Increasing = 1, | 25 | Increasing = 1, |
| @@ -27,6 +29,31 @@ enum class SubmissionMode : u32 { | |||
| 27 | IncreaseOnce = 5 | 29 | IncreaseOnce = 5 |
| 28 | }; | 30 | }; |
| 29 | 31 | ||
| 32 | // Note that, traditionally, methods are treated as 4-byte addressable locations, and hence | ||
| 33 | // their numbers are written down multiplied by 4 in Docs. Here we are not multiply by 4. | ||
| 34 | // So the values you see in docs might be multiplied by 4. | ||
| 35 | enum class BufferMethods : u32 { | ||
| 36 | BindObject = 0x0, | ||
| 37 | Nop = 0x2, | ||
| 38 | SemaphoreAddressHigh = 0x4, | ||
| 39 | SemaphoreAddressLow = 0x5, | ||
| 40 | SemaphoreSequence = 0x6, | ||
| 41 | SemaphoreTrigger = 0x7, | ||
| 42 | NotifyIntr = 0x8, | ||
| 43 | WrcacheFlush = 0x9, | ||
| 44 | Unk28 = 0xA, | ||
| 45 | UnkCacheFlush = 0xB, | ||
| 46 | RefCnt = 0x14, | ||
| 47 | SemaphoreAcquire = 0x1A, | ||
| 48 | SemaphoreRelease = 0x1B, | ||
| 49 | FenceValue = 0x1C, | ||
| 50 | FenceAction = 0x1D, | ||
| 51 | WaitForInterrupt = 0x1E, | ||
| 52 | Unk7c = 0x1F, | ||
| 53 | Yield = 0x20, | ||
| 54 | NonPullerMethods = 0x40, | ||
| 55 | }; | ||
| 56 | |||
| 30 | struct CommandListHeader { | 57 | struct CommandListHeader { |
| 31 | union { | 58 | union { |
| 32 | u64 raw; | 59 | u64 raw; |
| @@ -49,9 +76,26 @@ union CommandHeader { | |||
| 49 | static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout"); | 76 | static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout"); |
| 50 | static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!"); | 77 | static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!"); |
| 51 | 78 | ||
| 52 | class GPU; | 79 | inline CommandHeader BuildCommandHeader(BufferMethods method, u32 arg_count, SubmissionMode mode) { |
| 80 | CommandHeader result{}; | ||
| 81 | result.method.Assign(static_cast<u32>(method)); | ||
| 82 | result.arg_count.Assign(arg_count); | ||
| 83 | result.mode.Assign(mode); | ||
| 84 | return result; | ||
| 85 | } | ||
| 86 | |||
| 87 | struct CommandList final { | ||
| 88 | CommandList() = default; | ||
| 89 | explicit CommandList(std::size_t size) : command_lists(size) {} | ||
| 90 | explicit CommandList(std::vector<Tegra::CommandHeader>&& prefetch_command_list) | ||
| 91 | : prefetch_command_list{std::move(prefetch_command_list)} {} | ||
| 53 | 92 | ||
| 54 | using CommandList = std::vector<Tegra::CommandListHeader>; | 93 | void RefreshIntegrityChecks(GPU& gpu); |
| 94 | |||
| 95 | std::vector<Tegra::CommandListHeader> command_lists; | ||
| 96 | std::vector<u64> command_list_hashes; | ||
| 97 | std::vector<Tegra::CommandHeader> prefetch_command_list; | ||
| 98 | }; | ||
| 55 | 99 | ||
| 56 | /** | 100 | /** |
| 57 | * The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the | 101 | * The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the |
| @@ -60,7 +104,7 @@ using CommandList = std::vector<Tegra::CommandListHeader>; | |||
| 60 | * See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for | 104 | * See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for |
| 61 | * details on this implementation. | 105 | * details on this implementation. |
| 62 | */ | 106 | */ |
| 63 | class DmaPusher { | 107 | class DmaPusher final { |
| 64 | public: | 108 | public: |
| 65 | explicit DmaPusher(Core::System& system, GPU& gpu); | 109 | explicit DmaPusher(Core::System& system, GPU& gpu); |
| 66 | ~DmaPusher(); | 110 | ~DmaPusher(); |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 171f78183..ebd149c3a 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -194,30 +194,6 @@ void GPU::SyncGuestHost() { | |||
| 194 | void GPU::OnCommandListEnd() { | 194 | void GPU::OnCommandListEnd() { |
| 195 | renderer->Rasterizer().ReleaseFences(); | 195 | renderer->Rasterizer().ReleaseFences(); |
| 196 | } | 196 | } |
| 197 | // Note that, traditionally, methods are treated as 4-byte addressable locations, and hence | ||
| 198 | // their numbers are written down multiplied by 4 in Docs. Here we are not multiply by 4. | ||
| 199 | // So the values you see in docs might be multiplied by 4. | ||
| 200 | enum class BufferMethods { | ||
| 201 | BindObject = 0x0, | ||
| 202 | Nop = 0x2, | ||
| 203 | SemaphoreAddressHigh = 0x4, | ||
| 204 | SemaphoreAddressLow = 0x5, | ||
| 205 | SemaphoreSequence = 0x6, | ||
| 206 | SemaphoreTrigger = 0x7, | ||
| 207 | NotifyIntr = 0x8, | ||
| 208 | WrcacheFlush = 0x9, | ||
| 209 | Unk28 = 0xA, | ||
| 210 | UnkCacheFlush = 0xB, | ||
| 211 | RefCnt = 0x14, | ||
| 212 | SemaphoreAcquire = 0x1A, | ||
| 213 | SemaphoreRelease = 0x1B, | ||
| 214 | FenceValue = 0x1C, | ||
| 215 | FenceAction = 0x1D, | ||
| 216 | Unk78 = 0x1E, | ||
| 217 | Unk7c = 0x1F, | ||
| 218 | Yield = 0x20, | ||
| 219 | NonPullerMethods = 0x40, | ||
| 220 | }; | ||
| 221 | 197 | ||
| 222 | enum class GpuSemaphoreOperation { | 198 | enum class GpuSemaphoreOperation { |
| 223 | AcquireEqual = 0x1, | 199 | AcquireEqual = 0x1, |
| @@ -277,7 +253,12 @@ void GPU::CallPullerMethod(const MethodCall& method_call) { | |||
| 277 | case BufferMethods::UnkCacheFlush: | 253 | case BufferMethods::UnkCacheFlush: |
| 278 | case BufferMethods::WrcacheFlush: | 254 | case BufferMethods::WrcacheFlush: |
| 279 | case BufferMethods::FenceValue: | 255 | case BufferMethods::FenceValue: |
| 256 | break; | ||
| 280 | case BufferMethods::FenceAction: | 257 | case BufferMethods::FenceAction: |
| 258 | ProcessFenceActionMethod(); | ||
| 259 | break; | ||
| 260 | case BufferMethods::WaitForInterrupt: | ||
| 261 | ProcessWaitForInterruptMethod(); | ||
| 281 | break; | 262 | break; |
| 282 | case BufferMethods::SemaphoreTrigger: { | 263 | case BufferMethods::SemaphoreTrigger: { |
| 283 | ProcessSemaphoreTriggerMethod(); | 264 | ProcessSemaphoreTriggerMethod(); |
| @@ -391,6 +372,25 @@ void GPU::ProcessBindMethod(const MethodCall& method_call) { | |||
| 391 | } | 372 | } |
| 392 | } | 373 | } |
| 393 | 374 | ||
| 375 | void GPU::ProcessFenceActionMethod() { | ||
| 376 | switch (regs.fence_action.op) { | ||
| 377 | case FenceOperation::Acquire: | ||
| 378 | WaitFence(regs.fence_action.syncpoint_id, regs.fence_value); | ||
| 379 | break; | ||
| 380 | case FenceOperation::Increment: | ||
| 381 | IncrementSyncPoint(regs.fence_action.syncpoint_id); | ||
| 382 | break; | ||
| 383 | default: | ||
| 384 | UNIMPLEMENTED_MSG("Unimplemented operation {}", | ||
| 385 | static_cast<u32>(regs.fence_action.op.Value())); | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | void GPU::ProcessWaitForInterruptMethod() { | ||
| 390 | // TODO(bunnei) ImplementMe | ||
| 391 | LOG_WARNING(HW_GPU, "(STUBBED) called"); | ||
| 392 | } | ||
| 393 | |||
| 394 | void GPU::ProcessSemaphoreTriggerMethod() { | 394 | void GPU::ProcessSemaphoreTriggerMethod() { |
| 395 | const auto semaphoreOperationMask = 0xF; | 395 | const auto semaphoreOperationMask = 0xF; |
| 396 | const auto op = | 396 | const auto op = |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index b8c613b11..cf5235a79 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -263,6 +263,24 @@ public: | |||
| 263 | return use_nvdec; | 263 | return use_nvdec; |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | enum class FenceOperation : u32 { | ||
| 267 | Acquire = 0, | ||
| 268 | Increment = 1, | ||
| 269 | }; | ||
| 270 | |||
| 271 | union FenceAction { | ||
| 272 | u32 raw; | ||
| 273 | BitField<0, 1, FenceOperation> op; | ||
| 274 | BitField<8, 24, u32> syncpoint_id; | ||
| 275 | |||
| 276 | static CommandHeader Build(FenceOperation op, u32 syncpoint_id) { | ||
| 277 | FenceAction result{}; | ||
| 278 | result.op.Assign(op); | ||
| 279 | result.syncpoint_id.Assign(syncpoint_id); | ||
| 280 | return {result.raw}; | ||
| 281 | } | ||
| 282 | }; | ||
| 283 | |||
| 266 | struct Regs { | 284 | struct Regs { |
| 267 | static constexpr size_t NUM_REGS = 0x40; | 285 | static constexpr size_t NUM_REGS = 0x40; |
| 268 | 286 | ||
| @@ -291,10 +309,7 @@ public: | |||
| 291 | u32 semaphore_acquire; | 309 | u32 semaphore_acquire; |
| 292 | u32 semaphore_release; | 310 | u32 semaphore_release; |
| 293 | u32 fence_value; | 311 | u32 fence_value; |
| 294 | union { | 312 | FenceAction fence_action; |
| 295 | BitField<4, 4, u32> operation; | ||
| 296 | BitField<8, 8, u32> id; | ||
| 297 | } fence_action; | ||
| 298 | INSERT_UNION_PADDING_WORDS(0xE2); | 313 | INSERT_UNION_PADDING_WORDS(0xE2); |
| 299 | 314 | ||
| 300 | // Puller state | 315 | // Puller state |
| @@ -342,6 +357,8 @@ protected: | |||
| 342 | 357 | ||
| 343 | private: | 358 | private: |
| 344 | void ProcessBindMethod(const MethodCall& method_call); | 359 | void ProcessBindMethod(const MethodCall& method_call); |
| 360 | void ProcessFenceActionMethod(); | ||
| 361 | void ProcessWaitForInterruptMethod(); | ||
| 345 | void ProcessSemaphoreTriggerMethod(); | 362 | void ProcessSemaphoreTriggerMethod(); |
| 346 | void ProcessSemaphoreRelease(); | 363 | void ProcessSemaphoreRelease(); |
| 347 | void ProcessSemaphoreAcquire(); | 364 | void ProcessSemaphoreAcquire(); |
diff --git a/src/video_core/renderer_opengl/gl_arb_decompiler.cpp b/src/video_core/renderer_opengl/gl_arb_decompiler.cpp index f4db62787..d6120c23e 100644 --- a/src/video_core/renderer_opengl/gl_arb_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_arb_decompiler.cpp | |||
| @@ -39,8 +39,8 @@ using Operation = const OperationNode&; | |||
| 39 | constexpr std::array INTERNAL_FLAG_NAMES = {"ZERO", "SIGN", "CARRY", "OVERFLOW"}; | 39 | constexpr std::array INTERNAL_FLAG_NAMES = {"ZERO", "SIGN", "CARRY", "OVERFLOW"}; |
| 40 | 40 | ||
| 41 | char Swizzle(std::size_t component) { | 41 | char Swizzle(std::size_t component) { |
| 42 | ASSERT(component < 4); | 42 | static constexpr std::string_view SWIZZLE{"xyzw"}; |
| 43 | return component["xyzw"]; | 43 | return SWIZZLE.at(component); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | constexpr bool IsGenericAttribute(Attribute::Index index) { | 46 | constexpr bool IsGenericAttribute(Attribute::Index index) { |
| @@ -224,7 +224,7 @@ private: | |||
| 224 | 224 | ||
| 225 | std::string Visit(const Node& node); | 225 | std::string Visit(const Node& node); |
| 226 | 226 | ||
| 227 | std::pair<std::string, std::size_t> BuildCoords(Operation); | 227 | std::tuple<std::string, std::string, std::size_t> BuildCoords(Operation); |
| 228 | std::string BuildAoffi(Operation); | 228 | std::string BuildAoffi(Operation); |
| 229 | std::string GlobalMemoryPointer(const GmemNode& gmem); | 229 | std::string GlobalMemoryPointer(const GmemNode& gmem); |
| 230 | void Exit(); | 230 | void Exit(); |
| @@ -1416,12 +1416,12 @@ std::string ARBDecompiler::Visit(const Node& node) { | |||
| 1416 | return {}; | 1416 | return {}; |
| 1417 | } | 1417 | } |
| 1418 | 1418 | ||
| 1419 | std::pair<std::string, std::size_t> ARBDecompiler::BuildCoords(Operation operation) { | 1419 | std::tuple<std::string, std::string, std::size_t> ARBDecompiler::BuildCoords(Operation operation) { |
| 1420 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); | 1420 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); |
| 1421 | UNIMPLEMENTED_IF(meta.sampler.is_indexed); | 1421 | UNIMPLEMENTED_IF(meta.sampler.is_indexed); |
| 1422 | UNIMPLEMENTED_IF(meta.sampler.is_shadow && meta.sampler.is_array && | ||
| 1423 | meta.sampler.type == Tegra::Shader::TextureType::TextureCube); | ||
| 1424 | 1422 | ||
| 1423 | const bool is_extended = meta.sampler.is_shadow && meta.sampler.is_array && | ||
| 1424 | meta.sampler.type == Tegra::Shader::TextureType::TextureCube; | ||
| 1425 | const std::size_t count = operation.GetOperandsCount(); | 1425 | const std::size_t count = operation.GetOperandsCount(); |
| 1426 | std::string temporary = AllocVectorTemporary(); | 1426 | std::string temporary = AllocVectorTemporary(); |
| 1427 | std::size_t i = 0; | 1427 | std::size_t i = 0; |
| @@ -1429,12 +1429,21 @@ std::pair<std::string, std::size_t> ARBDecompiler::BuildCoords(Operation operati | |||
| 1429 | AddLine("MOV.F {}.{}, {};", temporary, Swizzle(i), Visit(operation[i])); | 1429 | AddLine("MOV.F {}.{}, {};", temporary, Swizzle(i), Visit(operation[i])); |
| 1430 | } | 1430 | } |
| 1431 | if (meta.sampler.is_array) { | 1431 | if (meta.sampler.is_array) { |
| 1432 | AddLine("I2F.S {}.{}, {};", temporary, Swizzle(i++), Visit(meta.array)); | 1432 | AddLine("I2F.S {}.{}, {};", temporary, Swizzle(i), Visit(meta.array)); |
| 1433 | ++i; | ||
| 1433 | } | 1434 | } |
| 1434 | if (meta.sampler.is_shadow) { | 1435 | if (meta.sampler.is_shadow) { |
| 1435 | AddLine("MOV.F {}.{}, {};", temporary, Swizzle(i++), Visit(meta.depth_compare)); | 1436 | std::string compare = Visit(meta.depth_compare); |
| 1437 | if (is_extended) { | ||
| 1438 | ASSERT(i == 4); | ||
| 1439 | std::string extra_coord = AllocVectorTemporary(); | ||
| 1440 | AddLine("MOV.F {}.x, {};", extra_coord, compare); | ||
| 1441 | return {fmt::format("{}, {}", temporary, extra_coord), extra_coord, 0}; | ||
| 1442 | } | ||
| 1443 | AddLine("MOV.F {}.{}, {};", temporary, Swizzle(i), compare); | ||
| 1444 | ++i; | ||
| 1436 | } | 1445 | } |
| 1437 | return {std::move(temporary), i}; | 1446 | return {temporary, temporary, i}; |
| 1438 | } | 1447 | } |
| 1439 | 1448 | ||
| 1440 | std::string ARBDecompiler::BuildAoffi(Operation operation) { | 1449 | std::string ARBDecompiler::BuildAoffi(Operation operation) { |
| @@ -1859,7 +1868,7 @@ std::string ARBDecompiler::LogicalAddCarry(Operation operation) { | |||
| 1859 | std::string ARBDecompiler::Texture(Operation operation) { | 1868 | std::string ARBDecompiler::Texture(Operation operation) { |
| 1860 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); | 1869 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); |
| 1861 | const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; | 1870 | const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; |
| 1862 | const auto [temporary, swizzle] = BuildCoords(operation); | 1871 | const auto [coords, temporary, swizzle] = BuildCoords(operation); |
| 1863 | 1872 | ||
| 1864 | std::string_view opcode = "TEX"; | 1873 | std::string_view opcode = "TEX"; |
| 1865 | std::string extra; | 1874 | std::string extra; |
| @@ -1888,7 +1897,7 @@ std::string ARBDecompiler::Texture(Operation operation) { | |||
| 1888 | } | 1897 | } |
| 1889 | } | 1898 | } |
| 1890 | 1899 | ||
| 1891 | AddLine("{}.F {}, {},{} texture[{}], {}{};", opcode, temporary, temporary, extra, sampler_id, | 1900 | AddLine("{}.F {}, {},{} texture[{}], {}{};", opcode, temporary, coords, extra, sampler_id, |
| 1892 | TextureType(meta), BuildAoffi(operation)); | 1901 | TextureType(meta), BuildAoffi(operation)); |
| 1893 | AddLine("MOV.U {}.x, {}.{};", temporary, temporary, Swizzle(meta.element)); | 1902 | AddLine("MOV.U {}.x, {}.{};", temporary, temporary, Swizzle(meta.element)); |
| 1894 | return fmt::format("{}.x", temporary); | 1903 | return fmt::format("{}.x", temporary); |
| @@ -1897,7 +1906,7 @@ std::string ARBDecompiler::Texture(Operation operation) { | |||
| 1897 | std::string ARBDecompiler::TextureGather(Operation operation) { | 1906 | std::string ARBDecompiler::TextureGather(Operation operation) { |
| 1898 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); | 1907 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); |
| 1899 | const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; | 1908 | const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; |
| 1900 | const auto [temporary, swizzle] = BuildCoords(operation); | 1909 | const auto [coords, temporary, swizzle] = BuildCoords(operation); |
| 1901 | 1910 | ||
| 1902 | std::string comp; | 1911 | std::string comp; |
| 1903 | if (!meta.sampler.is_shadow) { | 1912 | if (!meta.sampler.is_shadow) { |
| @@ -1907,7 +1916,7 @@ std::string ARBDecompiler::TextureGather(Operation operation) { | |||
| 1907 | 1916 | ||
| 1908 | AddLine("TXG.F {}, {}, texture[{}]{}, {}{};", temporary, temporary, sampler_id, comp, | 1917 | AddLine("TXG.F {}, {}, texture[{}]{}, {}{};", temporary, temporary, sampler_id, comp, |
| 1909 | TextureType(meta), BuildAoffi(operation)); | 1918 | TextureType(meta), BuildAoffi(operation)); |
| 1910 | AddLine("MOV.U {}.x, {}.{};", temporary, temporary, Swizzle(meta.element)); | 1919 | AddLine("MOV.U {}.x, {}.{};", temporary, coords, Swizzle(meta.element)); |
| 1911 | return fmt::format("{}.x", temporary); | 1920 | return fmt::format("{}.x", temporary); |
| 1912 | } | 1921 | } |
| 1913 | 1922 | ||
| @@ -1945,13 +1954,13 @@ std::string ARBDecompiler::TextureQueryLod(Operation operation) { | |||
| 1945 | std::string ARBDecompiler::TexelFetch(Operation operation) { | 1954 | std::string ARBDecompiler::TexelFetch(Operation operation) { |
| 1946 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); | 1955 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); |
| 1947 | const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; | 1956 | const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; |
| 1948 | const auto [temporary, swizzle] = BuildCoords(operation); | 1957 | const auto [coords, temporary, swizzle] = BuildCoords(operation); |
| 1949 | 1958 | ||
| 1950 | if (!meta.sampler.is_buffer) { | 1959 | if (!meta.sampler.is_buffer) { |
| 1951 | ASSERT(swizzle < 4); | 1960 | ASSERT(swizzle < 4); |
| 1952 | AddLine("MOV.F {}.w, {};", temporary, Visit(meta.lod)); | 1961 | AddLine("MOV.F {}.w, {};", temporary, Visit(meta.lod)); |
| 1953 | } | 1962 | } |
| 1954 | AddLine("TXF.F {}, {}, texture[{}], {}{};", temporary, temporary, sampler_id, TextureType(meta), | 1963 | AddLine("TXF.F {}, {}, texture[{}], {}{};", temporary, coords, sampler_id, TextureType(meta), |
| 1955 | BuildAoffi(operation)); | 1964 | BuildAoffi(operation)); |
| 1956 | AddLine("MOV.U {}.x, {}.{};", temporary, temporary, Swizzle(meta.element)); | 1965 | AddLine("MOV.U {}.x, {}.{};", temporary, temporary, Swizzle(meta.element)); |
| 1957 | return fmt::format("{}.x", temporary); | 1966 | return fmt::format("{}.x", temporary); |
| @@ -1962,7 +1971,7 @@ std::string ARBDecompiler::TextureGradient(Operation operation) { | |||
| 1962 | const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; | 1971 | const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; |
| 1963 | const std::string ddx = AllocVectorTemporary(); | 1972 | const std::string ddx = AllocVectorTemporary(); |
| 1964 | const std::string ddy = AllocVectorTemporary(); | 1973 | const std::string ddy = AllocVectorTemporary(); |
| 1965 | const std::string coord = BuildCoords(operation).first; | 1974 | const std::string coord = std::get<1>(BuildCoords(operation)); |
| 1966 | 1975 | ||
| 1967 | const std::size_t num_components = meta.derivates.size() / 2; | 1976 | const std::size_t num_components = meta.derivates.size() / 2; |
| 1968 | for (std::size_t index = 0; index < num_components; ++index) { | 1977 | for (std::size_t index = 0; index < num_components; ++index) { |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index bbb8fb095..95ca96c8e 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -2056,15 +2056,19 @@ private: | |||
| 2056 | } | 2056 | } |
| 2057 | 2057 | ||
| 2058 | Expression Texture(Operation operation) { | 2058 | Expression Texture(Operation operation) { |
| 2059 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 2059 | const auto meta = std::get<MetaTexture>(operation.GetMeta()); |
| 2060 | ASSERT(meta); | 2060 | const bool separate_dc = meta.sampler.type == TextureType::TextureCube && |
| 2061 | 2061 | meta.sampler.is_array && meta.sampler.is_shadow; | |
| 2062 | std::string expr = GenerateTexture( | 2062 | // TODO: Replace this with an array and make GenerateTexture use C++20 std::span |
| 2063 | operation, "", {TextureOffset{}, TextureArgument{Type::Float, meta->bias}}); | 2063 | const std::vector<TextureIR> extras{ |
| 2064 | if (meta->sampler.is_shadow) { | 2064 | TextureOffset{}, |
| 2065 | expr = "vec4(" + expr + ')'; | 2065 | TextureArgument{Type::Float, meta.bias}, |
| 2066 | }; | ||
| 2067 | std::string expr = GenerateTexture(operation, "", extras, separate_dc); | ||
| 2068 | if (meta.sampler.is_shadow) { | ||
| 2069 | expr = fmt::format("vec4({})", expr); | ||
| 2066 | } | 2070 | } |
| 2067 | return {expr + GetSwizzle(meta->element), Type::Float}; | 2071 | return {expr + GetSwizzle(meta.element), Type::Float}; |
| 2068 | } | 2072 | } |
| 2069 | 2073 | ||
| 2070 | Expression TextureLod(Operation operation) { | 2074 | Expression TextureLod(Operation operation) { |
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index e1217ca83..f34ed6735 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp | |||
| @@ -771,13 +771,18 @@ void VKDevice::CollectTelemetryParameters() { | |||
| 771 | VkPhysicalDeviceDriverPropertiesKHR driver{ | 771 | VkPhysicalDeviceDriverPropertiesKHR driver{ |
| 772 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR, | 772 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR, |
| 773 | .pNext = nullptr, | 773 | .pNext = nullptr, |
| 774 | .driverID = {}, | ||
| 775 | .driverName = {}, | ||
| 776 | .driverInfo = {}, | ||
| 777 | .conformanceVersion = {}, | ||
| 774 | }; | 778 | }; |
| 775 | 779 | ||
| 776 | VkPhysicalDeviceProperties2KHR properties{ | 780 | VkPhysicalDeviceProperties2KHR device_properties{ |
| 777 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, | 781 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, |
| 778 | .pNext = &driver, | 782 | .pNext = &driver, |
| 783 | .properties = {}, | ||
| 779 | }; | 784 | }; |
| 780 | physical.GetProperties2KHR(properties); | 785 | physical.GetProperties2KHR(device_properties); |
| 781 | 786 | ||
| 782 | driver_id = driver.driverID; | 787 | driver_id = driver.driverID; |
| 783 | vendor_name = driver.driverName; | 788 | vendor_name = driver.driverName; |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 696eaeb5f..0e8f9c352 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -159,6 +159,7 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules( | |||
| 159 | .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | 159 | .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, |
| 160 | .pNext = nullptr, | 160 | .pNext = nullptr, |
| 161 | .flags = 0, | 161 | .flags = 0, |
| 162 | .codeSize = 0, | ||
| 162 | }; | 163 | }; |
| 163 | 164 | ||
| 164 | std::vector<vk::ShaderModule> modules; | 165 | std::vector<vk::ShaderModule> modules; |
| @@ -388,6 +389,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 388 | .logicOp = VK_LOGIC_OP_COPY, | 389 | .logicOp = VK_LOGIC_OP_COPY, |
| 389 | .attachmentCount = static_cast<u32>(num_attachments), | 390 | .attachmentCount = static_cast<u32>(num_attachments), |
| 390 | .pAttachments = cb_attachments.data(), | 391 | .pAttachments = cb_attachments.data(), |
| 392 | .blendConstants = {}, | ||
| 391 | }; | 393 | }; |
| 392 | 394 | ||
| 393 | std::vector dynamic_states{ | 395 | std::vector dynamic_states{ |
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp index 4e932a4b6..02fdccd86 100644 --- a/src/video_core/shader/decode/texture.cpp +++ b/src/video_core/shader/decode/texture.cpp | |||
| @@ -556,7 +556,6 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, | |||
| 556 | const bool is_shadow = depth_compare != nullptr; | 556 | const bool is_shadow = depth_compare != nullptr; |
| 557 | const bool is_bindless = bindless_reg.has_value(); | 557 | const bool is_bindless = bindless_reg.has_value(); |
| 558 | 558 | ||
| 559 | UNIMPLEMENTED_IF(texture_type == TextureType::TextureCube && is_array && is_shadow); | ||
| 560 | ASSERT_MSG(texture_type != TextureType::Texture3D || !is_array || !is_shadow, | 559 | ASSERT_MSG(texture_type != TextureType::Texture3D || !is_array || !is_shadow, |
| 561 | "Illegal texture type"); | 560 | "Illegal texture type"); |
| 562 | 561 | ||
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index e8515321b..13dd16356 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp | |||
| @@ -240,6 +240,7 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( | |||
| 240 | .is_tiled = is_tiled, | 240 | .is_tiled = is_tiled, |
| 241 | .srgb_conversion = config.format == Tegra::RenderTargetFormat::B8G8R8A8_SRGB || | 241 | .srgb_conversion = config.format == Tegra::RenderTargetFormat::B8G8R8A8_SRGB || |
| 242 | config.format == Tegra::RenderTargetFormat::A8B8G8R8_SRGB, | 242 | config.format == Tegra::RenderTargetFormat::A8B8G8R8_SRGB, |
| 243 | .is_layered = false, | ||
| 243 | .block_width = is_tiled ? std::min(config.BlockWidth(), 5U) : 0U, | 244 | .block_width = is_tiled ? std::min(config.BlockWidth(), 5U) : 0U, |
| 244 | .block_height = is_tiled ? std::min(config.BlockHeight(), 5U) : 0U, | 245 | .block_height = is_tiled ? std::min(config.BlockHeight(), 5U) : 0U, |
| 245 | .block_depth = is_tiled ? std::min(config.BlockDepth(), 5U) : 0U, | 246 | .block_depth = is_tiled ? std::min(config.BlockDepth(), 5U) : 0U, |
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index fa9124ecf..db9518798 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp | |||
| @@ -25,8 +25,8 @@ ConfigureAudio::ConfigureAudio(QWidget* parent) | |||
| 25 | connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this, | 25 | connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this, |
| 26 | &ConfigureAudio::UpdateAudioDevices); | 26 | &ConfigureAudio::UpdateAudioDevices); |
| 27 | 27 | ||
| 28 | ui->volume_label->setVisible(Settings::configuring_global); | 28 | ui->volume_label->setVisible(Settings::IsConfiguringGlobal()); |
| 29 | ui->volume_combo_box->setVisible(!Settings::configuring_global); | 29 | ui->volume_combo_box->setVisible(!Settings::IsConfiguringGlobal()); |
| 30 | 30 | ||
| 31 | SetupPerGameUI(); | 31 | SetupPerGameUI(); |
| 32 | 32 | ||
| @@ -51,7 +51,7 @@ void ConfigureAudio::SetConfiguration() { | |||
| 51 | 51 | ||
| 52 | ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching.GetValue()); | 52 | ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching.GetValue()); |
| 53 | 53 | ||
| 54 | if (!Settings::configuring_global) { | 54 | if (!Settings::IsConfiguringGlobal()) { |
| 55 | if (Settings::values.volume.UsingGlobal()) { | 55 | if (Settings::values.volume.UsingGlobal()) { |
| 56 | ui->volume_combo_box->setCurrentIndex(0); | 56 | ui->volume_combo_box->setCurrentIndex(0); |
| 57 | ui->volume_slider->setEnabled(false); | 57 | ui->volume_slider->setEnabled(false); |
| @@ -99,7 +99,7 @@ void ConfigureAudio::SetVolumeIndicatorText(int percentage) { | |||
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | void ConfigureAudio::ApplyConfiguration() { | 101 | void ConfigureAudio::ApplyConfiguration() { |
| 102 | if (Settings::configuring_global) { | 102 | if (Settings::IsConfiguringGlobal()) { |
| 103 | Settings::values.sink_id = | 103 | Settings::values.sink_id = |
| 104 | ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) | 104 | ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) |
| 105 | .toStdString(); | 105 | .toStdString(); |
| @@ -165,7 +165,7 @@ void ConfigureAudio::RetranslateUI() { | |||
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | void ConfigureAudio::SetupPerGameUI() { | 167 | void ConfigureAudio::SetupPerGameUI() { |
| 168 | if (Settings::configuring_global) { | 168 | if (Settings::IsConfiguringGlobal()) { |
| 169 | ui->volume_slider->setEnabled(Settings::values.volume.UsingGlobal()); | 169 | ui->volume_slider->setEnabled(Settings::values.volume.UsingGlobal()); |
| 170 | ui->toggle_audio_stretching->setEnabled( | 170 | ui->toggle_audio_stretching->setEnabled( |
| 171 | Settings::values.enable_audio_stretching.UsingGlobal()); | 171 | Settings::values.enable_audio_stretching.UsingGlobal()); |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 8186929a6..5041e0bf8 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, | 15 | ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, |
| 16 | InputCommon::InputSubsystem* input_subsystem) | 16 | InputCommon::InputSubsystem* input_subsystem) |
| 17 | : QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) { | 17 | : QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) { |
| 18 | Settings::configuring_global = true; | 18 | Settings::SetConfiguringGlobal(true); |
| 19 | 19 | ||
| 20 | ui->setupUi(this); | 20 | ui->setupUi(this); |
| 21 | ui->hotkeysTab->Populate(registry); | 21 | ui->hotkeysTab->Populate(registry); |
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 830096ea0..d4d29d422 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp | |||
| @@ -19,7 +19,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent) | |||
| 19 | 19 | ||
| 20 | SetConfiguration(); | 20 | SetConfiguration(); |
| 21 | 21 | ||
| 22 | if (Settings::configuring_global) { | 22 | if (Settings::IsConfiguringGlobal()) { |
| 23 | connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit, | 23 | connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit, |
| 24 | [this]() { ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked()); }); | 24 | [this]() { ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked()); }); |
| 25 | } | 25 | } |
| @@ -41,7 +41,7 @@ void ConfigureGeneral::SetConfiguration() { | |||
| 41 | ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue()); | 41 | ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue()); |
| 42 | ui->frame_limit->setValue(Settings::values.frame_limit.GetValue()); | 42 | ui->frame_limit->setValue(Settings::values.frame_limit.GetValue()); |
| 43 | 43 | ||
| 44 | if (Settings::configuring_global) { | 44 | if (Settings::IsConfiguringGlobal()) { |
| 45 | ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue()); | 45 | ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue()); |
| 46 | } else { | 46 | } else { |
| 47 | ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue() && | 47 | ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue() && |
| @@ -50,7 +50,7 @@ void ConfigureGeneral::SetConfiguration() { | |||
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | void ConfigureGeneral::ApplyConfiguration() { | 52 | void ConfigureGeneral::ApplyConfiguration() { |
| 53 | if (Settings::configuring_global) { | 53 | if (Settings::IsConfiguringGlobal()) { |
| 54 | UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); | 54 | UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); |
| 55 | UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); | 55 | UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); |
| 56 | UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); | 56 | UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); |
| @@ -93,7 +93,7 @@ void ConfigureGeneral::RetranslateUI() { | |||
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | void ConfigureGeneral::SetupPerGameUI() { | 95 | void ConfigureGeneral::SetupPerGameUI() { |
| 96 | if (Settings::configuring_global) { | 96 | if (Settings::IsConfiguringGlobal()) { |
| 97 | ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal()); | 97 | ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal()); |
| 98 | ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal()); | 98 | ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal()); |
| 99 | 99 | ||
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 4f083ecda..6fda0ce35 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -33,7 +33,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent) | |||
| 33 | 33 | ||
| 34 | connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] { | 34 | connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] { |
| 35 | UpdateDeviceComboBox(); | 35 | UpdateDeviceComboBox(); |
| 36 | if (!Settings::configuring_global) { | 36 | if (!Settings::IsConfiguringGlobal()) { |
| 37 | ConfigurationShared::SetHighlight( | 37 | ConfigurationShared::SetHighlight( |
| 38 | ui->api_layout, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX); | 38 | ui->api_layout, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX); |
| 39 | } | 39 | } |
| @@ -49,8 +49,8 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent) | |||
| 49 | UpdateBackgroundColorButton(new_bg_color); | 49 | UpdateBackgroundColorButton(new_bg_color); |
| 50 | }); | 50 | }); |
| 51 | 51 | ||
| 52 | ui->bg_label->setVisible(Settings::configuring_global); | 52 | ui->bg_label->setVisible(Settings::IsConfiguringGlobal()); |
| 53 | ui->bg_combobox->setVisible(!Settings::configuring_global); | 53 | ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal()); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | void ConfigureGraphics::UpdateDeviceSelection(int device) { | 56 | void ConfigureGraphics::UpdateDeviceSelection(int device) { |
| @@ -76,7 +76,7 @@ void ConfigureGraphics::SetConfiguration() { | |||
| 76 | Settings::values.use_asynchronous_gpu_emulation.GetValue()); | 76 | Settings::values.use_asynchronous_gpu_emulation.GetValue()); |
| 77 | ui->use_nvdec_emulation->setChecked(Settings::values.use_nvdec_emulation.GetValue()); | 77 | ui->use_nvdec_emulation->setChecked(Settings::values.use_nvdec_emulation.GetValue()); |
| 78 | 78 | ||
| 79 | if (Settings::configuring_global) { | 79 | if (Settings::IsConfiguringGlobal()) { |
| 80 | ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); | 80 | ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); |
| 81 | ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); | 81 | ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); |
| 82 | } else { | 82 | } else { |
| @@ -100,7 +100,7 @@ void ConfigureGraphics::SetConfiguration() { | |||
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | void ConfigureGraphics::ApplyConfiguration() { | 102 | void ConfigureGraphics::ApplyConfiguration() { |
| 103 | if (Settings::configuring_global) { | 103 | if (Settings::IsConfiguringGlobal()) { |
| 104 | // Guard if during game and set to game-specific value | 104 | // Guard if during game and set to game-specific value |
| 105 | if (Settings::values.renderer_backend.UsingGlobal()) { | 105 | if (Settings::values.renderer_backend.UsingGlobal()) { |
| 106 | Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend()); | 106 | Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend()); |
| @@ -194,7 +194,7 @@ void ConfigureGraphics::UpdateDeviceComboBox() { | |||
| 194 | 194 | ||
| 195 | bool enabled = false; | 195 | bool enabled = false; |
| 196 | 196 | ||
| 197 | if (!Settings::configuring_global && | 197 | if (!Settings::IsConfiguringGlobal() && |
| 198 | ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { | 198 | ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { |
| 199 | vulkan_device = Settings::values.vulkan_device.GetValue(); | 199 | vulkan_device = Settings::values.vulkan_device.GetValue(); |
| 200 | } | 200 | } |
| @@ -212,7 +212,7 @@ void ConfigureGraphics::UpdateDeviceComboBox() { | |||
| 212 | break; | 212 | break; |
| 213 | } | 213 | } |
| 214 | // If in per-game config and use global is selected, don't enable. | 214 | // If in per-game config and use global is selected, don't enable. |
| 215 | enabled &= !(!Settings::configuring_global && | 215 | enabled &= !(!Settings::IsConfiguringGlobal() && |
| 216 | ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX); | 216 | ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX); |
| 217 | ui->device->setEnabled(enabled && !Core::System::GetInstance().IsPoweredOn()); | 217 | ui->device->setEnabled(enabled && !Core::System::GetInstance().IsPoweredOn()); |
| 218 | } | 218 | } |
| @@ -227,7 +227,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() { | |||
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { | 229 | Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { |
| 230 | if (Settings::configuring_global) { | 230 | if (Settings::IsConfiguringGlobal()) { |
| 231 | return static_cast<Settings::RendererBackend>(ui->api->currentIndex()); | 231 | return static_cast<Settings::RendererBackend>(ui->api->currentIndex()); |
| 232 | } | 232 | } |
| 233 | 233 | ||
| @@ -241,7 +241,7 @@ Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { | |||
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | void ConfigureGraphics::SetupPerGameUI() { | 243 | void ConfigureGraphics::SetupPerGameUI() { |
| 244 | if (Settings::configuring_global) { | 244 | if (Settings::IsConfiguringGlobal()) { |
| 245 | ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal()); | 245 | ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal()); |
| 246 | ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal()); | 246 | ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal()); |
| 247 | ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal()); | 247 | ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal()); |
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 73f276949..383c7bac8 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp | |||
| @@ -32,7 +32,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { | |||
| 32 | ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); | 32 | ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); |
| 33 | ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); | 33 | ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); |
| 34 | 34 | ||
| 35 | if (Settings::configuring_global) { | 35 | if (Settings::IsConfiguringGlobal()) { |
| 36 | ui->gpu_accuracy->setCurrentIndex( | 36 | ui->gpu_accuracy->setCurrentIndex( |
| 37 | static_cast<int>(Settings::values.gpu_accuracy.GetValue())); | 37 | static_cast<int>(Settings::values.gpu_accuracy.GetValue())); |
| 38 | ui->anisotropic_filtering_combobox->setCurrentIndex( | 38 | ui->anisotropic_filtering_combobox->setCurrentIndex( |
| @@ -52,9 +52,9 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { | |||
| 52 | // Subtract 2 if configuring per-game (separator and "use global configuration" take 2 slots) | 52 | // Subtract 2 if configuring per-game (separator and "use global configuration" take 2 slots) |
| 53 | const auto gpu_accuracy = static_cast<Settings::GPUAccuracy>( | 53 | const auto gpu_accuracy = static_cast<Settings::GPUAccuracy>( |
| 54 | ui->gpu_accuracy->currentIndex() - | 54 | ui->gpu_accuracy->currentIndex() - |
| 55 | ((Settings::configuring_global) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET)); | 55 | ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET)); |
| 56 | 56 | ||
| 57 | if (Settings::configuring_global) { | 57 | if (Settings::IsConfiguringGlobal()) { |
| 58 | // Must guard in case of a during-game configuration when set to be game-specific. | 58 | // Must guard in case of a during-game configuration when set to be game-specific. |
| 59 | if (Settings::values.gpu_accuracy.UsingGlobal()) { | 59 | if (Settings::values.gpu_accuracy.UsingGlobal()) { |
| 60 | Settings::values.gpu_accuracy.SetValue(gpu_accuracy); | 60 | Settings::values.gpu_accuracy.SetValue(gpu_accuracy); |
| @@ -118,7 +118,7 @@ void ConfigureGraphicsAdvanced::RetranslateUI() { | |||
| 118 | 118 | ||
| 119 | void ConfigureGraphicsAdvanced::SetupPerGameUI() { | 119 | void ConfigureGraphicsAdvanced::SetupPerGameUI() { |
| 120 | // Disable if not global (only happens during game) | 120 | // Disable if not global (only happens during game) |
| 121 | if (Settings::configuring_global) { | 121 | if (Settings::IsConfiguringGlobal()) { |
| 122 | ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); | 122 | ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); |
| 123 | ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); | 123 | ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); |
| 124 | ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal()); | 124 | ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal()); |
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 1e49f0787..002db3f93 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp | |||
| @@ -31,7 +31,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id) | |||
| 31 | : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id(title_id) { | 31 | : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id(title_id) { |
| 32 | game_config = std::make_unique<Config>(fmt::format("{:016X}.ini", title_id), false); | 32 | game_config = std::make_unique<Config>(fmt::format("{:016X}.ini", title_id), false); |
| 33 | 33 | ||
| 34 | Settings::configuring_global = false; | 34 | Settings::SetConfiguringGlobal(false); |
| 35 | 35 | ||
| 36 | ui->setupUi(this); | 36 | ui->setupUi(this); |
| 37 | setFocusPolicy(Qt::ClickFocus); | 37 | setFocusPolicy(Qt::ClickFocus); |
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 5e8e201dc..59a58d92c 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -37,8 +37,8 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui:: | |||
| 37 | } | 37 | } |
| 38 | }); | 38 | }); |
| 39 | 39 | ||
| 40 | ui->label_console_id->setVisible(Settings::configuring_global); | 40 | ui->label_console_id->setVisible(Settings::IsConfiguringGlobal()); |
| 41 | ui->button_regenerate_console_id->setVisible(Settings::configuring_global); | 41 | ui->button_regenerate_console_id->setVisible(Settings::IsConfiguringGlobal()); |
| 42 | 42 | ||
| 43 | SetupPerGameUI(); | 43 | SetupPerGameUI(); |
| 44 | 44 | ||
| @@ -78,7 +78,7 @@ void ConfigureSystem::SetConfiguration() { | |||
| 78 | Settings::values.rng_seed.UsingGlobal()); | 78 | Settings::values.rng_seed.UsingGlobal()); |
| 79 | ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); | 79 | ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); |
| 80 | 80 | ||
| 81 | if (Settings::configuring_global) { | 81 | if (Settings::IsConfiguringGlobal()) { |
| 82 | ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); | 82 | ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); |
| 83 | ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue()); | 83 | ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue()); |
| 84 | ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue()); | 84 | ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue()); |
| @@ -125,7 +125,7 @@ void ConfigureSystem::ApplyConfiguration() { | |||
| 125 | return; | 125 | return; |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | if (Settings::configuring_global) { | 128 | if (Settings::IsConfiguringGlobal()) { |
| 129 | // Guard if during game and set to game-specific value | 129 | // Guard if during game and set to game-specific value |
| 130 | if (Settings::values.language_index.UsingGlobal()) { | 130 | if (Settings::values.language_index.UsingGlobal()) { |
| 131 | Settings::values.language_index.SetValue(ui->combo_language->currentIndex()); | 131 | Settings::values.language_index.SetValue(ui->combo_language->currentIndex()); |
| @@ -218,7 +218,7 @@ void ConfigureSystem::RefreshConsoleID() { | |||
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | void ConfigureSystem::SetupPerGameUI() { | 220 | void ConfigureSystem::SetupPerGameUI() { |
| 221 | if (Settings::configuring_global) { | 221 | if (Settings::IsConfiguringGlobal()) { |
| 222 | ui->combo_language->setEnabled(Settings::values.language_index.UsingGlobal()); | 222 | ui->combo_language->setEnabled(Settings::values.language_index.UsingGlobal()); |
| 223 | ui->combo_region->setEnabled(Settings::values.region_index.UsingGlobal()); | 223 | ui->combo_region->setEnabled(Settings::values.region_index.UsingGlobal()); |
| 224 | ui->combo_time_zone->setEnabled(Settings::values.time_zone_index.UsingGlobal()); | 224 | ui->combo_time_zone->setEnabled(Settings::values.time_zone_index.UsingGlobal()); |