Skip to content

Commit 26846be

Browse files
author
N3xoX1
committed
add HostSyncpointRegisterAction
1 parent b93e9b7 commit 26846be

9 files changed

Lines changed: 123 additions & 22 deletions

File tree

src/nxemu-module-spec/base.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
enum
1818
{
1919
MODULE_LOADER_SPECS_VERSION = 0x0106,
20-
MODULE_VIDEO_SPECS_VERSION = 0x0105,
20+
MODULE_VIDEO_SPECS_VERSION = 0x0106,
2121
MODULE_CPU_SPECS_VERSION = 0x0102,
2222
MODULE_OPERATING_SYSTEM_SPECS_VERSION = 0x0106,
2323
};

src/nxemu-module-spec/video.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ __interface IChannelState
3636
};
3737

3838
typedef void (*DeviceMemoryOperation)(uint64_t device_address, void* user_data);
39+
typedef void (*HostActionCallback)(uint32_t slot, void * userData);
3940

4041
__interface IVideo
4142
{
@@ -53,6 +54,7 @@ __interface IVideo
5354
void ApplyOpOnDeviceMemoryPointer(const uint8_t * pointer, uint32_t * scratchBuffer, size_t scratchBufferSize, DeviceMemoryOperation operation, void * userData) = 0;
5455
bool OnCPUWrite(uint64_t addr, uint64_t size) = 0;
5556
uint32_t HostSyncpointValue(uint32_t id) = 0;
57+
uint32_t HostSyncpointRegisterAction(uint32_t fence_id, uint32_t target_value, HostActionCallback operation, uint32_t slot, void * userData) = 0;
5658
};
5759

5860
EXPORT IVideo * CALL CreateVideo(IRenderWindow & RenderWindow, ISwitchSystem & System);

src/nxemu-os/core/core.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,14 @@ void System::SetShuttingDown(bool shutting_down) {
270270
impl->SetShuttingDown(shutting_down);
271271
}
272272

273+
std::unique_lock<std::mutex> System::StallApplication() {
274+
return impl->StallApplication();
275+
}
276+
277+
void System::UnstallApplication() {
278+
impl->UnstallApplication();
279+
}
280+
273281
bool System::IsPoweredOn() const {
274282
return impl->is_powered_on.load(std::memory_order::relaxed);
275283
}

src/nxemu-os/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,76 @@ NvResult nvhost_ctrl::IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_a
124124
return NvResult::Success;
125125
}
126126

127-
UNIMPLEMENTED();
127+
//auto& host1x_syncpoint_manager = system.Host1x().GetSyncpointManager();
128+
const u32 target_value = params.fence.value;
129+
130+
auto lock = NvEventsLock();
131+
132+
u32 slot = [&]() {
133+
if (is_allocation) {
134+
params.value.raw = 0;
135+
return FindFreeNvEvent(fence_id);
136+
} else {
137+
return params.value.raw;
138+
}
139+
}();
140+
141+
must_unmark_fail = false;
142+
143+
const auto check_failing = [&]() {
144+
if (events[slot].fails > 2) {
145+
{
146+
auto lk = system.StallApplication();
147+
__debugbreak();
148+
//host1x_syncpoint_manager.WaitHost(fence_id, target_value);
149+
system.UnstallApplication();
150+
}
151+
params.value.raw = target_value;
152+
return true;
153+
}
154+
return false;
155+
};
156+
157+
if (slot >= MaxNvEvents) {
158+
return NvResult::BadParameter;
159+
}
160+
161+
if (params.timeout == 0) {
162+
if (check_failing()) {
163+
events[slot].fails = 0;
164+
return NvResult::Success;
165+
}
166+
return NvResult::Timeout;
167+
}
168+
169+
auto& event = events[slot];
170+
171+
if (!event.registered) {
172+
return NvResult::BadParameter;
173+
}
174+
175+
if (event.IsBeingUsed()) {
176+
return NvResult::BadParameter;
177+
}
178+
179+
if (check_failing()) {
180+
event.fails = 0;
181+
return NvResult::Success;
182+
}
183+
184+
params.value.raw = 0;
185+
186+
event.status.store(EventState::Waiting, std::memory_order_release);
187+
event.assigned_syncpt = fence_id;
188+
event.assigned_value = target_value;
189+
if (is_allocation) {
190+
params.value.syncpoint_id_for_allocation.Assign(static_cast<u16>(fence_id));
191+
params.value.event_allocated.Assign(1);
192+
} else {
193+
params.value.syncpoint_id.Assign(fence_id);
194+
}
195+
params.value.raw |= slot;
196+
event.wait_handle = system.GetVideo().HostSyncpointRegisterAction(fence_id, target_value, HostActionCallback, slot, this);
128197
return NvResult::Timeout;
129198
}
130199

