mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-06-05 15:55:01 -06:00
Kernel.Event: Implement kqueue and kevent (#4065)
* Remove dead code from EqueueInternal::WaitForEvents No longer necessary now that we avoid using small timers when falling back on equeue logic. * Refactor type names Might as well * Properly define OrbisKernelEqueue as a handle Most of the functions using an "OrbisKernelEqueue" call directly into kevent. Therefore, OrbisKernelEqueue should be a equeue handle. * Clang * Widen OrbisKernelEqueue type On real hardware, it's some value that contains the handle, as opposed to just the handle itself. * kqueue implementation The easy part * Hardware-accurate timer data Needed to make kevent simpler for these uses. * Move callback scheduling to EqueueInternal::AddEvent kevent would become excessively bloated if I needed to deal with that in there. * posix_kevent kevent is a bit of a pain, for now I've implemented as much as libkernel actually uses for it's wrappers, and left error logs to skip behavior when necessary. * Log calls * Apple, why are you calling fstat on an equeue?
This commit is contained in:
parent
607d704707
commit
6cbab87745
@ -85,7 +85,8 @@ enum class FileType {
|
|||||||
Device,
|
Device,
|
||||||
Socket,
|
Socket,
|
||||||
Epoll,
|
Epoll,
|
||||||
Resolver
|
Resolver,
|
||||||
|
Equeue
|
||||||
};
|
};
|
||||||
|
|
||||||
struct File {
|
struct File {
|
||||||
|
|||||||
@ -123,21 +123,23 @@ static inline bool IsValidEventType(Platform::InterruptId id) {
|
|||||||
static_cast<u32>(id) == static_cast<u32>(Platform::InterruptId::GfxEop);
|
static_cast<u32>(id) == static_cast<u32>(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");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
|
|
||||||
if (!eq) {
|
auto equeue = GetEqueue(eq);
|
||||||
|
if (!equeue) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
EqueueEvent kernel_event{};
|
EqueueEvent kernel_event{};
|
||||||
kernel_event.event.ident = id;
|
kernel_event.event.ident = id;
|
||||||
kernel_event.event.filter = SceKernelEvent::Filter::GraphicsCore;
|
kernel_event.event.filter = OrbisKernelEvent::Filter::GraphicsCore;
|
||||||
kernel_event.event.flags = SceKernelEvent::Flags::Add;
|
kernel_event.event.flags = OrbisKernelEvent::Flags::Add;
|
||||||
kernel_event.event.fflags = 0;
|
kernel_event.event.fflags = 0;
|
||||||
kernel_event.event.data = id;
|
kernel_event.event.data = id;
|
||||||
kernel_event.event.udata = udata;
|
kernel_event.event.udata = udata;
|
||||||
eq->AddEvent(kernel_event);
|
|
||||||
|
equeue->AddEvent(kernel_event);
|
||||||
|
|
||||||
Platform::IrqC::Instance()->Register(
|
Platform::IrqC::Instance()->Register(
|
||||||
static_cast<Platform::InterruptId>(id),
|
static_cast<Platform::InterruptId>(id),
|
||||||
@ -149,10 +151,11 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Event data is expected to be an event type as per sceGnmGetEqEventType.
|
// Event data is expected to be an event type as per sceGnmGetEqEventType.
|
||||||
eq->TriggerEvent(static_cast<GnmEventType>(id), SceKernelEvent::Filter::GraphicsCore,
|
equeue->TriggerEvent(static_cast<GnmEventType>(id),
|
||||||
reinterpret_cast<void*>(id));
|
OrbisKernelEvent::Filter::GraphicsCore,
|
||||||
|
reinterpret_cast<void*>(id));
|
||||||
},
|
},
|
||||||
eq);
|
equeue);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,16 +270,17 @@ int PS4_SYSV_ABI sceGnmDebugHardwareStatus() {
|
|||||||
return ORBIS_OK;
|
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");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
|
|
||||||
if (!eq) {
|
auto equeue = GetEqueue(eq);
|
||||||
|
if (!equeue) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
eq->RemoveEvent(id, SceKernelEvent::Filter::GraphicsCore);
|
equeue->RemoveEvent(id, OrbisKernelEvent::Filter::GraphicsCore);
|
||||||
|
|
||||||
Platform::IrqC::Instance()->Unregister(static_cast<Platform::InterruptId>(id), eq);
|
Platform::IrqC::Instance()->Unregister(static_cast<Platform::InterruptId>(id), equeue);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,7 +899,7 @@ int PS4_SYSV_ABI sceGnmGetDebugTimestamp() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev) {
|
int PS4_SYSV_ABI sceGnmGetEqEventType(const OrbisKernelEvent* ev) {
|
||||||
LOG_TRACE(Lib_GnmDriver, "called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
return sceKernelGetEventData(ev);
|
return sceKernelGetEventData(ev);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ namespace Libraries::GnmDriver {
|
|||||||
|
|
||||||
using namespace Kernel;
|
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 sceGnmAreSubmitsAllowed();
|
||||||
int PS4_SYSV_ABI sceGnmBeginWorkload(u32 workload_stream, u64* workload);
|
int PS4_SYSV_ABI sceGnmBeginWorkload(u32 workload_stream, u64* workload);
|
||||||
s32 PS4_SYSV_ABI sceGnmComputeWaitOnAddress(u32* cmdbuf, u32 size, uintptr_t addr, u32 mask,
|
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 sceGnmDebuggerWriteGds();
|
||||||
int PS4_SYSV_ABI sceGnmDebuggerWriteSqIndirectRegister();
|
int PS4_SYSV_ABI sceGnmDebuggerWriteSqIndirectRegister();
|
||||||
int PS4_SYSV_ABI sceGnmDebugHardwareStatus();
|
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();
|
int PS4_SYSV_ABI sceGnmDestroyWorkloadStream();
|
||||||
void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw);
|
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);
|
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 sceGnmGetCoredumpProtectionFaultTimestamp();
|
||||||
int PS4_SYSV_ABI sceGnmGetDbgGcHandle();
|
int PS4_SYSV_ABI sceGnmGetDbgGcHandle();
|
||||||
int PS4_SYSV_ABI sceGnmGetDebugTimestamp();
|
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 sceGnmGetEqTimeStamp();
|
||||||
int PS4_SYSV_ABI sceGnmGetGpuBlockStatus();
|
int PS4_SYSV_ABI sceGnmGetGpuBlockStatus();
|
||||||
u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency();
|
u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency();
|
||||||
|
|||||||
@ -2,12 +2,17 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <magic_enum/magic_enum.hpp>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/logging/log.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/equeue.h"
|
||||||
|
#include "core/libraries/kernel/kernel.h"
|
||||||
#include "core/libraries/kernel/orbis_error.h"
|
#include "core/libraries/kernel/orbis_error.h"
|
||||||
|
#include "core/libraries/kernel/posix_error.h"
|
||||||
#include "core/libraries/kernel/time.h"
|
#include "core/libraries/kernel/time.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
@ -16,59 +21,104 @@ namespace Libraries::Kernel {
|
|||||||
extern boost::asio::io_context io_context;
|
extern boost::asio::io_context io_context;
|
||||||
extern void KernelSignalRequest();
|
extern void KernelSignalRequest();
|
||||||
|
|
||||||
|
static std::unordered_map<s32, EqueueInternal*> kqueues;
|
||||||
static constexpr auto HrTimerSpinlockThresholdNs = 1200000u;
|
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.
|
// Events are uniquely identified by id and filter.
|
||||||
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
||||||
std::scoped_lock lock{m_mutex};
|
{
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
// Calculate timer interval
|
// Calculate timer interval
|
||||||
event.time_added = std::chrono::steady_clock::now();
|
event.time_added = std::chrono::steady_clock::now();
|
||||||
if (event.event.filter == SceKernelEvent::Filter::Timer ||
|
if (event.event.filter == OrbisKernelEvent::Filter::Timer) {
|
||||||
event.event.filter == SceKernelEvent::Filter::HrTimer) {
|
// Set timer interval, this is stored in milliseconds for timers.
|
||||||
// Set timer interval
|
event.timer_interval = std::chrono::milliseconds(event.event.data);
|
||||||
event.timer_interval = std::chrono::nanoseconds(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<OrbisKernelBintime*>(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.
|
// Schedule callbacks for timer events
|
||||||
u64 id = event.event.ident;
|
if (event.event.filter == OrbisKernelEvent::Timer) {
|
||||||
SceKernelEvent::Filter filter = event.event.filter;
|
return this->ScheduleEvent(event.event.ident, OrbisKernelEvent::Filter::Timer,
|
||||||
const auto& find_it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
TimerCallback);
|
||||||
return ev.event.ident == id && ev.event.filter == filter;
|
} else if (event.event.filter == OrbisKernelEvent::HrTimer) {
|
||||||
});
|
return this->ScheduleEvent(event.event.ident, OrbisKernelEvent::Filter::HrTimer,
|
||||||
// If there is a duplicate event, we need to update that instead.
|
HrTimerCallback);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EqueueInternal::ScheduleEvent(u64 id, s16 filter,
|
bool EqueueInternal::ScheduleEvent(u64 id, s16 filter,
|
||||||
void (*callback)(SceKernelEqueue, const SceKernelEvent&)) {
|
void (*callback)(OrbisKernelEqueue, const OrbisKernelEvent&)) {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
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;
|
const auto& event = *it;
|
||||||
ASSERT(event.event.filter == SceKernelEvent::Filter::Timer ||
|
ASSERT(event.event.filter == OrbisKernelEvent::Filter::Timer ||
|
||||||
event.event.filter == SceKernelEvent::Filter::HrTimer);
|
event.event.filter == OrbisKernelEvent::Filter::HrTimer);
|
||||||
|
|
||||||
if (!it->timer) {
|
if (!it->timer) {
|
||||||
it->timer = std::make_unique<boost::asio::steady_timer>(io_context, event.timer_interval);
|
it->timer = std::make_unique<boost::asio::steady_timer>(io_context, event.timer_interval);
|
||||||
@ -101,7 +151,7 @@ bool EqueueInternal::ScheduleEvent(u64 id, s16 filter,
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callback(this, event_data);
|
callback(this->m_handle, event_data);
|
||||||
});
|
});
|
||||||
KernelSignalRequest();
|
KernelSignalRequest();
|
||||||
|
|
||||||
@ -122,7 +172,7 @@ bool EqueueInternal::RemoveEvent(u64 id, s16 filter) {
|
|||||||
return has_found;
|
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) {
|
if (timo != nullptr && *timo == 0) {
|
||||||
// Effectively acts as a poll; only events that have already
|
// Effectively acts as a poll; only events that have already
|
||||||
// arrived at the time of this function call can be received
|
// 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);
|
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::microseconds>(
|
|
||||||
std::chrono::steady_clock::now() - m_events[0].time_added)
|
|
||||||
.count();
|
|
||||||
count = WaitForSmallTimer(ev, num, std::max(0l, long(micros - time_waited)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,12 +211,12 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
|||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
for (auto& event : m_events) {
|
for (auto& event : m_events) {
|
||||||
if (event.event.ident == ident && event.event.filter == filter) {
|
if (event.event.ident == ident && event.event.filter == filter) {
|
||||||
if (filter == SceKernelEvent::Filter::VideoOut) {
|
if (filter == OrbisKernelEvent::Filter::VideoOut) {
|
||||||
event.TriggerDisplay(trigger_data);
|
event.TriggerDisplay(trigger_data);
|
||||||
} else if (filter == SceKernelEvent::Filter::User) {
|
} else if (filter == OrbisKernelEvent::Filter::User) {
|
||||||
event.TriggerUser(trigger_data);
|
event.TriggerUser(trigger_data);
|
||||||
} else if (filter == SceKernelEvent::Filter::Timer ||
|
} else if (filter == OrbisKernelEvent::Filter::Timer ||
|
||||||
filter == SceKernelEvent::Filter::HrTimer) {
|
filter == OrbisKernelEvent::Filter::HrTimer) {
|
||||||
event.TriggerTimer();
|
event.TriggerTimer();
|
||||||
} else {
|
} else {
|
||||||
event.Trigger(trigger_data);
|
event.Trigger(trigger_data);
|
||||||
@ -188,15 +229,15 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
|||||||
return has_found;
|
return has_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) {
|
int EqueueInternal::GetTriggeredEvents(OrbisKernelEvent* ev, int num) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (auto it = m_events.begin(); it != m_events.end();) {
|
for (auto it = m_events.begin(); it != m_events.end();) {
|
||||||
if (it->IsTriggered()) {
|
if (it->IsTriggered()) {
|
||||||
ev[count++] = it->event;
|
ev[count++] = it->event;
|
||||||
if (it->event.flags & SceKernelEvent::Flags::Clear) {
|
if (it->event.flags & OrbisKernelEvent::Flags::Clear) {
|
||||||
it->Clear();
|
it->Clear();
|
||||||
}
|
}
|
||||||
if (it->event.flags & SceKernelEvent::Flags::OneShot) {
|
if (it->event.flags & OrbisKernelEvent::Flags::OneShot) {
|
||||||
it = m_events.erase(it);
|
it = m_events.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
@ -214,10 +255,17 @@ int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EqueueInternal::AddSmallTimer(EqueueEvent& ev) {
|
bool EqueueInternal::AddSmallTimer(EqueueEvent& ev) {
|
||||||
|
// Retrieve inputted time, this is stored in the bintime format
|
||||||
|
OrbisKernelBintime* time = reinterpret_cast<OrbisKernelBintime*>(ev.event.data);
|
||||||
|
OrbisKernelTimespec ts;
|
||||||
|
ts.tv_sec = time->sec;
|
||||||
|
ts.tv_nsec = ((1000000000 * (time->frac >> 32)) >> 32);
|
||||||
|
|
||||||
|
// Create the small timer
|
||||||
SmallTimer st;
|
SmallTimer st;
|
||||||
st.event = ev.event;
|
st.event = ev.event;
|
||||||
st.added = std::chrono::steady_clock::now();
|
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};
|
std::scoped_lock lock{m_mutex};
|
||||||
m_small_timers[st.event.ident] = std::move(st);
|
m_small_timers[st.event.ident] = std::move(st);
|
||||||
@ -225,7 +273,7 @@ bool EqueueInternal::AddSmallTimer(EqueueEvent& ev) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
|
int EqueueInternal::WaitForSmallTimer(OrbisKernelEvent* ev, int num, u32 micros) {
|
||||||
ASSERT(num >= 1);
|
ASSERT(num >= 1);
|
||||||
|
|
||||||
auto curr_clock = std::chrono::steady_clock::now();
|
auto curr_clock = std::chrono::steady_clock::now();
|
||||||
@ -266,18 +314,119 @@ bool EqueueInternal::EventExists(u64 id, s16 filter) {
|
|||||||
return it != m_events.cend();
|
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<Core::FileSys::HandleTable>::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) {
|
if (eq == nullptr) {
|
||||||
LOG_ERROR(Kernel_Event, "Event queue is null!");
|
LOG_ERROR(Kernel_Event, "Event queue is null!");
|
||||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name == nullptr) {
|
if (name == nullptr) {
|
||||||
LOG_ERROR(Kernel_Event, "Event queue name is null!");
|
LOG_ERROR(Kernel_Event, "Event queue name is null!");
|
||||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maximum is 32 including null terminator
|
// Maximum is 32 including null terminator
|
||||||
static constexpr size_t MaxEventQueueNameSize = 32;
|
static constexpr u64 MaxEventQueueNameSize = 32;
|
||||||
if (std::strlen(name) > MaxEventQueueNameSize) {
|
if (std::strlen(name) > MaxEventQueueNameSize) {
|
||||||
LOG_ERROR(Kernel_Event, "Event queue name exceeds 32 bytes!");
|
LOG_ERROR(Kernel_Event, "Event queue name exceeds 32 bytes!");
|
||||||
return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
|
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);
|
LOG_INFO(Kernel_Event, "name = {}", name);
|
||||||
|
|
||||||
*eq = new EqueueInternal(name);
|
// Reserve a file handle for the kqueue
|
||||||
|
auto* handles = Common::Singleton<Core::FileSys::HandleTable>::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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelDeleteEqueue(SceKernelEqueue eq) {
|
int PS4_SYSV_ABI sceKernelDeleteEqueue(OrbisKernelEqueue eq) {
|
||||||
if (eq == nullptr) {
|
if (!kqueues.contains(eq)) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete eq;
|
auto* handles = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
|
handles->DeleteHandle(eq);
|
||||||
|
kqueues.erase(eq);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out,
|
int PS4_SYSV_ABI sceKernelWaitEqueue(OrbisKernelEqueue eq, OrbisKernelEvent* ev, int num, int* out,
|
||||||
SceKernelUseconds* timo) {
|
OrbisKernelUseconds* timo) {
|
||||||
HLE_TRACE;
|
HLE_TRACE;
|
||||||
TRACE_HINT(eq->GetName());
|
if (!kqueues.contains(eq)) {
|
||||||
LOG_TRACE(Kernel_Event, "equeue = {} num = {}", eq->GetName(), num);
|
|
||||||
|
|
||||||
if (eq == nullptr) {
|
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
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) {
|
if (ev == nullptr) {
|
||||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||||
}
|
}
|
||||||
@ -317,7 +479,7 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int
|
|||||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = eq->WaitForEvents(ev, num, timo);
|
*out = equeue->WaitForEvents(ev, num, timo);
|
||||||
|
|
||||||
if (*out == 0) {
|
if (*out == 0) {
|
||||||
return ORBIS_KERNEL_ERROR_ETIMEDOUT;
|
return ORBIS_KERNEL_ERROR_ETIMEDOUT;
|
||||||
@ -326,13 +488,9 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HrTimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
|
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(OrbisKernelEqueue eq, int id, OrbisKernelTimespec* ts,
|
||||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, OrbisKernelTimespec* ts,
|
|
||||||
void* udata) {
|
void* udata) {
|
||||||
if (eq == nullptr) {
|
if (!kqueues.contains(eq)) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,10 +498,12 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, OrbisKerne
|
|||||||
|
|
||||||
EqueueEvent event{};
|
EqueueEvent event{};
|
||||||
event.event.ident = id;
|
event.event.ident = id;
|
||||||
event.event.filter = SceKernelEvent::Filter::HrTimer;
|
event.event.filter = OrbisKernelEvent::Filter::HrTimer;
|
||||||
event.event.flags = SceKernelEvent::Flags::Add | SceKernelEvent::Flags::OneShot;
|
event.event.flags = OrbisKernelEvent::Flags::Add | OrbisKernelEvent::Flags::OneShot;
|
||||||
event.event.fflags = 0;
|
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<u64>(&time);
|
||||||
event.event.udata = udata;
|
event.event.udata = udata;
|
||||||
|
|
||||||
// HR timers cannot be implemented within the existing event queue architecture due to the
|
// 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
|
// `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
|
// large. Even for large delays, we truncate a small portion to complete the wait
|
||||||
// using the spinlock, prioritizing precision.
|
// using the spinlock, prioritizing precision.
|
||||||
|
auto& equeue = kqueues[eq];
|
||||||
if (total_ns < HrTimerSpinlockThresholdNs) {
|
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) ||
|
if (!equeue->AddEvent(event)) {
|
||||||
!eq->ScheduleEvent(id, SceKernelEvent::Filter::HrTimer, HrTimerCallback)) {
|
|
||||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||||
}
|
}
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelDeleteHRTimerEvent(SceKernelEqueue eq, int id) {
|
int PS4_SYSV_ABI sceKernelDeleteHRTimerEvent(OrbisKernelEqueue eq, int id) {
|
||||||
if (eq == nullptr) {
|
if (!kqueues.contains(eq)) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eq->HasSmallTimer()) {
|
auto& equeue = kqueues[eq];
|
||||||
return eq->RemoveSmallTimer(id) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOENT;
|
if (equeue->HasSmallTimer()) {
|
||||||
|
return equeue->RemoveSmallTimer(id) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOENT;
|
||||||
} else {
|
} else {
|
||||||
return eq->RemoveEvent(id, SceKernelEvent::Filter::HrTimer) ? ORBIS_OK
|
return equeue->RemoveEvent(id, OrbisKernelEvent::Filter::HrTimer)
|
||||||
: ORBIS_KERNEL_ERROR_ENOENT;
|
? ORBIS_OK
|
||||||
|
: ORBIS_KERNEL_ERROR_ENOENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
|
int PS4_SYSV_ABI sceKernelAddTimerEvent(OrbisKernelEqueue eq, int id, OrbisKernelUseconds usec,
|
||||||
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,
|
|
||||||
void* udata) {
|
void* udata) {
|
||||||
if (eq == nullptr) {
|
if (!kqueues.contains(eq)) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
EqueueEvent event{};
|
EqueueEvent event{};
|
||||||
event.event.ident = static_cast<u64>(id);
|
event.event.ident = static_cast<u64>(id);
|
||||||
event.event.filter = SceKernelEvent::Filter::Timer;
|
event.event.filter = OrbisKernelEvent::Filter::Timer;
|
||||||
event.event.flags = SceKernelEvent::Flags::Add;
|
event.event.flags = OrbisKernelEvent::Flags::Add;
|
||||||
event.event.fflags = 0;
|
event.event.fflags = 0;
|
||||||
event.event.data = usec * 1000;
|
event.event.data = usec / 1000;
|
||||||
event.event.udata = udata;
|
event.event.udata = udata;
|
||||||
|
|
||||||
LOG_DEBUG(Kernel_Event, "Added timing event: queue name={}, queue id={}, usec={}, pointer={:x}",
|
auto& equeue = kqueues[eq];
|
||||||
eq->GetName(), event.event.ident, usec, reinterpret_cast<uintptr_t>(udata));
|
if (!equeue->AddEvent(event)) {
|
||||||
|
|
||||||
if (!eq->AddEvent(event) ||
|
|
||||||
!eq->ScheduleEvent(id, SceKernelEvent::Filter::Timer, TimerCallback)) {
|
|
||||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||||
}
|
}
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelDeleteTimerEvent(SceKernelEqueue eq, int id) {
|
int PS4_SYSV_ABI sceKernelDeleteTimerEvent(OrbisKernelEqueue eq, int id) {
|
||||||
if (eq == nullptr) {
|
if (!kqueues.contains(eq)) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
return eq->RemoveEvent(id, SceKernelEvent::Filter::Timer) ? ORBIS_OK
|
return kqueues[eq]->RemoveEvent(id, OrbisKernelEvent::Filter::Timer)
|
||||||
: ORBIS_KERNEL_ERROR_ENOENT;
|
? ORBIS_OK
|
||||||
|
: ORBIS_KERNEL_ERROR_ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
|
int PS4_SYSV_ABI sceKernelAddUserEvent(OrbisKernelEqueue eq, int id) {
|
||||||
if (eq == nullptr) {
|
if (!kqueues.contains(eq)) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
EqueueEvent event{};
|
EqueueEvent event{};
|
||||||
event.event.ident = id;
|
event.event.ident = id;
|
||||||
event.event.filter = SceKernelEvent::Filter::User;
|
event.event.filter = OrbisKernelEvent::Filter::User;
|
||||||
event.event.udata = 0;
|
event.event.udata = 0;
|
||||||
event.event.flags = SceKernelEvent::Flags::Add;
|
event.event.flags = OrbisKernelEvent::Flags::Add;
|
||||||
event.event.fflags = 0;
|
event.event.fflags = 0;
|
||||||
event.event.data = 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) {
|
int PS4_SYSV_ABI sceKernelAddUserEventEdge(OrbisKernelEqueue eq, int id) {
|
||||||
if (eq == nullptr) {
|
if (!kqueues.contains(eq)) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
EqueueEvent event{};
|
EqueueEvent event{};
|
||||||
event.event.ident = id;
|
event.event.ident = id;
|
||||||
event.event.filter = SceKernelEvent::Filter::User;
|
event.event.filter = OrbisKernelEvent::Filter::User;
|
||||||
event.event.udata = 0;
|
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.fflags = 0;
|
||||||
event.event.data = 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);
|
ASSERT(ev);
|
||||||
return ev->udata;
|
return ev->udata;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 PS4_SYSV_ABI sceKernelGetEventId(const SceKernelEvent* ev) {
|
u64 PS4_SYSV_ABI sceKernelGetEventId(const OrbisKernelEvent* ev) {
|
||||||
return ev->ident;
|
return ev->ident;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelTriggerUserEvent(SceKernelEqueue eq, int id, void* udata) {
|
int PS4_SYSV_ABI sceKernelTriggerUserEvent(OrbisKernelEqueue eq, int id, void* udata) {
|
||||||
if (eq == nullptr) {
|
if (!kqueues.contains(eq)) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
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_KERNEL_ERROR_ENOENT;
|
||||||
}
|
}
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id) {
|
int PS4_SYSV_ABI sceKernelDeleteUserEvent(OrbisKernelEqueue eq, int id) {
|
||||||
if (eq == nullptr) {
|
if (!kqueues.contains(eq)) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
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_KERNEL_ERROR_ENOENT;
|
||||||
}
|
}
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelGetEventFilter(const SceKernelEvent* ev) {
|
int PS4_SYSV_ABI sceKernelGetEventFilter(const OrbisKernelEvent* ev) {
|
||||||
return ev->filter;
|
return ev->filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev) {
|
u64 PS4_SYSV_ABI sceKernelGetEventData(const OrbisKernelEvent* ev) {
|
||||||
return ev->data;
|
return ev->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
|
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("D0OdFMjp46I", "libkernel", 1, "libkernel", sceKernelCreateEqueue);
|
||||||
LIB_FUNCTION("jpFjmgAC5AE", "libkernel", 1, "libkernel", sceKernelDeleteEqueue);
|
LIB_FUNCTION("jpFjmgAC5AE", "libkernel", 1, "libkernel", sceKernelDeleteEqueue);
|
||||||
LIB_FUNCTION("fzyMKs9kim0", "libkernel", 1, "libkernel", sceKernelWaitEqueue);
|
LIB_FUNCTION("fzyMKs9kim0", "libkernel", 1, "libkernel", sceKernelWaitEqueue);
|
||||||
|
|||||||
@ -22,10 +22,15 @@ namespace Libraries::Kernel {
|
|||||||
class EqueueInternal;
|
class EqueueInternal;
|
||||||
struct EqueueEvent;
|
struct EqueueEvent;
|
||||||
|
|
||||||
using SceKernelUseconds = u32;
|
struct OrbisKernelBintime {
|
||||||
using SceKernelEqueue = EqueueInternal*;
|
s64 sec;
|
||||||
|
s64 frac;
|
||||||
|
};
|
||||||
|
|
||||||
struct SceKernelEvent {
|
using OrbisKernelUseconds = u32;
|
||||||
|
using OrbisKernelEqueue = s64;
|
||||||
|
|
||||||
|
struct OrbisKernelEvent {
|
||||||
enum Filter : s16 {
|
enum Filter : s16 {
|
||||||
None = 0,
|
None = 0,
|
||||||
Read = -1,
|
Read = -1,
|
||||||
@ -78,7 +83,7 @@ struct OrbisVideoOutEventData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct EqueueEvent {
|
struct EqueueEvent {
|
||||||
SceKernelEvent event;
|
OrbisKernelEvent event;
|
||||||
void* data = nullptr;
|
void* data = nullptr;
|
||||||
std::chrono::steady_clock::time_point time_added;
|
std::chrono::steady_clock::time_point time_added;
|
||||||
std::chrono::nanoseconds timer_interval;
|
std::chrono::nanoseconds timer_interval;
|
||||||
@ -137,13 +142,14 @@ private:
|
|||||||
|
|
||||||
class EqueueInternal {
|
class EqueueInternal {
|
||||||
struct SmallTimer {
|
struct SmallTimer {
|
||||||
SceKernelEvent event;
|
OrbisKernelEvent event;
|
||||||
std::chrono::steady_clock::time_point added;
|
std::chrono::steady_clock::time_point added;
|
||||||
std::chrono::nanoseconds interval;
|
std::chrono::nanoseconds interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
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 {
|
std::string_view GetName() const {
|
||||||
return m_name;
|
return m_name;
|
||||||
@ -151,11 +157,11 @@ public:
|
|||||||
|
|
||||||
bool AddEvent(EqueueEvent& event);
|
bool AddEvent(EqueueEvent& event);
|
||||||
bool ScheduleEvent(u64 id, s16 filter,
|
bool ScheduleEvent(u64 id, s16 filter,
|
||||||
void (*callback)(SceKernelEqueue, const SceKernelEvent&));
|
void (*callback)(OrbisKernelEqueue, const OrbisKernelEvent&));
|
||||||
bool RemoveEvent(u64 id, s16 filter);
|
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);
|
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 AddSmallTimer(EqueueEvent& event);
|
||||||
bool HasSmallTimer() {
|
bool HasSmallTimer() {
|
||||||
@ -170,11 +176,12 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros);
|
int WaitForSmallTimer(OrbisKernelEvent* ev, int num, u32 micros);
|
||||||
|
|
||||||
bool EventExists(u64 id, s16 filter);
|
bool EventExists(u64 id, s16 filter);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
OrbisKernelEqueue m_handle;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
std::vector<EqueueEvent> m_events;
|
std::vector<EqueueEvent> m_events;
|
||||||
@ -182,7 +189,8 @@ private:
|
|||||||
std::unordered_map<u64, SmallTimer> m_small_timers;
|
std::unordered_map<u64, SmallTimer> 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);
|
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);
|
||||||
|
|
||||||
|
|||||||
@ -792,7 +792,8 @@ s32 PS4_SYSV_ABI fstat(s32 fd, OrbisKernelStat* sb) {
|
|||||||
return file->socket->fstat(sb);
|
return file->socket->fstat(sb);
|
||||||
}
|
}
|
||||||
case Core::FileSys::FileType::Epoll:
|
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()));
|
LOG_ERROR(Kernel_Fs, "(STUBBED) file type {}", magic_enum::enum_name(file->type.load()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -193,7 +193,7 @@ void VideoOutDriver::Flip(const Request& req) {
|
|||||||
if (event != nullptr) {
|
if (event != nullptr) {
|
||||||
event->TriggerEvent(
|
event->TriggerEvent(
|
||||||
static_cast<u64>(OrbisVideoOutInternalEventId::Flip),
|
static_cast<u64>(OrbisVideoOutInternalEventId::Flip),
|
||||||
Kernel::SceKernelEvent::Filter::VideoOut,
|
Kernel::OrbisKernelEvent::Filter::VideoOut,
|
||||||
reinterpret_cast<void*>(static_cast<u64>(OrbisVideoOutInternalEventId::Flip) |
|
reinterpret_cast<void*>(static_cast<u64>(OrbisVideoOutInternalEventId::Flip) |
|
||||||
(req.flip_arg << 16)));
|
(req.flip_arg << 16)));
|
||||||
}
|
}
|
||||||
@ -320,7 +320,7 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
|||||||
for (auto& event : main_port.vblank_events) {
|
for (auto& event : main_port.vblank_events) {
|
||||||
if (event != nullptr) {
|
if (event != nullptr) {
|
||||||
event->TriggerEvent(static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
|
event->TriggerEvent(static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
|
||||||
Kernel::SceKernelEvent::Filter::VideoOut,
|
Kernel::OrbisKernelEvent::Filter::VideoOut,
|
||||||
reinterpret_cast<void*>(
|
reinterpret_cast<void*>(
|
||||||
static_cast<u64>(OrbisVideoOutInternalEventId::Vblank) |
|
static_cast<u64>(OrbisVideoOutInternalEventId::Vblank) |
|
||||||
(vblank_status.count << 16)));
|
(vblank_status.count << 16)));
|
||||||
|
|||||||
@ -25,8 +25,8 @@ struct VideoOutPort {
|
|||||||
std::array<BufferAttributeGroup, MaxDisplayBufferGroups> groups;
|
std::array<BufferAttributeGroup, MaxDisplayBufferGroups> groups;
|
||||||
FlipStatus flip_status;
|
FlipStatus flip_status;
|
||||||
SceVideoOutVblankStatus vblank_status;
|
SceVideoOutVblankStatus vblank_status;
|
||||||
std::vector<Kernel::SceKernelEqueue> flip_events;
|
std::vector<Kernel::EqueueInternal*> flip_events;
|
||||||
std::vector<Kernel::SceKernelEqueue> vblank_events;
|
std::vector<Kernel::EqueueInternal*> vblank_events;
|
||||||
std::mutex vo_mutex;
|
std::mutex vo_mutex;
|
||||||
std::mutex port_mutex;
|
std::mutex port_mutex;
|
||||||
std::condition_variable vo_cv;
|
std::condition_variable vo_cv;
|
||||||
|
|||||||
@ -38,7 +38,7 @@ void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(BufferAttribute* attribute, Pixe
|
|||||||
attribute->option = SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_NONE;
|
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);
|
LOG_INFO(Lib_VideoOut, "handle = {}", handle);
|
||||||
|
|
||||||
auto* port = driver->GetPort(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;
|
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;
|
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::EqueueEvent event{};
|
Kernel::EqueueEvent event{};
|
||||||
event.event.ident = static_cast<u64>(OrbisVideoOutInternalEventId::Flip);
|
event.event.ident = static_cast<u64>(OrbisVideoOutInternalEventId::Flip);
|
||||||
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
|
event.event.filter = Kernel::OrbisKernelEvent::Filter::VideoOut;
|
||||||
event.event.flags = Kernel::SceKernelEvent::Flags::Add;
|
event.event.flags = Kernel::OrbisKernelEvent::Flags::Add;
|
||||||
event.event.udata = udata;
|
event.event.udata = udata;
|
||||||
event.event.fflags = 0;
|
event.event.fflags = 0;
|
||||||
event.event.data = 0;
|
event.event.data = 0;
|
||||||
event.data = port;
|
event.data = port;
|
||||||
eq->AddEvent(event);
|
equeue->AddEvent(event);
|
||||||
|
|
||||||
port->flip_events.push_back(eq);
|
port->flip_events.push_back(equeue);
|
||||||
return ORBIS_OK;
|
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);
|
auto* port = driver->GetPort(handle);
|
||||||
if (port == nullptr) {
|
if (port == nullptr) {
|
||||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_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;
|
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||||
}
|
}
|
||||||
eq->RemoveEvent(handle, Kernel::SceKernelEvent::Filter::VideoOut);
|
equeue->RemoveEvent(handle, Kernel::OrbisKernelEvent::Filter::VideoOut);
|
||||||
port->flip_events.erase(find(port->flip_events.begin(), port->flip_events.end(), eq));
|
port->flip_events.erase(find(port->flip_events.begin(), port->flip_events.end(), equeue));
|
||||||
return ORBIS_OK;
|
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);
|
LOG_INFO(Lib_VideoOut, "handle = {}", handle);
|
||||||
|
|
||||||
auto* port = driver->GetPort(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;
|
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;
|
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::EqueueEvent event{};
|
Kernel::EqueueEvent event{};
|
||||||
event.event.ident = static_cast<u64>(OrbisVideoOutInternalEventId::Vblank);
|
event.event.ident = static_cast<u64>(OrbisVideoOutInternalEventId::Vblank);
|
||||||
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
|
event.event.filter = Kernel::OrbisKernelEvent::Filter::VideoOut;
|
||||||
event.event.flags = Kernel::SceKernelEvent::Flags::Add;
|
event.event.flags = Kernel::OrbisKernelEvent::Flags::Add;
|
||||||
event.event.udata = udata;
|
event.event.udata = udata;
|
||||||
event.event.fflags = 0;
|
event.event.fflags = 0;
|
||||||
event.event.data = 0;
|
event.event.data = 0;
|
||||||
event.data = port;
|
event.data = port;
|
||||||
eq->AddEvent(event);
|
equeue->AddEvent(event);
|
||||||
|
|
||||||
port->vblank_events.push_back(eq);
|
port->vblank_events.push_back(equeue);
|
||||||
return ORBIS_OK;
|
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);
|
auto* port = driver->GetPort(handle);
|
||||||
if (port == nullptr) {
|
if (port == nullptr) {
|
||||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_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;
|
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||||
}
|
}
|
||||||
eq->RemoveEvent(handle, Kernel::SceKernelEvent::Filter::VideoOut);
|
equeue->RemoveEvent(handle, Kernel::OrbisKernelEvent::Filter::VideoOut);
|
||||||
port->vblank_events.erase(find(port->vblank_events.begin(), port->vblank_events.end(), eq));
|
port->vblank_events.erase(find(port->vblank_events.begin(), port->vblank_events.end(), equeue));
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,11 +184,11 @@ s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev) {
|
s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::OrbisKernelEvent* ev) {
|
||||||
if (ev == nullptr) {
|
if (ev == nullptr) {
|
||||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS;
|
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;
|
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) {
|
if (ev == nullptr || data == nullptr) {
|
||||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS;
|
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;
|
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,11 +229,11 @@ s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, s64*
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceVideoOutGetEventCount(const Kernel::SceKernelEvent* ev) {
|
s32 PS4_SYSV_ABI sceVideoOutGetEventCount(const Kernel::OrbisKernelEvent* ev) {
|
||||||
if (ev == nullptr) {
|
if (ev == nullptr) {
|
||||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS;
|
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;
|
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -119,8 +119,8 @@ struct OrbisVideoOutEventData {
|
|||||||
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(BufferAttribute* attribute, PixelFormat pixelFormat,
|
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(BufferAttribute* attribute, PixelFormat pixelFormat,
|
||||||
u32 tilingMode, u32 aspectRatio, u32 width,
|
u32 tilingMode, u32 aspectRatio, u32 width,
|
||||||
u32 height, u32 pitchInPixel);
|
u32 height, u32 pitchInPixel);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(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::SceKernelEqueue 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 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses,
|
||||||
s32 bufferNum, const BufferAttribute* attribute);
|
s32 bufferNum, const BufferAttribute* attribute);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_addr);
|
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 PS4_SYSV_ABI sceVideoOutOpen(Libraries::UserService::OrbisUserServiceUserId userId, s32 busType,
|
||||||
s32 index, const void* param);
|
s32 index, const void* param);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle);
|
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev);
|
s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::OrbisKernelEvent* ev);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, s64* data);
|
s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::OrbisKernelEvent* ev, s64* data);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutColorSettingsSetGamma(SceVideoOutColorSettings* settings, float gamma);
|
s32 PS4_SYSV_ABI sceVideoOutColorSettingsSetGamma(SceVideoOutColorSettings* settings, float gamma);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutAdjustColor(s32 handle, const SceVideoOutColorSettings* settings);
|
s32 PS4_SYSV_ABI sceVideoOutAdjustColor(s32 handle, const SceVideoOutColorSettings* settings);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user