diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 176 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 42 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_vic.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.cpp | 174 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.h | 56 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 7 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.h | 1 |
14 files changed, 291 insertions, 199 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 51c40f620..122c1d5e1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -3,9 +3,11 @@ | |||
| 3 | // SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3 | 3 | // SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3 |
| 4 | // or any later version Refer to the license.txt file included. | 4 | // or any later version Refer to the license.txt file included. |
| 5 | 5 | ||
| 6 | #include <bit> | ||
| 6 | #include <cstdlib> | 7 | #include <cstdlib> |
| 7 | #include <cstring> | 8 | #include <cstring> |
| 8 | 9 | ||
| 10 | #include <fmt/format.h> | ||
| 9 | #include "common/assert.h" | 11 | #include "common/assert.h" |
| 10 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 11 | #include "common/scope_exit.h" | 13 | #include "common/scope_exit.h" |
| @@ -22,8 +24,19 @@ namespace Service::Nvidia::Devices { | |||
| 22 | nvhost_ctrl::nvhost_ctrl(Core::System& system_, EventInterface& events_interface_, | 24 | nvhost_ctrl::nvhost_ctrl(Core::System& system_, EventInterface& events_interface_, |
| 23 | NvCore::Container& core_) | 25 | NvCore::Container& core_) |
| 24 | : nvdevice{system_}, events_interface{events_interface_}, core{core_}, | 26 | : nvdevice{system_}, events_interface{events_interface_}, core{core_}, |
| 25 | syncpoint_manager{core_.GetSyncpointManager()} {} | 27 | syncpoint_manager{core_.GetSyncpointManager()} { |
| 26 | nvhost_ctrl::~nvhost_ctrl() = default; | 28 | events_interface.RegisterForSignal(this); |
| 29 | } | ||
| 30 | |||
| 31 | nvhost_ctrl::~nvhost_ctrl() { | ||
| 32 | events_interface.UnregisterForSignal(this); | ||
| 33 | for (auto& event : events) { | ||
| 34 | if (!event.registered) { | ||
| 35 | continue; | ||
| 36 | } | ||
| 37 | events_interface.FreeEvent(event.kevent); | ||
| 38 | } | ||
| 39 | } | ||
| 27 | 40 | ||
| 28 | NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | 41 | NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 29 | std::vector<u8>& output) { | 42 | std::vector<u8>& output) { |
| @@ -87,7 +100,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 87 | SCOPE_EXIT({ | 100 | SCOPE_EXIT({ |
| 88 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 101 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 89 | if (must_unmark_fail) { | 102 | if (must_unmark_fail) { |
| 90 | events_interface.fails[event_id] = 0; | 103 | events[event_id].fails = 0; |
| 91 | } | 104 | } |
| 92 | }); | 105 | }); |
| 93 | 106 | ||
| @@ -116,12 +129,12 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 116 | auto& gpu = system.GPU(); | 129 | auto& gpu = system.GPU(); |
| 117 | const u32 target_value = params.fence.value; | 130 | const u32 target_value = params.fence.value; |
| 118 | 131 | ||
| 119 | auto lock = events_interface.Lock(); | 132 | auto lock = NvEventsLock(); |
| 120 | 133 | ||
| 121 | u32 slot = [&]() { | 134 | u32 slot = [&]() { |
| 122 | if (is_allocation) { | 135 | if (is_allocation) { |
| 123 | params.value.raw = 0; | 136 | params.value.raw = 0; |
| 124 | return events_interface.FindFreeEvent(fence_id); | 137 | return FindFreeNvEvent(fence_id); |
| 125 | } else { | 138 | } else { |
| 126 | return params.value.raw; | 139 | return params.value.raw; |
| 127 | } | 140 | } |
| @@ -130,7 +143,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 130 | must_unmark_fail = true; | 143 | must_unmark_fail = true; |
| 131 | 144 | ||
| 132 | const auto check_failing = [&]() { | 145 | const auto check_failing = [&]() { |
| 133 | if (events_interface.fails[slot] > 2) { | 146 | if (events[slot].fails > 2) { |
| 134 | { | 147 | { |
| 135 | auto lk = system.StallProcesses(); | 148 | auto lk = system.StallProcesses(); |
| 136 | gpu.WaitFence(fence_id, target_value); | 149 | gpu.WaitFence(fence_id, target_value); |
| @@ -142,6 +155,10 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 142 | return false; | 155 | return false; |
| 143 | }; | 156 | }; |
| 144 | 157 | ||
| 158 | if (slot >= MaxNvEvents) { | ||
| 159 | return NvResult::BadParameter; | ||
| 160 | } | ||
| 161 | |||
| 145 | if (params.timeout == 0) { | 162 | if (params.timeout == 0) { |
| 146 | if (check_failing()) { | 163 | if (check_failing()) { |
| 147 | return NvResult::Success; | 164 | return NvResult::Success; |
| @@ -149,17 +166,13 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 149 | return NvResult::Timeout; | 166 | return NvResult::Timeout; |
| 150 | } | 167 | } |
| 151 | 168 | ||
| 152 | if (slot >= MaxNvEvents) { | 169 | auto& event = events[slot]; |
| 153 | return NvResult::BadParameter; | ||
| 154 | } | ||
| 155 | |||
| 156 | auto* event = events_interface.events[slot]; | ||
| 157 | 170 | ||
| 158 | if (!event) { | 171 | if (!event.registered) { |
| 159 | return NvResult::BadParameter; | 172 | return NvResult::BadParameter; |
| 160 | } | 173 | } |
| 161 | 174 | ||
| 162 | if (events_interface.IsBeingUsed(slot)) { | 175 | if (event.IsBeingUsed()) { |
| 163 | return NvResult::BadParameter; | 176 | return NvResult::BadParameter; |
| 164 | } | 177 | } |
| 165 | 178 | ||
| @@ -169,9 +182,9 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 169 | 182 | ||
| 170 | params.value.raw = 0; | 183 | params.value.raw = 0; |
| 171 | 184 | ||
| 172 | events_interface.status[slot].store(EventState::Waiting, std::memory_order_release); | 185 | event.status.store(EventState::Waiting, std::memory_order_release); |
| 173 | events_interface.assigned_syncpt[slot] = fence_id; | 186 | event.assigned_syncpt = fence_id; |
| 174 | events_interface.assigned_value[slot] = target_value; | 187 | event.assigned_value = target_value; |
| 175 | if (is_allocation) { | 188 | if (is_allocation) { |
| 176 | params.value.syncpoint_id_for_allocation.Assign(static_cast<u16>(fence_id)); | 189 | params.value.syncpoint_id_for_allocation.Assign(static_cast<u16>(fence_id)); |
| 177 | params.value.event_allocated.Assign(1); | 190 | params.value.event_allocated.Assign(1); |
| @@ -189,15 +202,17 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) { | |||
| 189 | return NvResult::BadParameter; | 202 | return NvResult::BadParameter; |
| 190 | } | 203 | } |
| 191 | 204 | ||
| 192 | if (!events_interface.registered[slot]) { | 205 | auto& event = events[slot]; |
| 206 | |||
| 207 | if (!event.registered) { | ||
| 193 | return NvResult::Success; | 208 | return NvResult::Success; |
| 194 | } | 209 | } |
| 195 | 210 | ||
| 196 | if (events_interface.IsBeingUsed(slot)) { | 211 | if (event.IsBeingUsed()) { |
| 197 | return NvResult::Busy; | 212 | return NvResult::Busy; |
| 198 | } | 213 | } |
| 199 | 214 | ||
| 200 | events_interface.Free(slot); | 215 | FreeNvEvent(slot); |
| 201 | return NvResult::Success; | 216 | return NvResult::Success; |
| 202 | } | 217 | } |
| 203 | 218 | ||
| @@ -210,15 +225,15 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve | |||
| 210 | return NvResult::BadParameter; | 225 | return NvResult::BadParameter; |
| 211 | } | 226 | } |
| 212 | 227 | ||
| 213 | auto lock = events_interface.Lock(); | 228 | auto lock = NvEventsLock(); |
| 214 | 229 | ||
| 215 | if (events_interface.registered[event_id]) { | 230 | if (events[event_id].registered) { |
| 216 | const auto result = FreeEvent(event_id); | 231 | const auto result = FreeEvent(event_id); |
| 217 | if (result != NvResult::Success) { | 232 | if (result != NvResult::Success) { |
| 218 | return result; | 233 | return result; |
| 219 | } | 234 | } |
| 220 | } | 235 | } |
| 221 | events_interface.Create(event_id); | 236 | CreateNvEvent(event_id); |
| 222 | return NvResult::Success; | 237 | return NvResult::Success; |
| 223 | } | 238 | } |
| 224 | 239 | ||
| @@ -229,7 +244,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, | |||
| 229 | const u32 event_id = params.user_event_id & 0x00FF; | 244 | const u32 event_id = params.user_event_id & 0x00FF; |
| 230 | LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); | 245 | LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); |
| 231 | 246 | ||
| 232 | auto lock = events_interface.Lock(); | 247 | auto lock = NvEventsLock(); |
| 233 | return FreeEvent(event_id); | 248 | return FreeEvent(event_id); |
| 234 | } | 249 | } |
| 235 | 250 | ||
| @@ -244,44 +259,121 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::v | |||
| 244 | return NvResult::BadParameter; | 259 | return NvResult::BadParameter; |
| 245 | } | 260 | } |
| 246 | 261 | ||
| 247 | auto lock = events_interface.Lock(); | 262 | auto lock = NvEventsLock(); |
| 248 | 263 | ||
| 249 | if (events_interface.status[event_id].exchange( | 264 | auto& event = events[event_id]; |
| 250 | EventState::Cancelling, std::memory_order_acq_rel) == EventState::Waiting) { | 265 | if (event.status.exchange(EventState::Cancelling, std::memory_order_acq_rel) == |
| 251 | system.GPU().CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id], | 266 | EventState::Waiting) { |
| 252 | events_interface.assigned_value[event_id]); | 267 | system.GPU().CancelSyncptInterrupt(event.assigned_syncpt, event.assigned_value); |
| 253 | syncpoint_manager.RefreshSyncpoint(events_interface.assigned_syncpt[event_id]); | 268 | syncpoint_manager.RefreshSyncpoint(event.assigned_syncpt); |
| 254 | } | 269 | } |
| 255 | events_interface.fails[event_id]++; | 270 | event.fails++; |
| 256 | events_interface.status[event_id].store(EventState::Cancelled, std::memory_order_release); | 271 | event.status.store(EventState::Cancelled, std::memory_order_release); |
| 257 | events_interface.events[event_id]->GetWritableEvent().Clear(); | 272 | event.kevent->GetWritableEvent().Clear(); |
| 258 | 273 | ||
| 259 | return NvResult::Success; | 274 | return NvResult::Success; |
| 260 | } | 275 | } |
| 261 | 276 | ||
| 262 | Kernel::KEvent* nvhost_ctrl::QueryEvent(u32 event_id) { | 277 | Kernel::KEvent* nvhost_ctrl::QueryEvent(u32 event_id) { |
| 263 | const auto event = SyncpointEventValue{.raw = event_id}; | 278 | const auto desired_event = SyncpointEventValue{.raw = event_id}; |
| 264 | 279 | ||
| 265 | const bool allocated = event.event_allocated.Value() != 0; | 280 | const bool allocated = desired_event.event_allocated.Value() != 0; |
| 266 | const u32 slot{allocated ? event.partial_slot.Value() : static_cast<u32>(event.slot)}; | 281 | const u32 slot{allocated ? desired_event.partial_slot.Value() |
| 282 | : static_cast<u32>(desired_event.slot)}; | ||
| 267 | if (slot >= MaxNvEvents) { | 283 | if (slot >= MaxNvEvents) { |
| 268 | ASSERT(false); | 284 | ASSERT(false); |
| 269 | return nullptr; | 285 | return nullptr; |
| 270 | } | 286 | } |
| 271 | 287 | ||
| 272 | const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value() | 288 | const u32 syncpoint_id{allocated ? desired_event.syncpoint_id_for_allocation.Value() |
| 273 | : event.syncpoint_id.Value()}; | 289 | : desired_event.syncpoint_id.Value()}; |
| 274 | 290 | ||
| 275 | auto lock = events_interface.Lock(); | 291 | auto lock = NvEventsLock(); |
| 276 | 292 | ||
| 277 | if (events_interface.registered[slot] && | 293 | auto& event = events[slot]; |
| 278 | events_interface.assigned_syncpt[slot] == syncpoint_id) { | 294 | if (event.registered && event.assigned_syncpt == syncpoint_id) { |
| 279 | ASSERT(events_interface.events[slot]); | 295 | ASSERT(event.kevent); |
| 280 | return events_interface.events[slot]; | 296 | return event.kevent; |
| 281 | } | 297 | } |
| 282 | // Is this possible in hardware? | 298 | // Is this possible in hardware? |
| 283 | ASSERT_MSG(false, "Slot:{}, SyncpointID:{}, requested", slot, syncpoint_id); | 299 | ASSERT_MSG(false, "Slot:{}, SyncpointID:{}, requested", slot, syncpoint_id); |
| 284 | return nullptr; | 300 | return nullptr; |
| 285 | } | 301 | } |
| 286 | 302 | ||
| 303 | std::unique_lock<std::mutex> nvhost_ctrl::NvEventsLock() { | ||
| 304 | return std::unique_lock<std::mutex>(events_mutex); | ||
| 305 | } | ||
| 306 | |||
| 307 | void nvhost_ctrl::CreateNvEvent(u32 event_id) { | ||
| 308 | auto& event = events[event_id]; | ||
| 309 | ASSERT(!event.kevent); | ||
| 310 | ASSERT(!event.registered); | ||
| 311 | ASSERT(!event.IsBeingUsed()); | ||
| 312 | event.kevent = events_interface.CreateEvent(fmt::format("NVCTRL::NvEvent_{}", event_id)); | ||
| 313 | event.status = EventState::Available; | ||
| 314 | event.registered = true; | ||
| 315 | const u64 mask = 1ULL << event_id; | ||
| 316 | event.fails = 0; | ||
| 317 | events_mask |= mask; | ||
| 318 | event.assigned_syncpt = 0; | ||
| 319 | } | ||
| 320 | |||
| 321 | void nvhost_ctrl::FreeNvEvent(u32 event_id) { | ||
| 322 | auto& event = events[event_id]; | ||
| 323 | ASSERT(event.kevent); | ||
| 324 | ASSERT(event.registered); | ||
| 325 | ASSERT(!event.IsBeingUsed()); | ||
| 326 | events_interface.FreeEvent(event.kevent); | ||
| 327 | event.kevent = nullptr; | ||
| 328 | event.status = EventState::Available; | ||
| 329 | event.registered = false; | ||
| 330 | const u64 mask = ~(1ULL << event_id); | ||
| 331 | events_mask &= mask; | ||
| 332 | } | ||
| 333 | |||
| 334 | u32 nvhost_ctrl::FindFreeNvEvent(u32 syncpoint_id) { | ||
| 335 | u32 slot{MaxNvEvents}; | ||
| 336 | u32 free_slot{MaxNvEvents}; | ||
| 337 | for (u32 i = 0; i < MaxNvEvents; i++) { | ||
| 338 | auto& event = events[i]; | ||
| 339 | if (event.registered) { | ||
| 340 | if (!event.IsBeingUsed()) { | ||
| 341 | slot = i; | ||
| 342 | if (event.assigned_syncpt == syncpoint_id) { | ||
| 343 | return slot; | ||
| 344 | } | ||
| 345 | } | ||
| 346 | } else if (free_slot == MaxNvEvents) { | ||
| 347 | free_slot = i; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | if (free_slot < MaxNvEvents) { | ||
| 351 | CreateNvEvent(free_slot); | ||
| 352 | return free_slot; | ||
| 353 | } | ||
| 354 | |||
| 355 | if (slot < MaxNvEvents) { | ||
| 356 | return slot; | ||
| 357 | } | ||
| 358 | |||
| 359 | LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event"); | ||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | |||
| 363 | void nvhost_ctrl::SignalNvEvent(u32 syncpoint_id, u32 value) { | ||
| 364 | const u32 max = MaxNvEvents - std::countl_zero(events_mask); | ||
| 365 | const u32 min = std::countr_zero(events_mask); | ||
| 366 | for (u32 i = min; i < max; i++) { | ||
| 367 | auto& event = events[i]; | ||
| 368 | if (event.assigned_syncpt != syncpoint_id || event.assigned_value != value) { | ||
| 369 | continue; | ||
| 370 | } | ||
| 371 | if (event.status.exchange(EventState::Signalling, std::memory_order_acq_rel) == | ||
| 372 | EventState::Waiting) { | ||
| 373 | event.kevent->GetWritableEvent().Signal(); | ||
| 374 | } | ||
| 375 | event.status.store(EventState::Signalled, std::memory_order_release); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 287 | } // namespace Service::Nvidia::Devices | 379 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 9fd46ea5f..f2fc5d047 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | |||
| @@ -53,7 +53,49 @@ public: | |||
| 53 | }; | 53 | }; |
| 54 | static_assert(sizeof(SyncpointEventValue) == sizeof(u32)); | 54 | static_assert(sizeof(SyncpointEventValue) == sizeof(u32)); |
| 55 | 55 | ||
| 56 | void SignalNvEvent(u32 syncpoint_id, u32 value); | ||
| 57 | |||
| 56 | private: | 58 | private: |
| 59 | struct InternalEvent { | ||
| 60 | // Mask representing registered events | ||
| 61 | |||
| 62 | // Each kernel event associated to an NV event | ||
| 63 | Kernel::KEvent* kevent{}; | ||
| 64 | // The status of the current NVEvent | ||
| 65 | std::atomic<EventState> status{}; | ||
| 66 | |||
| 67 | // Tells the NVEvent that it has failed. | ||
| 68 | u32 fails{}; | ||
| 69 | // When an NVEvent is waiting on GPU interrupt, this is the sync_point | ||
| 70 | // associated with it. | ||
| 71 | u32 assigned_syncpt{}; | ||
| 72 | // This is the value of the GPU interrupt for which the NVEvent is waiting | ||
| 73 | // for. | ||
| 74 | u32 assigned_value{}; | ||
| 75 | |||
| 76 | // Tells if an NVEvent is registered or not | ||
| 77 | bool registered{}; | ||
| 78 | |||
| 79 | bool IsBeingUsed() { | ||
| 80 | const auto current_status = status.load(std::memory_order_acquire); | ||
| 81 | return current_status == EventState::Waiting || | ||
| 82 | current_status == EventState::Cancelling || | ||
| 83 | current_status == EventState::Signalling; | ||
| 84 | } | ||
| 85 | }; | ||
| 86 | |||
| 87 | std::unique_lock<std::mutex> NvEventsLock(); | ||
| 88 | |||
| 89 | void CreateNvEvent(u32 event_id); | ||
| 90 | |||
| 91 | void FreeNvEvent(u32 event_id); | ||
| 92 | |||
| 93 | u32 FindFreeNvEvent(u32 syncpoint_id); | ||
| 94 | |||
| 95 | std::array<InternalEvent, MaxNvEvents> events{}; | ||
| 96 | std::mutex events_mutex; | ||
| 97 | u64 events_mask{}; | ||
| 98 | |||
| 57 | struct IocSyncptReadParams { | 99 | struct IocSyncptReadParams { |
| 58 | u32_le id{}; | 100 | u32_le id{}; |
| 59 | u32_le value{}; | 101 | u32_le value{}; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index e353408eb..ced57dfe6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -13,10 +13,13 @@ namespace Service::Nvidia::Devices { | |||
| 13 | 13 | ||
| 14 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) | 14 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) |
| 15 | : nvdevice{system_}, events_interface{events_interface_} { | 15 | : nvdevice{system_}, events_interface{events_interface_} { |
| 16 | error_notifier_event = events_interface.CreateNonCtrlEvent("CtrlGpuErrorNotifier"); | 16 | error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); |
| 17 | unknown_event = events_interface.CreateNonCtrlEvent("CtrlGpuUknownEvent"); | 17 | unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent"); |
| 18 | } | ||
| 19 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { | ||
| 20 | events_interface.FreeEvent(error_notifier_event); | ||
| 21 | events_interface.FreeEvent(unknown_event); | ||
| 18 | } | 22 | } |
| 19 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; | ||
| 20 | 23 | ||
| 21 | NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | 24 | NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 22 | std::vector<u8>& output) { | 25 | std::vector<u8>& output) { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index e7921ade2..cb54ee5a4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -30,13 +30,17 @@ nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_, | |||
| 30 | channel_fence.id = syncpoint_manager.AllocateSyncpoint(); | 30 | channel_fence.id = syncpoint_manager.AllocateSyncpoint(); |
| 31 | channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id); | 31 | channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id); |
| 32 | sm_exception_breakpoint_int_report_event = | 32 | sm_exception_breakpoint_int_report_event = |
| 33 | events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointInt"); | 33 | events_interface.CreateEvent("GpuChannelSMExceptionBreakpointInt"); |
| 34 | sm_exception_breakpoint_pause_report_event = | 34 | sm_exception_breakpoint_pause_report_event = |
| 35 | events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointPause"); | 35 | events_interface.CreateEvent("GpuChannelSMExceptionBreakpointPause"); |
| 36 | error_notifier_event = events_interface.CreateNonCtrlEvent("GpuChannelErrorNotifier"); | 36 | error_notifier_event = events_interface.CreateEvent("GpuChannelErrorNotifier"); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | nvhost_gpu::~nvhost_gpu() = default; | 39 | nvhost_gpu::~nvhost_gpu() { |
| 40 | events_interface.FreeEvent(sm_exception_breakpoint_int_report_event); | ||
| 41 | events_interface.FreeEvent(sm_exception_breakpoint_pause_report_event); | ||
| 42 | events_interface.FreeEvent(error_notifier_event); | ||
| 43 | } | ||
| 40 | 44 | ||
| 41 | NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | 45 | NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 42 | std::vector<u8>& output) { | 46 | std::vector<u8>& output) { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index aa1a00832..00947ea19 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -10,6 +10,8 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::Nvidia::Devices { | 11 | namespace Service::Nvidia::Devices { |
| 12 | 12 | ||
| 13 | u32 nvhost_nvdec::next_id{}; | ||
| 14 | |||
| 13 | nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core) | 15 | nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core) |
| 14 | : nvhost_nvdec_common{system_, core} {} | 16 | : nvhost_nvdec_common{system_, core} {} |
| 15 | nvhost_nvdec::~nvhost_nvdec() = default; | 17 | nvhost_nvdec::~nvhost_nvdec() = default; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index fef4b3216..3261ce1d4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | |||
| @@ -24,7 +24,7 @@ public: | |||
| 24 | void OnClose(DeviceFD fd) override; | 24 | void OnClose(DeviceFD fd) override; |
| 25 | 25 | ||
| 26 | private: | 26 | private: |
| 27 | u32 next_id{}; | 27 | static u32 next_id; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | } // namespace Service::Nvidia::Devices | 30 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index e76c9e5ed..77e6a1cd6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | |||
| @@ -45,6 +45,8 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s | |||
| 45 | } | 45 | } |
| 46 | } // Anonymous namespace | 46 | } // Anonymous namespace |
| 47 | 47 | ||
| 48 | std::unordered_map<DeviceFD, u32> nvhost_nvdec_common::fd_to_id{}; | ||
| 49 | |||
| 48 | nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_) | 50 | nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_) |
| 49 | : nvdevice{system_}, core{core_}, | 51 | : nvdevice{system_}, core{core_}, |
| 50 | syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} {} | 52 | syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} {} |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 74231d5c5..53029af6a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | |||
| @@ -115,7 +115,7 @@ protected: | |||
| 115 | 115 | ||
| 116 | Kernel::KEvent* QueryEvent(u32 event_id) override; | 116 | Kernel::KEvent* QueryEvent(u32 event_id) override; |
| 117 | 117 | ||
| 118 | std::unordered_map<DeviceFD, u32> fd_to_id{}; | 118 | static std::unordered_map<DeviceFD, u32> fd_to_id; |
| 119 | s32_le nvmap_fd{}; | 119 | s32_le nvmap_fd{}; |
| 120 | u32_le submit_timeout{}; | 120 | u32_le submit_timeout{}; |
| 121 | NvCore::Container& core; | 121 | NvCore::Container& core; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 358e89aa8..c89ff6b27 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | |||
| @@ -8,6 +8,9 @@ | |||
| 8 | #include "video_core/renderer_base.h" | 8 | #include "video_core/renderer_base.h" |
| 9 | 9 | ||
| 10 | namespace Service::Nvidia::Devices { | 10 | namespace Service::Nvidia::Devices { |
| 11 | |||
| 12 | u32 nvhost_vic::next_id{}; | ||
| 13 | |||
| 11 | nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core) | 14 | nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core) |
| 12 | : nvhost_nvdec_common{system_, core} {} | 15 | : nvhost_nvdec_common{system_, core} {} |
| 13 | 16 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index 252b1e6f2..59e23b41e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h | |||
| @@ -23,6 +23,6 @@ public: | |||
| 23 | void OnClose(DeviceFD fd) override; | 23 | void OnClose(DeviceFD fd) override; |
| 24 | 24 | ||
| 25 | private: | 25 | private: |
| 26 | u32 next_id{}; | 26 | static u32 next_id; |
| 27 | }; | 27 | }; |
| 28 | } // namespace Service::Nvidia::Devices | 28 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index f4914d539..ff8c7c13c 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | // SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3 | 3 | // SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3 |
| 4 | // or any later version Refer to the license.txt file included. | 4 | // or any later version Refer to the license.txt file included. |
| 5 | 5 | ||
| 6 | #include <bit> | ||
| 7 | #include <utility> | 6 | #include <utility> |
| 8 | 7 | ||
| 9 | #include <fmt/format.h> | 8 | #include <fmt/format.h> |
| @@ -30,101 +29,39 @@ | |||
| 30 | 29 | ||
| 31 | namespace Service::Nvidia { | 30 | namespace Service::Nvidia { |
| 32 | 31 | ||
| 33 | EventInterface::EventInterface(Module& module_) : module{module_} { | 32 | EventInterface::EventInterface(Module& module_) : module{module_} {} |
| 34 | events_mask = 0; | ||
| 35 | for (u32 i = 0; i < MaxNvEvents; i++) { | ||
| 36 | status[i] = EventState::Available; | ||
| 37 | events[i] = nullptr; | ||
| 38 | registered[i] = false; | ||
| 39 | } | ||
| 40 | } | ||
| 41 | 33 | ||
| 42 | EventInterface::~EventInterface() { | 34 | EventInterface::~EventInterface() = default; |
| 43 | auto lk = Lock(); | ||
| 44 | for (u32 i = 0; i < MaxNvEvents; i++) { | ||
| 45 | if (registered[i]) { | ||
| 46 | module.service_context.CloseEvent(events[i]); | ||
| 47 | events[i] = nullptr; | ||
| 48 | registered[i] = false; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | for (auto* event : basic_events) { | ||
| 52 | module.service_context.CloseEvent(event); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | 35 | ||
| 56 | std::unique_lock<std::mutex> EventInterface::Lock() { | 36 | void EventInterface::RegisterForSignal(Devices::nvhost_ctrl* device) { |
| 57 | return std::unique_lock<std::mutex>(events_mutex); | 37 | std::unique_lock<std::mutex> lk(guard); |
| 38 | on_signal.push_back(device); | ||
| 58 | } | 39 | } |
| 59 | 40 | ||
| 60 | void EventInterface::Signal(u32 event_id) { | 41 | void EventInterface::UnregisterForSignal(Devices::nvhost_ctrl* device) { |
| 61 | if (status[event_id].exchange(EventState::Signalling, std::memory_order_acq_rel) == | 42 | std::unique_lock<std::mutex> lk(guard); |
| 62 | EventState::Waiting) { | 43 | auto it = std::find(on_signal.begin(), on_signal.end(), device); |
| 63 | events[event_id]->GetWritableEvent().Signal(); | 44 | if (it != on_signal.end()) { |
| 45 | on_signal.erase(it); | ||
| 64 | } | 46 | } |
| 65 | status[event_id].store(EventState::Signalled, std::memory_order_release); | ||
| 66 | } | ||
| 67 | |||
| 68 | void EventInterface::Create(u32 event_id) { | ||
| 69 | ASSERT(!events[event_id]); | ||
| 70 | ASSERT(!registered[event_id]); | ||
| 71 | ASSERT(!IsBeingUsed(event_id)); | ||
| 72 | events[event_id] = | ||
| 73 | module.service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", event_id)); | ||
| 74 | status[event_id] = EventState::Available; | ||
| 75 | registered[event_id] = true; | ||
| 76 | const u64 mask = 1ULL << event_id; | ||
| 77 | fails[event_id] = 0; | ||
| 78 | events_mask |= mask; | ||
| 79 | assigned_syncpt[event_id] = 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | void EventInterface::Free(u32 event_id) { | ||
| 83 | ASSERT(events[event_id]); | ||
| 84 | ASSERT(registered[event_id]); | ||
| 85 | ASSERT(!IsBeingUsed(event_id)); | ||
| 86 | module.service_context.CloseEvent(events[event_id]); | ||
| 87 | events[event_id] = nullptr; | ||
| 88 | status[event_id] = EventState::Available; | ||
| 89 | registered[event_id] = false; | ||
| 90 | const u64 mask = ~(1ULL << event_id); | ||
| 91 | events_mask &= mask; | ||
| 92 | } | 47 | } |
| 93 | 48 | ||
| 94 | u32 EventInterface::FindFreeEvent(u32 syncpoint_id) { | 49 | void EventInterface::Signal(u32 syncpoint_id, u32 value) { |
| 95 | u32 slot{MaxNvEvents}; | 50 | std::unique_lock<std::mutex> lk(guard); |
| 96 | u32 free_slot{MaxNvEvents}; | 51 | for (auto* device : on_signal) { |
| 97 | for (u32 i = 0; i < MaxNvEvents; i++) { | 52 | device->SignalNvEvent(syncpoint_id, value); |
| 98 | if (registered[i]) { | ||
| 99 | if (!IsBeingUsed(i)) { | ||
| 100 | slot = i; | ||
| 101 | if (assigned_syncpt[i] == syncpoint_id) { | ||
| 102 | return slot; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } else if (free_slot == MaxNvEvents) { | ||
| 106 | free_slot = i; | ||
| 107 | } | ||
| 108 | } | 53 | } |
| 109 | if (free_slot < MaxNvEvents) { | ||
| 110 | Create(free_slot); | ||
| 111 | return free_slot; | ||
| 112 | } | ||
| 113 | |||
| 114 | if (slot < MaxNvEvents) { | ||
| 115 | return slot; | ||
| 116 | } | ||
| 117 | |||
| 118 | LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event"); | ||
| 119 | return 0; | ||
| 120 | } | 54 | } |
| 121 | 55 | ||
| 122 | Kernel::KEvent* EventInterface::CreateNonCtrlEvent(std::string name) { | 56 | Kernel::KEvent* EventInterface::CreateEvent(std::string name) { |
| 123 | Kernel::KEvent* new_event = module.service_context.CreateEvent(std::move(name)); | 57 | Kernel::KEvent* new_event = module.service_context.CreateEvent(std::move(name)); |
| 124 | basic_events.push_back(new_event); | ||
| 125 | return new_event; | 58 | return new_event; |
| 126 | } | 59 | } |
| 127 | 60 | ||
| 61 | void EventInterface::FreeEvent(Kernel::KEvent* event) { | ||
| 62 | module.service_context.CloseEvent(event); | ||
| 63 | } | ||
| 64 | |||
| 128 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, | 65 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, |
| 129 | Core::System& system) { | 66 | Core::System& system) { |
| 130 | auto module_ = std::make_shared<Module>(system); | 67 | auto module_ = std::make_shared<Module>(system); |
| @@ -138,18 +75,50 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger | |||
| 138 | 75 | ||
| 139 | Module::Module(Core::System& system) | 76 | Module::Module(Core::System& system) |
| 140 | : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} { | 77 | : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} { |
| 141 | devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, container); | 78 | builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { |
| 142 | devices["/dev/nvhost-gpu"] = | 79 | std::shared_ptr<Devices::nvdevice> device = |
| 143 | std::make_shared<Devices::nvhost_gpu>(system, events_interface, container); | 80 | std::make_shared<Devices::nvhost_as_gpu>(system, container); |
| 144 | devices["/dev/nvhost-ctrl-gpu"] = | 81 | return open_files.emplace(fd, device).first; |
| 145 | std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface); | 82 | }; |
| 146 | devices["/dev/nvmap"] = std::make_shared<Devices::nvmap>(system, container); | 83 | builders["/dev/nvhost-gpu"] = [this, &system](DeviceFD fd) { |
| 147 | devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, container); | 84 | std::shared_ptr<Devices::nvdevice> device = |
| 148 | devices["/dev/nvhost-ctrl"] = | 85 | std::make_shared<Devices::nvhost_gpu>(system, events_interface, container); |
| 149 | std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container); | 86 | return open_files.emplace(fd, device).first; |
| 150 | devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system, container); | 87 | }; |
| 151 | devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); | 88 | builders["/dev/nvhost-ctrl-gpu"] = [this, &system](DeviceFD fd) { |
| 152 | devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system, container); | 89 | std::shared_ptr<Devices::nvdevice> device = |
| 90 | std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface); | ||
| 91 | return open_files.emplace(fd, device).first; | ||
| 92 | }; | ||
| 93 | builders["/dev/nvmap"] = [this, &system](DeviceFD fd) { | ||
| 94 | std::shared_ptr<Devices::nvdevice> device = | ||
| 95 | std::make_shared<Devices::nvmap>(system, container); | ||
| 96 | return open_files.emplace(fd, device).first; | ||
| 97 | }; | ||
| 98 | builders["/dev/nvdisp_disp0"] = [this, &system](DeviceFD fd) { | ||
| 99 | std::shared_ptr<Devices::nvdevice> device = | ||
| 100 | std::make_shared<Devices::nvdisp_disp0>(system, container); | ||
| 101 | return open_files.emplace(fd, device).first; | ||
| 102 | }; | ||
| 103 | builders["/dev/nvhost-ctrl"] = [this, &system](DeviceFD fd) { | ||
| 104 | std::shared_ptr<Devices::nvdevice> device = | ||
| 105 | std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container); | ||
| 106 | return open_files.emplace(fd, device).first; | ||
| 107 | }; | ||
| 108 | builders["/dev/nvhost-nvdec"] = [this, &system](DeviceFD fd) { | ||
| 109 | std::shared_ptr<Devices::nvdevice> device = | ||
| 110 | std::make_shared<Devices::nvhost_nvdec>(system, container); | ||
| 111 | return open_files.emplace(fd, device).first; | ||
| 112 | }; | ||
| 113 | builders["/dev/nvhost-nvjpg"] = [this, &system](DeviceFD fd) { | ||
| 114 | std::shared_ptr<Devices::nvdevice> device = std::make_shared<Devices::nvhost_nvjpg>(system); | ||
| 115 | return open_files.emplace(fd, device).first; | ||
| 116 | }; | ||
| 117 | builders["/dev/nvhost-vic"] = [this, &system](DeviceFD fd) { | ||
| 118 | std::shared_ptr<Devices::nvdevice> device = | ||
| 119 | std::make_shared<Devices::nvhost_vic>(system, container); | ||
| 120 | return open_files.emplace(fd, device).first; | ||
| 121 | }; | ||
| 153 | } | 122 | } |
| 154 | 123 | ||
| 155 | Module::~Module() = default; | 124 | Module::~Module() = default; |
| @@ -169,18 +138,18 @@ NvResult Module::VerifyFD(DeviceFD fd) const { | |||
| 169 | } | 138 | } |
| 170 | 139 | ||
| 171 | DeviceFD Module::Open(const std::string& device_name) { | 140 | DeviceFD Module::Open(const std::string& device_name) { |
| 172 | if (devices.find(device_name) == devices.end()) { | 141 | auto it = builders.find(device_name); |
| 142 | if (it == builders.end()) { | ||
| 173 | LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); | 143 | LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); |
| 174 | return INVALID_NVDRV_FD; | 144 | return INVALID_NVDRV_FD; |
| 175 | } | 145 | } |
| 176 | 146 | ||
| 177 | auto device = devices[device_name]; | ||
| 178 | const DeviceFD fd = next_fd++; | 147 | const DeviceFD fd = next_fd++; |
| 148 | auto& builder = it->second; | ||
| 149 | auto device = builder(fd)->second; | ||
| 179 | 150 | ||
| 180 | device->OnOpen(fd); | 151 | device->OnOpen(fd); |
| 181 | 152 | ||
| 182 | open_files[fd] = std::move(device); | ||
| 183 | |||
| 184 | return fd; | 153 | return fd; |
| 185 | } | 154 | } |
| 186 | 155 | ||
| @@ -256,14 +225,7 @@ NvResult Module::Close(DeviceFD fd) { | |||
| 256 | } | 225 | } |
| 257 | 226 | ||
| 258 | void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { | 227 | void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { |
| 259 | const u32 max = MaxNvEvents - std::countl_zero(events_interface.events_mask); | 228 | events_interface.Signal(syncpoint_id, value); |
| 260 | const u32 min = std::countr_zero(events_interface.events_mask); | ||
| 261 | for (u32 i = min; i < max; i++) { | ||
| 262 | if (events_interface.assigned_syncpt[i] == syncpoint_id && | ||
| 263 | events_interface.assigned_value[i] == value) { | ||
| 264 | events_interface.Signal(i); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | } | 229 | } |
| 268 | 230 | ||
| 269 | NvResult Module::QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event) { | 231 | NvResult Module::QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event) { |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 96adf2ffb..3983794bb 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #pragma once | 6 | #pragma once |
| 7 | 7 | ||
| 8 | #include <functional> | ||
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | #include <string> | 10 | #include <string> |
| 10 | #include <unordered_map> | 11 | #include <unordered_map> |
| @@ -38,7 +39,8 @@ class SyncpointManager; | |||
| 38 | 39 | ||
| 39 | namespace Devices { | 40 | namespace Devices { |
| 40 | class nvdevice; | 41 | class nvdevice; |
| 41 | } | 42 | class nvhost_ctrl; |
| 43 | } // namespace Devices | ||
| 42 | 44 | ||
| 43 | class Module; | 45 | class Module; |
| 44 | 46 | ||
| @@ -47,47 +49,19 @@ public: | |||
| 47 | EventInterface(Module& module_); | 49 | EventInterface(Module& module_); |
| 48 | ~EventInterface(); | 50 | ~EventInterface(); |
| 49 | 51 | ||
| 50 | // Mask representing registered events | 52 | void RegisterForSignal(Devices::nvhost_ctrl*); |
| 51 | u64 events_mask{}; | 53 | void UnregisterForSignal(Devices::nvhost_ctrl*); |
| 52 | // Each kernel event associated to an NV event | ||
| 53 | std::array<Kernel::KEvent*, MaxNvEvents> events{}; | ||
| 54 | // The status of the current NVEvent | ||
| 55 | std::array<std::atomic<EventState>, MaxNvEvents> status{}; | ||
| 56 | // Tells if an NVEvent is registered or not | ||
| 57 | std::array<bool, MaxNvEvents> registered{}; | ||
| 58 | // Tells the NVEvent that it has failed. | ||
| 59 | std::array<u32, MaxNvEvents> fails{}; | ||
| 60 | // When an NVEvent is waiting on GPU interrupt, this is the sync_point | ||
| 61 | // associated with it. | ||
| 62 | std::array<u32, MaxNvEvents> assigned_syncpt{}; | ||
| 63 | // This is the value of the GPU interrupt for which the NVEvent is waiting | ||
| 64 | // for. | ||
| 65 | std::array<u32, MaxNvEvents> assigned_value{}; | ||
| 66 | // Constant to denote an unasigned syncpoint. | ||
| 67 | static constexpr u32 unassigned_syncpt = 0xFFFFFFFF; | ||
| 68 | |||
| 69 | bool IsBeingUsed(u32 event_id) { | ||
| 70 | const auto current_status = status[event_id].load(std::memory_order_acquire); | ||
| 71 | return current_status == EventState::Waiting || current_status == EventState::Cancelling || | ||
| 72 | current_status == EventState::Signalling; | ||
| 73 | } | ||
| 74 | |||
| 75 | std::unique_lock<std::mutex> Lock(); | ||
| 76 | |||
| 77 | void Signal(u32 event_id); | ||
| 78 | |||
| 79 | void Create(u32 event_id); | ||
| 80 | 54 | ||
| 81 | void Free(u32 event_id); | 55 | void Signal(u32 syncpoint_id, u32 value); |
| 82 | 56 | ||
| 83 | u32 FindFreeEvent(u32 syncpoint_id); | 57 | Kernel::KEvent* CreateEvent(std::string name); |
| 84 | 58 | ||
| 85 | Kernel::KEvent* CreateNonCtrlEvent(std::string name); | 59 | void FreeEvent(Kernel::KEvent* event); |
| 86 | 60 | ||
| 87 | private: | 61 | private: |
| 88 | std::mutex events_mutex; | ||
| 89 | Module& module; | 62 | Module& module; |
| 90 | std::vector<Kernel::KEvent*> basic_events; | 63 | std::mutex guard; |
| 64 | std::list<Devices::nvhost_ctrl*> on_signal; | ||
| 91 | }; | 65 | }; |
| 92 | 66 | ||
| 93 | class Module final { | 67 | class Module final { |
| @@ -97,9 +71,9 @@ public: | |||
| 97 | 71 | ||
| 98 | /// Returns a pointer to one of the available devices, identified by its name. | 72 | /// Returns a pointer to one of the available devices, identified by its name. |
| 99 | template <typename T> | 73 | template <typename T> |
| 100 | std::shared_ptr<T> GetDevice(const std::string& name) { | 74 | std::shared_ptr<T> GetDevice(DeviceFD fd) { |
| 101 | auto itr = devices.find(name); | 75 | auto itr = open_files.find(fd); |
| 102 | if (itr == devices.end()) | 76 | if (itr == open_files.end()) |
| 103 | return nullptr; | 77 | return nullptr; |
| 104 | return std::static_pointer_cast<T>(itr->second); | 78 | return std::static_pointer_cast<T>(itr->second); |
| 105 | } | 79 | } |
| @@ -132,8 +106,9 @@ private: | |||
| 132 | /// Id to use for the next open file descriptor. | 106 | /// Id to use for the next open file descriptor. |
| 133 | DeviceFD next_fd = 1; | 107 | DeviceFD next_fd = 1; |
| 134 | 108 | ||
| 109 | using FilesContainerType = std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>>; | ||
| 135 | /// Mapping of file descriptors to the devices they reference. | 110 | /// Mapping of file descriptors to the devices they reference. |
| 136 | std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files; | 111 | FilesContainerType open_files; |
| 137 | 112 | ||
| 138 | /// Mapping of device node names to their implementation. | 113 | /// Mapping of device node names to their implementation. |
| 139 | std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; | 114 | std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; |
| @@ -147,6 +122,7 @@ private: | |||
| 147 | 122 | ||
| 148 | void CreateEvent(u32 event_id); | 123 | void CreateEvent(u32 event_id); |
| 149 | void FreeEvent(u32 event_id); | 124 | void FreeEvent(u32 event_id); |
| 125 | std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders; | ||
| 150 | }; | 126 | }; |
| 151 | 127 | ||
| 152 | /// Registers all NVDRV services with the specified service manager. | 128 | /// Registers all NVDRV services with the specified service manager. |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 4246e5e25..8c3013f83 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -105,10 +105,15 @@ NVFlinger::~NVFlinger() { | |||
| 105 | display.GetLayer(layer).Core().NotifyShutdown(); | 105 | display.GetLayer(layer).Core().NotifyShutdown(); |
| 106 | } | 106 | } |
| 107 | } | 107 | } |
| 108 | |||
| 109 | if (nvdrv) { | ||
| 110 | nvdrv->Close(disp_fd); | ||
| 111 | } | ||
| 108 | } | 112 | } |
| 109 | 113 | ||
| 110 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { | 114 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { |
| 111 | nvdrv = std::move(instance); | 115 | nvdrv = std::move(instance); |
| 116 | disp_fd = nvdrv->Open("/dev/nvdisp_disp0"); | ||
| 112 | } | 117 | } |
| 113 | 118 | ||
| 114 | std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { | 119 | std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { |
| @@ -276,7 +281,7 @@ void NVFlinger::Compose() { | |||
| 276 | // Now send the buffer to the GPU for drawing. | 281 | // Now send the buffer to the GPU for drawing. |
| 277 | // TODO(Subv): Support more than just disp0. The display device selection is probably based | 282 | // TODO(Subv): Support more than just disp0. The display device selection is probably based |
| 278 | // on which display we're drawing (Default, Internal, External, etc) | 283 | // on which display we're drawing (Default, Internal, External, etc) |
| 279 | auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); | 284 | auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); |
| 280 | ASSERT(nvdisp); | 285 | ASSERT(nvdisp); |
| 281 | 286 | ||
| 282 | Common::Rectangle<int> crop_rect{ | 287 | Common::Rectangle<int> crop_rect{ |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 3bbe5d92b..b62615de2 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -116,6 +116,7 @@ private: | |||
| 116 | void SplitVSync(std::stop_token stop_token); | 116 | void SplitVSync(std::stop_token stop_token); |
| 117 | 117 | ||
| 118 | std::shared_ptr<Nvidia::Module> nvdrv; | 118 | std::shared_ptr<Nvidia::Module> nvdrv; |
| 119 | s32 disp_fd; | ||
| 119 | 120 | ||
| 120 | std::list<VI::Display> displays; | 121 | std::list<VI::Display> displays; |
| 121 | 122 | ||