@@ -281,4 +350,15 @@ u32 nvhost_ctrl::FindFreeNvEvent(u32 syncpoint_id) {
281350
return 0;
282351
}
283352

353+
void nvhost_ctrl::HostActionCallback(uint32_t slot, void * userData)
354+
{
355+
nvhost_ctrl & impl = *((nvhost_ctrl*)userData);
356+
auto& event_ = impl.events[slot];
357+
if (event_.status.exchange(EventState::Signalling, std::memory_order_acq_rel) ==
358+
EventState::Waiting) {
359+
event_.kevent->Signal();
360+
}
361+
event_.status.store(EventState::Signalled, std::memory_order_release);
362+
}
363+
284364
} // namespace Service::Nvidia::Devices

src/nxemu-os/core/hle/service/nvdrv/devices/nvhost_ctrl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ class nvhost_ctrl final : public nvdevice {
7575
// Tells if an NVEvent is registered or not
7676
bool registered{};
7777

78+
// Used for waiting on a syncpoint & canceling it.
79+
uint32_t wait_handle{};
80+
7881
bool IsBeingUsed() const {
7982
const auto current_status = status.load(std::memory_order_acquire);
8083
return current_status == EventState::Waiting ||
@@ -191,6 +194,8 @@ class nvhost_ctrl final : public nvdevice {
191194

192195
NvResult FreeEvent(u32 slot);
193196

197+
static void HostActionCallback(uint32_t slot, void * userData);
198+
194199
EventInterface& events_interface;
195200
NvCore::Container& core;
196201
NvCore::SyncpointManager& syncpoint_manager;

src/nxemu-video/video_manager.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,10 @@ uint32_t VideoManager::HostSyncpointValue(uint32_t id)
158158
{
159159
return impl->m_host1x->GetSyncpointManager().GetHostSyncpointValue(id);
160160
}
161+
162+
uint32_t VideoManager::HostSyncpointRegisterAction(uint32_t fence_id, uint32_t target_value, HostActionCallback operation, uint32_t slot, void* userData)
163+
{
164+
return impl->m_host1x->GetSyncpointManager().RegisterHostAction(fence_id, target_value, [operation, userData, slot]() {
165+
operation(slot, userData);
166+
});
167+
}

src/nxemu-video/video_manager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class VideoManager :
3131
void ApplyOpOnDeviceMemoryPointer(const uint8_t* pointer, uint32_t* scratchBuffer, size_t scratchBufferSize, DeviceMemoryOperation operation, void* userData) override;
3232
bool OnCPUWrite(uint64_t addr, uint64_t size) override;
3333
uint32_t HostSyncpointValue(uint32_t id) override;
34+
uint32_t HostSyncpointRegisterAction(uint32_t fence_id, uint32_t target_value, HostActionCallback operation, uint32_t slot, void * userData) override;
3435

3536
private:
3637
VideoManager() = delete;

src/yuzu_video_core/host1x/syncpoint_manager.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Host1x {
1010

1111
MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
1212

13-
SyncpointManager::ActionHandle SyncpointManager::RegisterAction(
13+
uint32_t SyncpointManager::RegisterAction(
1414
std::atomic<u32>& syncpoint, std::list<RegisteredAction>& action_storage, u32 expected_value,
1515
std::function<void()>&& action) {
1616
if (syncpoint.load(std::memory_order_acquire) >= expected_value) {
@@ -30,30 +30,27 @@ SyncpointManager::ActionHandle SyncpointManager::RegisterAction(
3030
}
3131
++it;
3232
}
33-
return action_storage.emplace(it, expected_value, std::move(action));
33+
u32 action_id = next_action_id.fetch_add(1);
34+
action_storage.emplace(it, expected_value, action_id, std::move(action));
35+
return action_id;
3436
}
3537

3638
void SyncpointManager::DeregisterAction(std::list<RegisteredAction>& action_storage,
37-
const ActionHandle& handle) {
39+
uint32_t handle) {
3840
std::unique_lock lk(guard);
39-
40-
// We want to ensure the iterator still exists prior to erasing it
41-
// Otherwise, if an invalid iterator was passed in then it could lead to UB
42-
// It is important to avoid UB in that case since the deregister isn't called from a locked
43-
// context
4441
for (auto it = action_storage.begin(); it != action_storage.end(); it++) {
45-
if (it == handle) {
42+
if (it->action_id == handle) {
4643
action_storage.erase(it);
4744
return;
4845
}
4946
}
5047
}
5148

52-
void SyncpointManager::DeregisterGuestAction(u32 syncpoint_id, const ActionHandle& handle) {
49+
void SyncpointManager::DeregisterGuestAction(u32 syncpoint_id, uint32_t handle) {
5350
DeregisterAction(guest_action_storage[syncpoint_id], handle);
5451
}
5552

56-
void SyncpointManager::DeregisterHostAction(u32 syncpoint_id, const ActionHandle& handle) {
53+
void SyncpointManager::DeregisterHostAction(u32 syncpoint_id, uint32_t handle) {
5754
DeregisterAction(host_action_storage[syncpoint_id], handle);
5855
}
5956

src/yuzu_video_core/host1x/syncpoint_manager.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,28 @@ class SyncpointManager {
2727
}
2828

2929
struct RegisteredAction {
30-
explicit RegisteredAction(u32 expected_value_, std::function<void()>&& action_)
31-
: expected_value{expected_value_}, action{std::move(action_)} {}
30+
explicit RegisteredAction(u32 expected_value_, u32 action_id_, std::function<void()>&& action_)
31+
: expected_value{expected_value_}, action_id{ action_id_}, action{std::move(action_)} {}
32+
u32 action_id;
3233
u32 expected_value;
3334
std::function<void()> action;
3435
};
35-
using ActionHandle = std::list<RegisteredAction>::iterator;
3636

3737
template <typename Func>
38-
ActionHandle RegisterGuestAction(u32 syncpoint_id, u32 expected_value, Func&& action) {
38+
uint32_t RegisterGuestAction(u32 syncpoint_id, u32 expected_value, Func&& action) {
3939
return RegisterAction(syncpoints_guest[syncpoint_id], guest_action_storage[syncpoint_id],
4040
expected_value, std::move(action));
4141
}
4242

4343
template <typename Func>
44-
ActionHandle RegisterHostAction(u32 syncpoint_id, u32 expected_value, Func&& action) {
44+
uint32_t RegisterHostAction(u32 syncpoint_id, u32 expected_value, Func&& action) {
4545
return RegisterAction(syncpoints_host[syncpoint_id], host_action_storage[syncpoint_id],
4646
expected_value, std::move(action));
4747
}
4848

49-
void DeregisterGuestAction(u32 syncpoint_id, const ActionHandle& handle);
49+
void DeregisterGuestAction(u32 syncpoint_id, uint32_t handle);
5050

51-
void DeregisterHostAction(u32 syncpoint_id, const ActionHandle& handle);
51+
void DeregisterHostAction(u32 syncpoint_id, uint32_t handle);
5252

5353
void IncrementGuest(u32 syncpoint_id);
5454

@@ -70,11 +70,11 @@ class SyncpointManager {
7070
void Increment(std::atomic<u32>& syncpoint, std::condition_variable& wait_cv,
7171
std::list<RegisteredAction>& action_storage);
7272

73-
ActionHandle RegisterAction(std::atomic<u32>& syncpoint,
73+
uint32_t RegisterAction(std::atomic<u32>& syncpoint,
7474
std::list<RegisteredAction>& action_storage, u32 expected_value,
7575
std::function<void()>&& action);
7676

77-
void DeregisterAction(std::list<RegisteredAction>& action_storage, const ActionHandle& handle);
77+
void DeregisterAction(std::list<RegisteredAction>& action_storage, uint32_t handle);
7878

7979
void Wait(std::atomic<u32>& syncpoint, std::condition_variable& wait_cv, u32 expected_value);
8080

@@ -83,6 +83,7 @@ class SyncpointManager {
8383
std::array<std::atomic<u32>, NUM_MAX_SYNCPOINTS> syncpoints_guest{};
8484
std::array<std::atomic<u32>, NUM_MAX_SYNCPOINTS> syncpoints_host{};
8585

86+
std::atomic<uint32_t> next_action_id{ 1 };
8687
std::array<std::list<RegisteredAction>, NUM_MAX_SYNCPOINTS> guest_action_storage;
8788
std::array<std::list<RegisteredAction>, NUM_MAX_SYNCPOINTS> host_action_storage;
8889

0 commit comments

Comments
 (0)