diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h index 6fc6c570f..0522c3d8a 100644 --- a/src/core/file_sys/fs.h +++ b/src/core/file_sys/fs.h @@ -85,7 +85,8 @@ enum class FileType { Device, Socket, Epoll, - Resolver + Resolver, + Equeue }; struct File { diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index 25682ada0..326dc2418 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -123,21 +123,23 @@ static inline bool IsValidEventType(Platform::InterruptId id) { static_cast(id) == static_cast(Platform::InterruptId::GfxEop); } -s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) { +s32 PS4_SYSV_ABI sceGnmAddEqEvent(OrbisKernelEqueue eq, u64 id, void* udata) { LOG_TRACE(Lib_GnmDriver, "called"); - if (!eq) { + auto equeue = GetEqueue(eq); + if (!equeue) { return ORBIS_KERNEL_ERROR_EBADF; } EqueueEvent kernel_event{}; kernel_event.event.ident = id; - kernel_event.event.filter = SceKernelEvent::Filter::GraphicsCore; - kernel_event.event.flags = SceKernelEvent::Flags::Add; + kernel_event.event.filter = OrbisKernelEvent::Filter::GraphicsCore; + kernel_event.event.flags = OrbisKernelEvent::Flags::Add; kernel_event.event.fflags = 0; kernel_event.event.data = id; kernel_event.event.udata = udata; - eq->AddEvent(kernel_event); + + equeue->AddEvent(kernel_event); Platform::IrqC::Instance()->Register( static_cast(id), @@ -149,10 +151,11 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) { return; // Event data is expected to be an event type as per sceGnmGetEqEventType. - eq->TriggerEvent(static_cast(id), SceKernelEvent::Filter::GraphicsCore, - reinterpret_cast(id)); + equeue->TriggerEvent(static_cast(id), + OrbisKernelEvent::Filter::GraphicsCore, + reinterpret_cast(id)); }, - eq); + equeue); return ORBIS_OK; } @@ -267,16 +270,17 @@ int PS4_SYSV_ABI sceGnmDebugHardwareStatus() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) { +s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(OrbisKernelEqueue eq, u64 id) { LOG_TRACE(Lib_GnmDriver, "called"); - if (!eq) { + auto equeue = GetEqueue(eq); + if (!equeue) { return ORBIS_KERNEL_ERROR_EBADF; } - eq->RemoveEvent(id, SceKernelEvent::Filter::GraphicsCore); + equeue->RemoveEvent(id, OrbisKernelEvent::Filter::GraphicsCore); - Platform::IrqC::Instance()->Unregister(static_cast(id), eq); + Platform::IrqC::Instance()->Unregister(static_cast(id), equeue); return ORBIS_OK; } @@ -895,7 +899,7 @@ int PS4_SYSV_ABI sceGnmGetDebugTimestamp() { return ORBIS_OK; } -int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev) { +int PS4_SYSV_ABI sceGnmGetEqEventType(const OrbisKernelEvent* ev) { LOG_TRACE(Lib_GnmDriver, "called"); return sceKernelGetEventData(ev); } diff --git a/src/core/libraries/gnmdriver/gnmdriver.h b/src/core/libraries/gnmdriver/gnmdriver.h index 5f3462dd9..9f5fde628 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.h +++ b/src/core/libraries/gnmdriver/gnmdriver.h @@ -14,7 +14,7 @@ namespace Libraries::GnmDriver { using namespace Kernel; -s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata); +s32 PS4_SYSV_ABI sceGnmAddEqEvent(OrbisKernelEqueue eq, u64 id, void* udata); int PS4_SYSV_ABI sceGnmAreSubmitsAllowed(); int PS4_SYSV_ABI sceGnmBeginWorkload(u32 workload_stream, u64* workload); s32 PS4_SYSV_ABI sceGnmComputeWaitOnAddress(u32* cmdbuf, u32 size, uintptr_t addr, u32 mask, @@ -31,7 +31,7 @@ int PS4_SYSV_ABI sceGnmDebuggerSetAddressWatch(); int PS4_SYSV_ABI sceGnmDebuggerWriteGds(); int PS4_SYSV_ABI sceGnmDebuggerWriteSqIndirectRegister(); int PS4_SYSV_ABI sceGnmDebugHardwareStatus(); -s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id); +s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(OrbisKernelEqueue eq, u64 id); int PS4_SYSV_ABI sceGnmDestroyWorkloadStream(); void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw); void PS4_SYSV_ABI sceGnmDingDongForWorkload(u32 gnm_vqid, u32 next_offs_dw, u64 workload_id); @@ -87,7 +87,7 @@ int PS4_SYSV_ABI sceGnmGetCoredumpMode(); int PS4_SYSV_ABI sceGnmGetCoredumpProtectionFaultTimestamp(); int PS4_SYSV_ABI sceGnmGetDbgGcHandle(); int PS4_SYSV_ABI sceGnmGetDebugTimestamp(); -int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev); +int PS4_SYSV_ABI sceGnmGetEqEventType(const OrbisKernelEvent* ev); int PS4_SYSV_ABI sceGnmGetEqTimeStamp(); int PS4_SYSV_ABI sceGnmGetGpuBlockStatus(); u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency(); diff --git a/src/core/libraries/kernel/equeue.cpp b/src/core/libraries/kernel/equeue.cpp index 9291c0a1a..68a6dae24 100644 --- a/src/core/libraries/kernel/equeue.cpp +++ b/src/core/libraries/kernel/equeue.cpp @@ -2,12 +2,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include "common/assert.h" #include "common/debug.h" #include "common/logging/log.h" +#include "common/singleton.h" +#include "core/file_sys/fs.h" #include "core/libraries/kernel/equeue.h" +#include "core/libraries/kernel/kernel.h" #include "core/libraries/kernel/orbis_error.h" +#include "core/libraries/kernel/posix_error.h" #include "core/libraries/kernel/time.h" #include "core/libraries/libs.h" @@ -16,59 +21,104 @@ namespace Libraries::Kernel { extern boost::asio::io_context io_context; extern void KernelSignalRequest(); +static std::unordered_map kqueues; static constexpr auto HrTimerSpinlockThresholdNs = 1200000u; +EqueueInternal* GetEqueue(OrbisKernelEqueue eq) { + if (!kqueues.contains(eq)) { + return nullptr; + } + return kqueues[eq]; +} + +static void HrTimerCallback(OrbisKernelEqueue eq, const OrbisKernelEvent& kevent) { + if (kqueues.contains(eq)) { + kqueues[eq]->TriggerEvent(kevent.ident, OrbisKernelEvent::Filter::HrTimer, kevent.udata); + } +} + +static void TimerCallback(OrbisKernelEqueue eq, const OrbisKernelEvent& kevent) { + if (kqueues.contains(eq) && kqueues[eq]->EventExists(kevent.ident, kevent.filter)) { + kqueues[eq]->TriggerEvent(kevent.ident, OrbisKernelEvent::Filter::Timer, kevent.udata); + if (!(kevent.flags & OrbisKernelEvent::Flags::OneShot)) { + // Reschedule the event for its next period. + kqueues[eq]->ScheduleEvent(kevent.ident, kevent.filter, TimerCallback); + } + } +} + // Events are uniquely identified by id and filter. bool EqueueInternal::AddEvent(EqueueEvent& event) { - std::scoped_lock lock{m_mutex}; + { + std::scoped_lock lock{m_mutex}; - // Calculate timer interval - event.time_added = std::chrono::steady_clock::now(); - if (event.event.filter == SceKernelEvent::Filter::Timer || - event.event.filter == SceKernelEvent::Filter::HrTimer) { - // Set timer interval - event.timer_interval = std::chrono::nanoseconds(event.event.data); + // Calculate timer interval + event.time_added = std::chrono::steady_clock::now(); + if (event.event.filter == OrbisKernelEvent::Filter::Timer) { + // Set timer interval, this is stored in milliseconds for timers. + event.timer_interval = std::chrono::milliseconds(event.event.data); + } else if (event.event.filter == OrbisKernelEvent::Filter::HrTimer) { + // Retrieve inputted time, this is stored in the bintime format. + OrbisKernelBintime* time = reinterpret_cast(event.event.data); + + // Convert the bintime format to a timespec. + OrbisKernelTimespec ts; + ts.tv_sec = time->sec; + ts.tv_nsec = (1000000000 * (time->frac >> 32)) >> 32; + + // Then use the timespec to set the timer interval. + event.timer_interval = std::chrono::nanoseconds(ts.tv_nsec + ts.tv_sec * 1000000000); + } + + // First, check if there's already an event with the same id and filter. + u64 id = event.event.ident; + OrbisKernelEvent::Filter filter = event.event.filter; + const auto& find_it = std::ranges::find_if(m_events, [id, filter](auto& ev) { + return ev.event.ident == id && ev.event.filter == filter; + }); + // If there is a duplicate event, we need to update that instead. + if (find_it != m_events.cend()) { + // Specifically, update user data and timer_interval. + // Trigger status and event data should remain intact. + auto& old_event = *find_it; + old_event.timer_interval = event.timer_interval; + old_event.event.udata = event.event.udata; + return true; + } + + // Clear input data from event. + event.event.data = 0; + + // Remove add flag from event + event.event.flags &= ~OrbisKernelEvent::Flags::Add; + + // Clear flag is appended to most event types internally. + if (event.event.filter != OrbisKernelEvent::Filter::User) { + event.event.flags |= OrbisKernelEvent::Flags::Clear; + } + + const auto& it = std::ranges::find(m_events, event); + if (it != m_events.cend()) { + *it = std::move(event); + } else { + m_events.emplace_back(std::move(event)); + } } - // First, check if there's already an event with the same id and filter. - u64 id = event.event.ident; - SceKernelEvent::Filter filter = event.event.filter; - const auto& find_it = std::ranges::find_if(m_events, [id, filter](auto& ev) { - return ev.event.ident == id && ev.event.filter == filter; - }); - // If there is a duplicate event, we need to update that instead. - if (find_it != m_events.cend()) { - // Specifically, update user data and timer_interval. - // Trigger status and event data should remain intact. - auto& old_event = *find_it; - old_event.timer_interval = event.timer_interval; - old_event.event.udata = event.event.udata; - return true; - } - - // Clear input data from event. - event.event.data = 0; - - // Remove add flag from event - event.event.flags &= ~SceKernelEvent::Flags::Add; - - // Clear flag is appended to most event types internally. - if (event.event.filter != SceKernelEvent::Filter::User) { - event.event.flags |= SceKernelEvent::Flags::Clear; - } - - const auto& it = std::ranges::find(m_events, event); - if (it != m_events.cend()) { - *it = std::move(event); - } else { - m_events.emplace_back(std::move(event)); + // Schedule callbacks for timer events + if (event.event.filter == OrbisKernelEvent::Timer) { + return this->ScheduleEvent(event.event.ident, OrbisKernelEvent::Filter::Timer, + TimerCallback); + } else if (event.event.filter == OrbisKernelEvent::HrTimer) { + return this->ScheduleEvent(event.event.ident, OrbisKernelEvent::Filter::HrTimer, + HrTimerCallback); } return true; } bool EqueueInternal::ScheduleEvent(u64 id, s16 filter, - void (*callback)(SceKernelEqueue, const SceKernelEvent&)) { + void (*callback)(OrbisKernelEqueue, const OrbisKernelEvent&)) { std::scoped_lock lock{m_mutex}; const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) { @@ -79,8 +129,8 @@ bool EqueueInternal::ScheduleEvent(u64 id, s16 filter, } const auto& event = *it; - ASSERT(event.event.filter == SceKernelEvent::Filter::Timer || - event.event.filter == SceKernelEvent::Filter::HrTimer); + ASSERT(event.event.filter == OrbisKernelEvent::Filter::Timer || + event.event.filter == OrbisKernelEvent::Filter::HrTimer); if (!it->timer) { it->timer = std::make_unique(io_context, event.timer_interval); @@ -101,7 +151,7 @@ bool EqueueInternal::ScheduleEvent(u64 id, s16 filter, } return; } - callback(this, event_data); + callback(this->m_handle, event_data); }); KernelSignalRequest(); @@ -122,7 +172,7 @@ bool EqueueInternal::RemoveEvent(u64 id, s16 filter) { return has_found; } -int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, const SceKernelUseconds* timo) { +int EqueueInternal::WaitForEvents(OrbisKernelEvent* ev, int num, const OrbisKernelUseconds* timo) { if (timo != nullptr && *timo == 0) { // Effectively acts as a poll; only events that have already // arrived at the time of this function call can be received @@ -152,15 +202,6 @@ int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, const SceKernelUs m_cond.wait_for(lock, std::chrono::microseconds(micros), predicate); } - if (HasSmallTimer()) { - if (count > 0) { - const auto time_waited = std::chrono::duration_cast( - std::chrono::steady_clock::now() - m_events[0].time_added) - .count(); - count = WaitForSmallTimer(ev, num, std::max(0l, long(micros - time_waited))); - } - } - return count; } @@ -170,12 +211,12 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) { std::scoped_lock lock{m_mutex}; for (auto& event : m_events) { if (event.event.ident == ident && event.event.filter == filter) { - if (filter == SceKernelEvent::Filter::VideoOut) { + if (filter == OrbisKernelEvent::Filter::VideoOut) { event.TriggerDisplay(trigger_data); - } else if (filter == SceKernelEvent::Filter::User) { + } else if (filter == OrbisKernelEvent::Filter::User) { event.TriggerUser(trigger_data); - } else if (filter == SceKernelEvent::Filter::Timer || - filter == SceKernelEvent::Filter::HrTimer) { + } else if (filter == OrbisKernelEvent::Filter::Timer || + filter == OrbisKernelEvent::Filter::HrTimer) { event.TriggerTimer(); } else { event.Trigger(trigger_data); @@ -188,15 +229,15 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) { return has_found; } -int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) { +int EqueueInternal::GetTriggeredEvents(OrbisKernelEvent* ev, int num) { int count = 0; for (auto it = m_events.begin(); it != m_events.end();) { if (it->IsTriggered()) { ev[count++] = it->event; - if (it->event.flags & SceKernelEvent::Flags::Clear) { + if (it->event.flags & OrbisKernelEvent::Flags::Clear) { it->Clear(); } - if (it->event.flags & SceKernelEvent::Flags::OneShot) { + if (it->event.flags & OrbisKernelEvent::Flags::OneShot) { it = m_events.erase(it); } else { ++it; @@ -214,10 +255,17 @@ int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) { } bool EqueueInternal::AddSmallTimer(EqueueEvent& ev) { + // Retrieve inputted time, this is stored in the bintime format + OrbisKernelBintime* time = reinterpret_cast(ev.event.data); + OrbisKernelTimespec ts; + ts.tv_sec = time->sec; + ts.tv_nsec = ((1000000000 * (time->frac >> 32)) >> 32); + + // Create the small timer SmallTimer st; st.event = ev.event; st.added = std::chrono::steady_clock::now(); - st.interval = std::chrono::nanoseconds{ev.event.data}; + st.interval = std::chrono::nanoseconds(ts.tv_nsec + ts.tv_sec * 1000000000); { std::scoped_lock lock{m_mutex}; m_small_timers[st.event.ident] = std::move(st); @@ -225,7 +273,7 @@ bool EqueueInternal::AddSmallTimer(EqueueEvent& ev) { return true; } -int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) { +int EqueueInternal::WaitForSmallTimer(OrbisKernelEvent* ev, int num, u32 micros) { ASSERT(num >= 1); auto curr_clock = std::chrono::steady_clock::now(); @@ -266,18 +314,119 @@ bool EqueueInternal::EventExists(u64 id, s16 filter) { return it != m_events.cend(); } -int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) { +s32 PS4_SYSV_ABI posix_kqueue() { + // Reserve a file handle for the kqueue + auto* handles = Common::Singleton::Instance(); + s32 kqueue_handle = handles->CreateHandle(); + auto* kqueue_file = handles->GetFile(kqueue_handle); + kqueue_file->type = Core::FileSys::FileType::Equeue; + + // Plenty of equeue logic uses names to identify queues. + // Create a unique name for the queue we create. + char name[32]; + memset(name, 0, sizeof(name)); + snprintf(name, sizeof(name), "kqueue%i", kqueue_handle); + + // Create the queue + kqueues[kqueue_handle] = new EqueueInternal(kqueue_handle, name); + LOG_INFO(Kernel_Event, "kqueue created with name {}", name); + + // Return handle. + return kqueue_handle; +} + +// Helper method to detect supported filters. +// We don't want to allow adding events we don't handle properly. +bool SupportedEqueueFilter(OrbisKernelEvent::Filter filter) { + return filter == OrbisKernelEvent::Filter::GraphicsCore || + filter == OrbisKernelEvent::Filter::HrTimer || + filter == OrbisKernelEvent::Filter::Timer || filter == OrbisKernelEvent::Filter::User || + filter == OrbisKernelEvent::Filter::VideoOut; +} + +s32 PS4_SYSV_ABI posix_kevent(s32 handle, OrbisKernelEvent* changelist, u64 nchanges, + OrbisKernelEvent* eventlist, u64 nevents, + OrbisKernelTimespec* timeout) { + LOG_INFO(Kernel_Event, "called, eq = {}, nchanges = {}, nevents = {}", handle, nchanges, + nevents); + + // Get the equeue + if (!kqueues.contains(handle)) { + *__Error() = POSIX_EBADF; + return ORBIS_FAIL; + } + auto equeue = kqueues[handle]; + + // First step is to apply all changes in changelist. + for (u64 i = 0; i < nchanges; i++) { + auto event = changelist[i]; + if (!SupportedEqueueFilter(event.filter)) { + LOG_ERROR(Kernel_Event, "Unsupported event filter {}", + magic_enum::enum_name(event.filter)); + continue; + } + + // Check the event flags to determine the appropriate action + if (event.flags & OrbisKernelEvent::Flags::Add) { + // The caller is requesting to add an event. + EqueueEvent internal_event{}; + internal_event.event = event; + if (!equeue->AddEvent(internal_event)) { + // Failed to add event, return error. + *__Error() = POSIX_ENOMEM; + return ORBIS_FAIL; + } + } + + if (event.flags & OrbisKernelEvent::Flags::Delete) { + // The caller is requesting to remove an event. + if (!equeue->RemoveEvent(event.ident, event.filter)) { + // Failed to remove event, return error. + *__Error() = POSIX_ENOENT; + return ORBIS_FAIL; + } + } + + if (event.filter == OrbisKernelEvent::Filter::User && event.fflags == 0x1000000) { + // For user events, this fflags value indicates we need to trigger the event. + if (!equeue->TriggerEvent(event.ident, OrbisKernelEvent::Filter::User, event.udata)) { + *__Error() = POSIX_ENOENT; + return ORBIS_FAIL; + } + } else if (event.fflags != 0) { + // The title is using filter-specific flags. Right now, these are unhandled. + LOG_ERROR(Kernel_Event, "Unhandled fflags {:#x} for event filter {}", event.fflags, + magic_enum::enum_name(event.filter)); + continue; + } + } + + // Now we need to wait on the event list. + s32 count = 0; + if (nevents > 0) { + if (timeout != nullptr) { + OrbisKernelUseconds micros = (timeout->tv_sec * 1000000) + (timeout->tv_nsec / 1000); + count = equeue->WaitForEvents(eventlist, nevents, µs); + } else { + count = equeue->WaitForEvents(eventlist, nevents, nullptr); + } + } + return count; +} + +int PS4_SYSV_ABI sceKernelCreateEqueue(OrbisKernelEqueue* eq, const char* name) { if (eq == nullptr) { LOG_ERROR(Kernel_Event, "Event queue is null!"); return ORBIS_KERNEL_ERROR_EINVAL; } + if (name == nullptr) { LOG_ERROR(Kernel_Event, "Event queue name is null!"); return ORBIS_KERNEL_ERROR_EINVAL; } // Maximum is 32 including null terminator - static constexpr size_t MaxEventQueueNameSize = 32; + static constexpr u64 MaxEventQueueNameSize = 32; if (std::strlen(name) > MaxEventQueueNameSize) { LOG_ERROR(Kernel_Event, "Event queue name exceeds 32 bytes!"); return ORBIS_KERNEL_ERROR_ENAMETOOLONG; @@ -285,29 +434,42 @@ int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) { LOG_INFO(Kernel_Event, "name = {}", name); - *eq = new EqueueInternal(name); + // Reserve a file handle for the kqueue + auto* handles = Common::Singleton::Instance(); + OrbisKernelEqueue kqueue_handle = handles->CreateHandle(); + auto* kqueue_file = handles->GetFile(kqueue_handle); + kqueue_file->type = Core::FileSys::FileType::Equeue; + + // Create the equeue + kqueues[kqueue_handle] = new EqueueInternal(kqueue_handle, name); + *eq = kqueue_handle; + return ORBIS_OK; } -int PS4_SYSV_ABI sceKernelDeleteEqueue(SceKernelEqueue eq) { - if (eq == nullptr) { +int PS4_SYSV_ABI sceKernelDeleteEqueue(OrbisKernelEqueue eq) { + if (!kqueues.contains(eq)) { return ORBIS_KERNEL_ERROR_EBADF; } - delete eq; + auto* handles = Common::Singleton::Instance(); + handles->DeleteHandle(eq); + kqueues.erase(eq); return ORBIS_OK; } -int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out, - SceKernelUseconds* timo) { +int PS4_SYSV_ABI sceKernelWaitEqueue(OrbisKernelEqueue eq, OrbisKernelEvent* ev, int num, int* out, + OrbisKernelUseconds* timo) { HLE_TRACE; - TRACE_HINT(eq->GetName()); - LOG_TRACE(Kernel_Event, "equeue = {} num = {}", eq->GetName(), num); - - if (eq == nullptr) { + if (!kqueues.contains(eq)) { return ORBIS_KERNEL_ERROR_EBADF; } + auto& equeue = kqueues[eq]; + + TRACE_HINT(equeue->GetName()); + LOG_TRACE(Kernel_Event, "equeue = {} num = {}", equeue->GetName(), num); + if (ev == nullptr) { return ORBIS_KERNEL_ERROR_EFAULT; } @@ -317,7 +479,7 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int return ORBIS_KERNEL_ERROR_EINVAL; } - *out = eq->WaitForEvents(ev, num, timo); + *out = equeue->WaitForEvents(ev, num, timo); if (*out == 0) { return ORBIS_KERNEL_ERROR_ETIMEDOUT; @@ -326,13 +488,9 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int return ORBIS_OK; } -static void HrTimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) { - eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata); -} - -s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, OrbisKernelTimespec* ts, +s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(OrbisKernelEqueue eq, int id, OrbisKernelTimespec* ts, void* udata) { - if (eq == nullptr) { + if (!kqueues.contains(eq)) { return ORBIS_KERNEL_ERROR_EBADF; } @@ -340,10 +498,12 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, OrbisKerne EqueueEvent event{}; event.event.ident = id; - event.event.filter = SceKernelEvent::Filter::HrTimer; - event.event.flags = SceKernelEvent::Flags::Add | SceKernelEvent::Flags::OneShot; + event.event.filter = OrbisKernelEvent::Filter::HrTimer; + event.event.flags = OrbisKernelEvent::Flags::Add | OrbisKernelEvent::Flags::OneShot; event.event.fflags = 0; - event.event.data = total_ns; + // Data is stored as the address of a OrbisKernelBintime struct. + OrbisKernelBintime time{ts->tv_sec, ts->tv_nsec * 0x44b82fa09}; + event.event.data = reinterpret_cast(&time); event.event.udata = udata; // HR timers cannot be implemented within the existing event queue architecture due to the @@ -353,146 +513,137 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, OrbisKerne // `HrTimerSpinlockThresholdUs`) and fall back to boost asio timers if the time to tick is // large. Even for large delays, we truncate a small portion to complete the wait // using the spinlock, prioritizing precision. + auto& equeue = kqueues[eq]; if (total_ns < HrTimerSpinlockThresholdNs) { - return eq->AddSmallTimer(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM; + return equeue->AddSmallTimer(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM; } - if (!eq->AddEvent(event) || - !eq->ScheduleEvent(id, SceKernelEvent::Filter::HrTimer, HrTimerCallback)) { + if (!equeue->AddEvent(event)) { return ORBIS_KERNEL_ERROR_ENOMEM; } return ORBIS_OK; } -int PS4_SYSV_ABI sceKernelDeleteHRTimerEvent(SceKernelEqueue eq, int id) { - if (eq == nullptr) { +int PS4_SYSV_ABI sceKernelDeleteHRTimerEvent(OrbisKernelEqueue eq, int id) { + if (!kqueues.contains(eq)) { return ORBIS_KERNEL_ERROR_EBADF; } - if (eq->HasSmallTimer()) { - return eq->RemoveSmallTimer(id) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOENT; + auto& equeue = kqueues[eq]; + if (equeue->HasSmallTimer()) { + return equeue->RemoveSmallTimer(id) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOENT; } else { - return eq->RemoveEvent(id, SceKernelEvent::Filter::HrTimer) ? ORBIS_OK - : ORBIS_KERNEL_ERROR_ENOENT; + return equeue->RemoveEvent(id, OrbisKernelEvent::Filter::HrTimer) + ? ORBIS_OK + : ORBIS_KERNEL_ERROR_ENOENT; } } -static void TimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) { - if (eq->EventExists(kevent.ident, kevent.filter)) { - eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::Timer, kevent.udata); - - if (!(kevent.flags & SceKernelEvent::Flags::OneShot)) { - // Reschedule the event for its next period. - eq->ScheduleEvent(kevent.ident, kevent.filter, TimerCallback); - } - } -} - -int PS4_SYSV_ABI sceKernelAddTimerEvent(SceKernelEqueue eq, int id, SceKernelUseconds usec, +int PS4_SYSV_ABI sceKernelAddTimerEvent(OrbisKernelEqueue eq, int id, OrbisKernelUseconds usec, void* udata) { - if (eq == nullptr) { + if (!kqueues.contains(eq)) { return ORBIS_KERNEL_ERROR_EBADF; } EqueueEvent event{}; event.event.ident = static_cast(id); - event.event.filter = SceKernelEvent::Filter::Timer; - event.event.flags = SceKernelEvent::Flags::Add; + event.event.filter = OrbisKernelEvent::Filter::Timer; + event.event.flags = OrbisKernelEvent::Flags::Add; event.event.fflags = 0; - event.event.data = usec * 1000; + event.event.data = usec / 1000; event.event.udata = udata; - LOG_DEBUG(Kernel_Event, "Added timing event: queue name={}, queue id={}, usec={}, pointer={:x}", - eq->GetName(), event.event.ident, usec, reinterpret_cast(udata)); - - if (!eq->AddEvent(event) || - !eq->ScheduleEvent(id, SceKernelEvent::Filter::Timer, TimerCallback)) { + auto& equeue = kqueues[eq]; + if (!equeue->AddEvent(event)) { return ORBIS_KERNEL_ERROR_ENOMEM; } return ORBIS_OK; } -int PS4_SYSV_ABI sceKernelDeleteTimerEvent(SceKernelEqueue eq, int id) { - if (eq == nullptr) { +int PS4_SYSV_ABI sceKernelDeleteTimerEvent(OrbisKernelEqueue eq, int id) { + if (!kqueues.contains(eq)) { return ORBIS_KERNEL_ERROR_EBADF; } - return eq->RemoveEvent(id, SceKernelEvent::Filter::Timer) ? ORBIS_OK - : ORBIS_KERNEL_ERROR_ENOENT; + return kqueues[eq]->RemoveEvent(id, OrbisKernelEvent::Filter::Timer) + ? ORBIS_OK + : ORBIS_KERNEL_ERROR_ENOENT; } -int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) { - if (eq == nullptr) { +int PS4_SYSV_ABI sceKernelAddUserEvent(OrbisKernelEqueue eq, int id) { + if (!kqueues.contains(eq)) { return ORBIS_KERNEL_ERROR_EBADF; } EqueueEvent event{}; event.event.ident = id; - event.event.filter = SceKernelEvent::Filter::User; + event.event.filter = OrbisKernelEvent::Filter::User; event.event.udata = 0; - event.event.flags = SceKernelEvent::Flags::Add; + event.event.flags = OrbisKernelEvent::Flags::Add; event.event.fflags = 0; event.event.data = 0; - return eq->AddEvent(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM; + return kqueues[eq]->AddEvent(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM; } -int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) { - if (eq == nullptr) { +int PS4_SYSV_ABI sceKernelAddUserEventEdge(OrbisKernelEqueue eq, int id) { + if (!kqueues.contains(eq)) { return ORBIS_KERNEL_ERROR_EBADF; } EqueueEvent event{}; event.event.ident = id; - event.event.filter = SceKernelEvent::Filter::User; + event.event.filter = OrbisKernelEvent::Filter::User; event.event.udata = 0; - event.event.flags = SceKernelEvent::Flags::Add | SceKernelEvent::Flags::Clear; + event.event.flags = OrbisKernelEvent::Flags::Add | OrbisKernelEvent::Flags::Clear; event.event.fflags = 0; event.event.data = 0; - return eq->AddEvent(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM; + return kqueues[eq]->AddEvent(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM; } -void* PS4_SYSV_ABI sceKernelGetEventUserData(const SceKernelEvent* ev) { +void* PS4_SYSV_ABI sceKernelGetEventUserData(const OrbisKernelEvent* ev) { ASSERT(ev); return ev->udata; } -u64 PS4_SYSV_ABI sceKernelGetEventId(const SceKernelEvent* ev) { +u64 PS4_SYSV_ABI sceKernelGetEventId(const OrbisKernelEvent* ev) { return ev->ident; } -int PS4_SYSV_ABI sceKernelTriggerUserEvent(SceKernelEqueue eq, int id, void* udata) { - if (eq == nullptr) { +int PS4_SYSV_ABI sceKernelTriggerUserEvent(OrbisKernelEqueue eq, int id, void* udata) { + if (!kqueues.contains(eq)) { return ORBIS_KERNEL_ERROR_EBADF; } - if (!eq->TriggerEvent(id, SceKernelEvent::Filter::User, udata)) { + if (!kqueues[eq]->TriggerEvent(id, OrbisKernelEvent::Filter::User, udata)) { return ORBIS_KERNEL_ERROR_ENOENT; } return ORBIS_OK; } -int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id) { - if (eq == nullptr) { +int PS4_SYSV_ABI sceKernelDeleteUserEvent(OrbisKernelEqueue eq, int id) { + if (!kqueues.contains(eq)) { return ORBIS_KERNEL_ERROR_EBADF; } - if (!eq->RemoveEvent(id, SceKernelEvent::Filter::User)) { + if (!kqueues[eq]->RemoveEvent(id, OrbisKernelEvent::Filter::User)) { return ORBIS_KERNEL_ERROR_ENOENT; } return ORBIS_OK; } -int PS4_SYSV_ABI sceKernelGetEventFilter(const SceKernelEvent* ev) { +int PS4_SYSV_ABI sceKernelGetEventFilter(const OrbisKernelEvent* ev) { return ev->filter; } -u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev) { +u64 PS4_SYSV_ABI sceKernelGetEventData(const OrbisKernelEvent* ev) { return ev->data; } void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("nh2IFMgKTv8", "libScePosix", 1, "libkernel", posix_kqueue); + LIB_FUNCTION("RW-GEfpnsqg", "libScePosix", 1, "libkernel", posix_kevent); LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", sceKernelCreateEqueue); LIB_FUNCTION("jpFjmgAC5AE", "libkernel", 1, "libkernel", sceKernelDeleteEqueue); LIB_FUNCTION("fzyMKs9kim0", "libkernel", 1, "libkernel", sceKernelWaitEqueue); diff --git a/src/core/libraries/kernel/equeue.h b/src/core/libraries/kernel/equeue.h index 83b4b8689..9b3c73c19 100644 --- a/src/core/libraries/kernel/equeue.h +++ b/src/core/libraries/kernel/equeue.h @@ -22,10 +22,15 @@ namespace Libraries::Kernel { class EqueueInternal; struct EqueueEvent; -using SceKernelUseconds = u32; -using SceKernelEqueue = EqueueInternal*; +struct OrbisKernelBintime { + s64 sec; + s64 frac; +}; -struct SceKernelEvent { +using OrbisKernelUseconds = u32; +using OrbisKernelEqueue = s64; + +struct OrbisKernelEvent { enum Filter : s16 { None = 0, Read = -1, @@ -78,7 +83,7 @@ struct OrbisVideoOutEventData { }; struct EqueueEvent { - SceKernelEvent event; + OrbisKernelEvent event; void* data = nullptr; std::chrono::steady_clock::time_point time_added; std::chrono::nanoseconds timer_interval; @@ -137,13 +142,14 @@ private: class EqueueInternal { struct SmallTimer { - SceKernelEvent event; + OrbisKernelEvent event; std::chrono::steady_clock::time_point added; std::chrono::nanoseconds interval; }; public: - explicit EqueueInternal(std::string_view name) : m_name(name) {} + explicit EqueueInternal(OrbisKernelEqueue handle, std::string_view name) + : m_handle(handle), m_name(name) {} std::string_view GetName() const { return m_name; @@ -151,11 +157,11 @@ public: bool AddEvent(EqueueEvent& event); bool ScheduleEvent(u64 id, s16 filter, - void (*callback)(SceKernelEqueue, const SceKernelEvent&)); + void (*callback)(OrbisKernelEqueue, const OrbisKernelEvent&)); bool RemoveEvent(u64 id, s16 filter); - int WaitForEvents(SceKernelEvent* ev, int num, const SceKernelUseconds* timo); + int WaitForEvents(OrbisKernelEvent* ev, int num, const OrbisKernelUseconds* timo); bool TriggerEvent(u64 ident, s16 filter, void* trigger_data); - int GetTriggeredEvents(SceKernelEvent* ev, int num); + int GetTriggeredEvents(OrbisKernelEvent* ev, int num); bool AddSmallTimer(EqueueEvent& event); bool HasSmallTimer() { @@ -170,11 +176,12 @@ public: return false; } - int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros); + int WaitForSmallTimer(OrbisKernelEvent* ev, int num, u32 micros); bool EventExists(u64 id, s16 filter); private: + OrbisKernelEqueue m_handle; std::string m_name; std::mutex m_mutex; std::vector m_events; @@ -182,7 +189,8 @@ private: std::unordered_map m_small_timers; }; -u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev); +EqueueInternal* GetEqueue(OrbisKernelEqueue eq); +u64 PS4_SYSV_ABI sceKernelGetEventData(const OrbisKernelEvent* ev); void RegisterEventQueue(Core::Loader::SymbolsResolver* sym); diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index bc4e2def6..184343801 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -792,7 +792,8 @@ s32 PS4_SYSV_ABI fstat(s32 fd, OrbisKernelStat* sb) { return file->socket->fstat(sb); } case Core::FileSys::FileType::Epoll: - case Core::FileSys::FileType::Resolver: { + case Core::FileSys::FileType::Resolver: + case Core::FileSys::FileType::Equeue: { LOG_ERROR(Kernel_Fs, "(STUBBED) file type {}", magic_enum::enum_name(file->type.load())); break; } diff --git a/src/core/libraries/videoout/driver.cpp b/src/core/libraries/videoout/driver.cpp index 2f44b1c99..bebbf9602 100644 --- a/src/core/libraries/videoout/driver.cpp +++ b/src/core/libraries/videoout/driver.cpp @@ -193,7 +193,7 @@ void VideoOutDriver::Flip(const Request& req) { if (event != nullptr) { event->TriggerEvent( static_cast(OrbisVideoOutInternalEventId::Flip), - Kernel::SceKernelEvent::Filter::VideoOut, + Kernel::OrbisKernelEvent::Filter::VideoOut, reinterpret_cast(static_cast(OrbisVideoOutInternalEventId::Flip) | (req.flip_arg << 16))); } @@ -320,7 +320,7 @@ void VideoOutDriver::PresentThread(std::stop_token token) { for (auto& event : main_port.vblank_events) { if (event != nullptr) { event->TriggerEvent(static_cast(OrbisVideoOutInternalEventId::Vblank), - Kernel::SceKernelEvent::Filter::VideoOut, + Kernel::OrbisKernelEvent::Filter::VideoOut, reinterpret_cast( static_cast(OrbisVideoOutInternalEventId::Vblank) | (vblank_status.count << 16))); diff --git a/src/core/libraries/videoout/driver.h b/src/core/libraries/videoout/driver.h index e0eace791..96bd58500 100644 --- a/src/core/libraries/videoout/driver.h +++ b/src/core/libraries/videoout/driver.h @@ -25,8 +25,8 @@ struct VideoOutPort { std::array groups; FlipStatus flip_status; SceVideoOutVblankStatus vblank_status; - std::vector flip_events; - std::vector vblank_events; + std::vector flip_events; + std::vector vblank_events; std::mutex vo_mutex; std::mutex port_mutex; std::condition_variable vo_cv; diff --git a/src/core/libraries/videoout/video_out.cpp b/src/core/libraries/videoout/video_out.cpp index da58772a0..1b8a6b59d 100644 --- a/src/core/libraries/videoout/video_out.cpp +++ b/src/core/libraries/videoout/video_out.cpp @@ -38,7 +38,7 @@ void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(BufferAttribute* attribute, Pixe attribute->option = SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_NONE; } -s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata) { +s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::OrbisKernelEqueue eq, s32 handle, void* udata) { LOG_INFO(Lib_VideoOut, "handle = {}", handle); auto* port = driver->GetPort(handle); @@ -46,39 +46,41 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle, return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE; } - if (eq == nullptr) { + auto equeue = Kernel::GetEqueue(eq); + if (equeue == nullptr) { return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE; } Kernel::EqueueEvent event{}; event.event.ident = static_cast(OrbisVideoOutInternalEventId::Flip); - event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut; - event.event.flags = Kernel::SceKernelEvent::Flags::Add; + event.event.filter = Kernel::OrbisKernelEvent::Filter::VideoOut; + event.event.flags = Kernel::OrbisKernelEvent::Flags::Add; event.event.udata = udata; event.event.fflags = 0; event.event.data = 0; event.data = port; - eq->AddEvent(event); + equeue->AddEvent(event); - port->flip_events.push_back(eq); + port->flip_events.push_back(equeue); return ORBIS_OK; } -s32 PS4_SYSV_ABI sceVideoOutDeleteFlipEvent(Kernel::SceKernelEqueue eq, s32 handle) { +s32 PS4_SYSV_ABI sceVideoOutDeleteFlipEvent(Kernel::OrbisKernelEqueue eq, s32 handle) { auto* port = driver->GetPort(handle); if (port == nullptr) { return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE; } - if (eq == nullptr) { + auto equeue = Kernel::GetEqueue(eq); + if (equeue == nullptr) { return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE; } - eq->RemoveEvent(handle, Kernel::SceKernelEvent::Filter::VideoOut); - port->flip_events.erase(find(port->flip_events.begin(), port->flip_events.end(), eq)); + equeue->RemoveEvent(handle, Kernel::OrbisKernelEvent::Filter::VideoOut); + port->flip_events.erase(find(port->flip_events.begin(), port->flip_events.end(), equeue)); return ORBIS_OK; } -s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata) { +s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::OrbisKernelEqueue eq, s32 handle, void* udata) { LOG_INFO(Lib_VideoOut, "handle = {}", handle); auto* port = driver->GetPort(handle); @@ -86,35 +88,37 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE; } - if (eq == nullptr) { + auto equeue = Kernel::GetEqueue(eq); + if (equeue == nullptr) { return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE; } Kernel::EqueueEvent event{}; event.event.ident = static_cast(OrbisVideoOutInternalEventId::Vblank); - event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut; - event.event.flags = Kernel::SceKernelEvent::Flags::Add; + event.event.filter = Kernel::OrbisKernelEvent::Filter::VideoOut; + event.event.flags = Kernel::OrbisKernelEvent::Flags::Add; event.event.udata = udata; event.event.fflags = 0; event.event.data = 0; event.data = port; - eq->AddEvent(event); + equeue->AddEvent(event); - port->vblank_events.push_back(eq); + port->vblank_events.push_back(equeue); return ORBIS_OK; } -s32 PS4_SYSV_ABI sceVideoOutDeleteVblankEvent(Kernel::SceKernelEqueue eq, s32 handle) { +s32 PS4_SYSV_ABI sceVideoOutDeleteVblankEvent(Kernel::OrbisKernelEqueue eq, s32 handle) { auto* port = driver->GetPort(handle); if (port == nullptr) { return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE; } - if (eq == nullptr) { + auto equeue = Kernel::GetEqueue(eq); + if (equeue == nullptr) { return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE; } - eq->RemoveEvent(handle, Kernel::SceKernelEvent::Filter::VideoOut); - port->vblank_events.erase(find(port->vblank_events.begin(), port->vblank_events.end(), eq)); + equeue->RemoveEvent(handle, Kernel::OrbisKernelEvent::Filter::VideoOut); + port->vblank_events.erase(find(port->vblank_events.begin(), port->vblank_events.end(), equeue)); return ORBIS_OK; } @@ -180,11 +184,11 @@ s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode return ORBIS_OK; } -s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev) { +s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::OrbisKernelEvent* ev) { if (ev == nullptr) { return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS; } - if (ev->filter != Kernel::SceKernelEvent::Filter::VideoOut) { + if (ev->filter != Kernel::OrbisKernelEvent::Filter::VideoOut) { return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT; } @@ -208,11 +212,11 @@ s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev) { } } -s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, s64* data) { +s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::OrbisKernelEvent* ev, s64* data) { if (ev == nullptr || data == nullptr) { return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS; } - if (ev->filter != Kernel::SceKernelEvent::Filter::VideoOut) { + if (ev->filter != Kernel::OrbisKernelEvent::Filter::VideoOut) { return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT; } @@ -225,11 +229,11 @@ s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, s64* return ORBIS_OK; } -s32 PS4_SYSV_ABI sceVideoOutGetEventCount(const Kernel::SceKernelEvent* ev) { +s32 PS4_SYSV_ABI sceVideoOutGetEventCount(const Kernel::OrbisKernelEvent* ev) { if (ev == nullptr) { return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS; } - if (ev->filter != Kernel::SceKernelEvent::Filter::VideoOut) { + if (ev->filter != Kernel::OrbisKernelEvent::Filter::VideoOut) { return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT; } diff --git a/src/core/libraries/videoout/video_out.h b/src/core/libraries/videoout/video_out.h index 2c99a4d1c..09b79e85d 100644 --- a/src/core/libraries/videoout/video_out.h +++ b/src/core/libraries/videoout/video_out.h @@ -119,8 +119,8 @@ struct OrbisVideoOutEventData { void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(BufferAttribute* attribute, PixelFormat pixelFormat, u32 tilingMode, u32 aspectRatio, u32 width, u32 height, u32 pitchInPixel); -s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata); -s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata); +s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::OrbisKernelEqueue eq, s32 handle, void* udata); +s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::OrbisKernelEqueue eq, s32 handle, void* udata); s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses, s32 bufferNum, const BufferAttribute* attribute); s32 PS4_SYSV_ABI sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_addr); @@ -133,8 +133,8 @@ s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutio s32 PS4_SYSV_ABI sceVideoOutOpen(Libraries::UserService::OrbisUserServiceUserId userId, s32 busType, s32 index, const void* param); s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle); -s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev); -s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, s64* data); +s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::OrbisKernelEvent* ev); +s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::OrbisKernelEvent* ev, s64* data); s32 PS4_SYSV_ABI sceVideoOutColorSettingsSetGamma(SceVideoOutColorSettings* settings, float gamma); s32 PS4_SYSV_ABI sceVideoOutAdjustColor(s32 handle, const SceVideoOutColorSettings* settings);