mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 07:31:50 +01:00
Add locking to nvhost-ctrl syncpoint events and sync with switchbrew
NvHostEvents were renamed to SyncpointEvents which is a much clearer name that more accurately describes them. Locking is needed as IOCTLs can be called asynchronously and so event registration and signalling can race.
This commit is contained in:
parent
c282276b74
commit
78cdb1eeb4
@ -1,5 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
// Copyright © 2019-2020 Ryujinx Team and Contributors
|
||||||
|
|
||||||
#include <gpu.h>
|
#include <gpu.h>
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
@ -7,75 +8,102 @@
|
|||||||
#include "nvhost_ctrl.h"
|
#include "nvhost_ctrl.h"
|
||||||
|
|
||||||
namespace skyline::service::nvdrv::device {
|
namespace skyline::service::nvdrv::device {
|
||||||
NvHostEvent::NvHostEvent(const DeviceState &state) : event(std::make_shared<type::KEvent>(state, false)) {}
|
SyncpointEvent::SyncpointEvent(const DeviceState &state) : event(std::make_shared<type::KEvent>(state, false)) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Metadata about a syncpoint event, used by QueryEvent and SyncpointEventWait
|
||||||
|
*/
|
||||||
|
union SyncpointEventValue {
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u8 _pad0_ : 4;
|
||||||
|
u32 syncpointIdAsync : 28;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
union {
|
||||||
|
u8 eventSlotAsync;
|
||||||
|
u16 eventSlotNonAsync;
|
||||||
|
};
|
||||||
|
u16 syncpointIdNonAsync : 12;
|
||||||
|
bool nonAsync : 1;
|
||||||
|
u8 _pad12_ : 3;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SyncpointEventValue) == sizeof(u32));
|
||||||
|
|
||||||
|
void SyncpointEvent::Signal() {
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
|
||||||
void NvHostEvent::Signal() {
|
|
||||||
auto oldState{state};
|
auto oldState{state};
|
||||||
state = State::Signalling;
|
state = State::Signalling;
|
||||||
|
|
||||||
// This is to ensure that the HOS event isn't signalled when the nvhost event is cancelled
|
// We should only signal the KEvent if the event is actively being waited on
|
||||||
if (oldState == State::Waiting)
|
if (oldState == State::Waiting)
|
||||||
event->Signal();
|
event->Signal();
|
||||||
|
|
||||||
state = State::Signalled;
|
state = State::Signalled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NvHostEvent::Cancel(const std::shared_ptr<gpu::GPU> &gpuState) {
|
void SyncpointEvent::Cancel(const std::shared_ptr<gpu::GPU> &gpuState) {
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
|
||||||
gpuState->syncpoints.at(fence.id).DeregisterWaiter(waiterId);
|
gpuState->syncpoints.at(fence.id).DeregisterWaiter(waiterId);
|
||||||
Signal();
|
Signal();
|
||||||
event->ResetSignal();
|
event->ResetSignal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NvHostEvent::Wait(const std::shared_ptr<gpu::GPU> &gpuState, const Fence &fence) {
|
void SyncpointEvent::Wait(const std::shared_ptr<gpu::GPU> &gpuState, const Fence &fence) {
|
||||||
waiterId = gpuState->syncpoints.at(fence.id).RegisterWaiter(fence.value, [this] { Signal(); });
|
std::lock_guard lock(mutex);
|
||||||
|
|
||||||
// If waiter ID is zero then the fence has already been hit and was signalled in the call to RegisterWaiter
|
this->fence = fence;
|
||||||
if (waiterId) {
|
state = State::Waiting;
|
||||||
this->fence = fence;
|
waiterId = gpuState->syncpoints.at(fence.id).RegisterWaiter(fence.value, [this] { Signal(); });
|
||||||
state = State::Waiting;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NvHostCtrl::NvHostCtrl(const DeviceState &state) : NvDevice(state) {}
|
NvHostCtrl::NvHostCtrl(const DeviceState &state) : NvDevice(state) {}
|
||||||
|
|
||||||
u32 NvHostCtrl::FindFreeEvent(u32 syncpointId) {
|
u32 NvHostCtrl::FindFreeSyncpointEvent(u32 syncpointId) {
|
||||||
u32 eventIndex{constant::NvHostEventCount}; //!< Holds the index of the last populated event in the event array
|
u32 eventSlot{constant::NvHostEventCount}; //!< Holds the slot of the last populated event in the event array
|
||||||
u32 freeIndex{constant::NvHostEventCount}; //!< Holds the index of the first unused event id
|
u32 freeSlot{constant::NvHostEventCount}; //!< Holds the slot of the first unused event id
|
||||||
|
std::lock_guard lock(syncpointEventMutex);
|
||||||
|
|
||||||
for (u32 i{}; i < constant::NvHostEventCount; i++) {
|
for (u32 i{}; i < constant::NvHostEventCount; i++) {
|
||||||
if (events[i]) {
|
if (syncpointEvents[i]) {
|
||||||
const auto &event{*events[i]};
|
auto event{syncpointEvents[i]};
|
||||||
|
|
||||||
if (event.state == NvHostEvent::State::Cancelled || event.state == NvHostEvent::State::Available || event.state == NvHostEvent::State::Signalled) {
|
if (event->state == SyncpointEvent::State::Cancelled || event->state == SyncpointEvent::State::Available || event->state == SyncpointEvent::State::Signalled) {
|
||||||
eventIndex = i;
|
eventSlot = i;
|
||||||
|
|
||||||
// This event is already attached to the requested syncpoint, so use it
|
// This event is already attached to the requested syncpoint, so use it
|
||||||
if (event.fence.id == syncpointId)
|
if (event->fence.id == syncpointId)
|
||||||
return eventIndex;
|
return eventSlot;
|
||||||
}
|
}
|
||||||
} else if (freeIndex == constant::NvHostEventCount) {
|
} else if (freeSlot == constant::NvHostEventCount) {
|
||||||
freeIndex = i;
|
freeSlot = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use an unused event if possible
|
// Use an unused event if possible
|
||||||
if (freeIndex < constant::NvHostEventCount) {
|
if (freeSlot < constant::NvHostEventCount) {
|
||||||
events.at(freeIndex) = static_cast<const std::optional<NvHostEvent>>(NvHostEvent(state));
|
syncpointEvents[eventSlot] = std::make_shared<SyncpointEvent>(state);
|
||||||
return freeIndex;
|
return freeSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recycle an existing event if all else fails
|
// Recycle an existing event if all else fails
|
||||||
if (eventIndex < constant::NvHostEventCount)
|
if (eventSlot < constant::NvHostEventCount)
|
||||||
return eventIndex;
|
return eventSlot;
|
||||||
|
|
||||||
throw exception("Failed to find a free nvhost event!");
|
throw exception("Failed to find a free nvhost event!");
|
||||||
}
|
}
|
||||||
|
|
||||||
NvStatus NvHostCtrl::EventWaitImpl(span<u8> buffer, bool async) {
|
NvStatus NvHostCtrl::SyncpointEventWaitImpl(span<u8> buffer, bool async) {
|
||||||
struct Data {
|
struct Data {
|
||||||
Fence fence; // In
|
Fence fence; // In
|
||||||
u32 timeout; // In
|
u32 timeout; // In
|
||||||
EventValue value; // InOut
|
SyncpointEventValue value; // InOut
|
||||||
} &data = buffer.as<Data>();
|
} &data = buffer.as<Data>();
|
||||||
|
|
||||||
if (data.fence.id >= constant::MaxHwSyncpointCount)
|
if (data.fence.id >= constant::MaxHwSyncpointCount)
|
||||||
@ -100,22 +128,29 @@ namespace skyline::service::nvdrv::device {
|
|||||||
return NvStatus::Success;
|
return NvStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 userEventId{};
|
u32 eventSlot{};
|
||||||
if (async) {
|
if (async) {
|
||||||
if (data.value.val >= constant::NvHostEventCount || !events.at(data.value.val))
|
if (data.value.val >= constant::NvHostEventCount)
|
||||||
return NvStatus::BadValue;
|
return NvStatus::BadValue;
|
||||||
|
|
||||||
userEventId = data.value.val;
|
eventSlot = data.value.val;
|
||||||
} else {
|
} else {
|
||||||
data.fence.value = 0;
|
data.fence.value = 0;
|
||||||
|
|
||||||
userEventId = FindFreeEvent(data.fence.id);
|
eventSlot = FindFreeSyncpointEvent(data.fence.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &event{*events.at(userEventId)};
|
std::lock_guard lock(syncpointEventMutex);
|
||||||
if (event.state == NvHostEvent::State::Cancelled || event.state == NvHostEvent::State::Available || event.state == NvHostEvent::State::Signalled) {
|
|
||||||
state.logger->Debug("Waiting on nvhost event: {} with fence: {}", userEventId, data.fence.id);
|
auto event{syncpointEvents[eventSlot]};
|
||||||
event.Wait(state.gpu, data.fence);
|
if (!event)
|
||||||
|
return NvStatus::BadValue;
|
||||||
|
|
||||||
|
std::lock_guard eventLock(event->mutex);
|
||||||
|
|
||||||
|
if (event->state == SyncpointEvent::State::Cancelled || event->state == SyncpointEvent::State::Available || event->state == SyncpointEvent::State::Signalled) {
|
||||||
|
state.logger->Debug("Waiting on syncpoint event: {} with fence: ({}, {})", eventSlot, data.fence.id, data.fence.value);
|
||||||
|
event->Wait(state.gpu, data.fence);
|
||||||
|
|
||||||
data.value.val = 0;
|
data.value.val = 0;
|
||||||
|
|
||||||
@ -126,7 +161,7 @@ namespace skyline::service::nvdrv::device {
|
|||||||
data.value.nonAsync = true;
|
data.value.nonAsync = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.value.val |= userEventId;
|
data.value.val |= eventSlot;
|
||||||
|
|
||||||
return NvStatus::Timeout;
|
return NvStatus::Timeout;
|
||||||
} else {
|
} else {
|
||||||
@ -138,53 +173,66 @@ namespace skyline::service::nvdrv::device {
|
|||||||
return NvStatus::BadValue;
|
return NvStatus::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
NvStatus NvHostCtrl::EventSignal(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
NvStatus NvHostCtrl::SyncpointClearEventWait(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||||
auto userEventId{buffer.as<u16>()};
|
auto eventSlot{buffer.as<u16>()};
|
||||||
state.logger->Debug("Signalling nvhost event: {}", userEventId);
|
|
||||||
|
|
||||||
if (userEventId >= constant::NvHostEventCount || !events.at(userEventId))
|
if (eventSlot >= constant::NvHostEventCount)
|
||||||
return NvStatus::BadValue;
|
return NvStatus::BadValue;
|
||||||
|
|
||||||
auto &event{*events.at(userEventId)};
|
std::lock_guard lock(syncpointEventMutex);
|
||||||
|
|
||||||
if (event.state == NvHostEvent::State::Waiting) {
|
auto event{syncpointEvents[eventSlot]};
|
||||||
event.state = NvHostEvent::State::Cancelling;
|
if (!event)
|
||||||
state.logger->Debug("Cancelling waiting nvhost event: {}", userEventId);
|
return NvStatus::BadValue;
|
||||||
event.Cancel(state.gpu);
|
|
||||||
|
std::lock_guard eventLock(event->mutex);
|
||||||
|
|
||||||
|
if (event->state == SyncpointEvent::State::Waiting) {
|
||||||
|
event->state = SyncpointEvent::State::Cancelling;
|
||||||
|
state.logger->Debug("Cancelling waiting syncpoint event: {}", eventSlot);
|
||||||
|
event->Cancel(state.gpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
event.state = NvHostEvent::State::Cancelled;
|
event->state = SyncpointEvent::State::Cancelled;
|
||||||
|
|
||||||
auto driver{nvdrv::driver.lock()};
|
auto driver{nvdrv::driver.lock()};
|
||||||
auto &hostSyncpoint{driver->hostSyncpoint};
|
auto &hostSyncpoint{driver->hostSyncpoint};
|
||||||
hostSyncpoint.UpdateMin(event.fence.id);
|
hostSyncpoint.UpdateMin(event->fence.id);
|
||||||
|
|
||||||
return NvStatus::Success;
|
return NvStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
NvStatus NvHostCtrl::EventWait(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
NvStatus NvHostCtrl::SyncpointEventWait(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||||
return EventWaitImpl(buffer, false);
|
return SyncpointEventWaitImpl(buffer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
NvStatus NvHostCtrl::EventWaitAsync(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
NvStatus NvHostCtrl::SyncpointEventWaitAsync(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||||
return EventWaitImpl(buffer, true);
|
return SyncpointEventWaitImpl(buffer, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
NvStatus NvHostCtrl::EventRegister(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
NvStatus NvHostCtrl::SyncpointRegisterEvent(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||||
auto userEventId{buffer.as<u32>()};
|
auto eventSlot{buffer.as<u32>()};
|
||||||
state.logger->Debug("Registering nvhost event: {}", userEventId);
|
state.logger->Debug("Registering syncpoint event: {}", eventSlot);
|
||||||
|
|
||||||
auto &event{events.at(userEventId)};
|
if (eventSlot >= constant::NvHostEventCount)
|
||||||
|
return NvStatus::BadValue;
|
||||||
|
|
||||||
|
std::lock_guard lock(syncpointEventMutex);
|
||||||
|
|
||||||
|
auto &event{syncpointEvents[eventSlot]};
|
||||||
if (event)
|
if (event)
|
||||||
throw exception("Recreating events is unimplemented");
|
throw exception("Recreating events is unimplemented");
|
||||||
event = NvHostEvent(state);
|
|
||||||
|
event = std::make_shared<SyncpointEvent>(state);
|
||||||
|
|
||||||
return NvStatus::Success;
|
return NvStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<type::KEvent> NvHostCtrl::QueryEvent(u32 eventId) {
|
std::shared_ptr<type::KEvent> NvHostCtrl::QueryEvent(u32 eventId) {
|
||||||
EventValue eventValue{.val = eventId};
|
SyncpointEventValue eventValue{.val = eventId};
|
||||||
const auto &event{events.at(eventValue.nonAsync ? eventValue.eventSlotNonAsync : eventValue.eventSlotAsync)};
|
std::lock_guard lock(syncpointEventMutex);
|
||||||
|
|
||||||
|
auto event{syncpointEvents.at(eventValue.nonAsync ? eventValue.eventSlotNonAsync : eventValue.eventSlotAsync)};
|
||||||
|
|
||||||
if (event && event->fence.id == (eventValue.nonAsync ? eventValue.syncpointIdNonAsync : eventValue.syncpointIdAsync))
|
if (event && event->fence.id == (eventValue.nonAsync ? eventValue.syncpointIdNonAsync : eventValue.syncpointIdAsync))
|
||||||
return event->event;
|
return event->event;
|
||||||
|
@ -13,9 +13,9 @@ namespace skyline {
|
|||||||
|
|
||||||
namespace service::nvdrv::device {
|
namespace service::nvdrv::device {
|
||||||
/**
|
/**
|
||||||
* @brief Events are used to expose fences to the userspace, they can be waited on using an IOCTL or be converted into a native HOS KEvent object that can be waited on just like any other KEvent on the guest
|
* @brief Syncpoint Events are used to expose fences to the userspace, they can be waited on using an IOCTL or be converted into a native HOS KEvent object that can be waited on just like any other KEvent on the guest
|
||||||
*/
|
*/
|
||||||
class NvHostEvent {
|
class SyncpointEvent {
|
||||||
private:
|
private:
|
||||||
u64 waiterId{};
|
u64 waiterId{};
|
||||||
|
|
||||||
@ -31,61 +31,40 @@ namespace skyline {
|
|||||||
Cancelled = 5,
|
Cancelled = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
NvHostEvent(const DeviceState &state);
|
SyncpointEvent(const DeviceState &state);
|
||||||
|
|
||||||
|
std::recursive_mutex mutex; //!< Protects access to the entire event
|
||||||
State state{State::Available};
|
State state{State::Available};
|
||||||
Fence fence{}; //!< The fence that is attached to this event
|
Fence fence{}; //!< The fence that is associated with this syncpoint event
|
||||||
std::shared_ptr<type::KEvent> event{}; //!< Returned by 'QueryEvent'
|
std::shared_ptr<type::KEvent> event{}; //!< Returned by 'QueryEvent'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stops any wait requests on an event and immediately signals it
|
* @brief Removes any wait requests on a syncpoint event and resets its state
|
||||||
*/
|
*/
|
||||||
void Cancel(const std::shared_ptr<gpu::GPU> &gpuState);
|
void Cancel(const std::shared_ptr<gpu::GPU> &gpuState);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Asynchronously waits on an event using the given fence
|
* @brief Asynchronously waits on a syncpoint event using the given fence
|
||||||
*/
|
*/
|
||||||
void Wait(const std::shared_ptr<gpu::GPU> &gpuState, const Fence &fence);
|
void Wait(const std::shared_ptr<gpu::GPU> &gpuState, const Fence &fence);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief NvHostCtrl (/dev/nvhost-ctrl) is used for GPU synchronization
|
* @brief NvHostCtrl (/dev/nvhost-ctrl) is used for NvHost management and synchronisation
|
||||||
* @url https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvhost-ctrl
|
* @url https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvhost-ctrl
|
||||||
*/
|
*/
|
||||||
class NvHostCtrl : public NvDevice {
|
class NvHostCtrl : public NvDevice {
|
||||||
private:
|
private:
|
||||||
/**
|
std::mutex syncpointEventMutex;
|
||||||
* @brief Metadata about an event, it's used by QueryEvent and EventWait
|
std::array<std::shared_ptr<SyncpointEvent>, constant::NvHostEventCount> syncpointEvents{};
|
||||||
*/
|
|
||||||
union EventValue {
|
|
||||||
u32 val;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u8 _pad0_ : 4;
|
|
||||||
u32 syncpointIdAsync : 28;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct {
|
|
||||||
union {
|
|
||||||
u8 eventSlotAsync;
|
|
||||||
u16 eventSlotNonAsync;
|
|
||||||
};
|
|
||||||
u16 syncpointIdNonAsync : 12;
|
|
||||||
bool nonAsync : 1;
|
|
||||||
u8 _pad12_ : 3;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(EventValue) == sizeof(u32));
|
|
||||||
|
|
||||||
std::array<std::optional<NvHostEvent>, constant::NvHostEventCount> events{};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Finds a free event for the given syncpoint id
|
* @brief Finds a free syncpoint event for the given id
|
||||||
* @return The index of the event in the event map
|
* @return The index of the syncpoint event in the map
|
||||||
*/
|
*/
|
||||||
u32 FindFreeEvent(u32 syncpointId);
|
u32 FindFreeSyncpointEvent(u32 syncpointId);
|
||||||
|
|
||||||
NvStatus EventWaitImpl(span<u8> buffer, bool async);
|
NvStatus SyncpointEventWaitImpl(span<u8> buffer, bool async);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NvHostCtrl(const DeviceState &state);
|
NvHostCtrl(const DeviceState &state);
|
||||||
@ -97,37 +76,37 @@ namespace skyline {
|
|||||||
NvStatus GetConfig(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
NvStatus GetConfig(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Signals an NvHost event
|
* @brief Clears a syncpoint event
|
||||||
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_SIGNAL
|
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_SYNCPT_CLEAR_EVENT_WAIT
|
||||||
*/
|
*/
|
||||||
NvStatus EventSignal(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
NvStatus SyncpointClearEventWait(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Synchronously waits on an NvHost event
|
* @brief Synchronously waits on a syncpoint event
|
||||||
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_WAIT
|
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_SYNCPT_EVENT_WAIT
|
||||||
*/
|
*/
|
||||||
NvStatus EventWait(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
NvStatus SyncpointEventWait(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Asynchronously waits on an NvHost event
|
* @brief Asynchronously waits on a syncpoint event
|
||||||
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_WAIT_ASYNC
|
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_SYNCPT_EVENT_WAIT_ASYNC
|
||||||
*/
|
*/
|
||||||
NvStatus EventWaitAsync(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
NvStatus SyncpointEventWaitAsync(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Registers an NvHost event
|
* @brief Registers a syncpoint event
|
||||||
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_REGISTER
|
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_SYNCPT_REGISTER_EVENT
|
||||||
*/
|
*/
|
||||||
NvStatus EventRegister(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
NvStatus SyncpointRegisterEvent(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
||||||
|
|
||||||
std::shared_ptr<type::KEvent> QueryEvent(u32 eventId);
|
std::shared_ptr<type::KEvent> QueryEvent(u32 eventId);
|
||||||
|
|
||||||
NVDEVICE_DECL(
|
NVDEVICE_DECL(
|
||||||
NVFUNC(0x001B, NvHostCtrl, GetConfig),
|
NVFUNC(0x001B, NvHostCtrl, GetConfig),
|
||||||
NVFUNC(0x001C, NvHostCtrl, EventSignal),
|
NVFUNC(0x001C, NvHostCtrl, SyncpointClearEventWait),
|
||||||
NVFUNC(0x001D, NvHostCtrl, EventWait),
|
NVFUNC(0x001D, NvHostCtrl, SyncpointEventWait),
|
||||||
NVFUNC(0x001E, NvHostCtrl, EventWaitAsync),
|
NVFUNC(0x001E, NvHostCtrl, SyncpointEventWaitAsync),
|
||||||
NVFUNC(0x001F, NvHostCtrl, EventRegister)
|
NVFUNC(0x001F, NvHostCtrl, SyncpointRegisterEvent)
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user