diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index b0706dfd..e5bbaaa0 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -30,8 +30,26 @@ static inline u32* WriteTrailingNop(u32* cmdbuf) { return cmdbuf + data_block_size + 1 /* header */; } -int PS4_SYSV_ABI sceGnmAddEqEvent() { - LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) { + LOG_TRACE(Lib_GnmDriver, "called"); + ASSERT_MSG(id == SceKernelEvent::Type::GfxEop); + + if (!eq) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + EqueueEvent kernel_event{}; + kernel_event.event.ident = id; + kernel_event.event.filter = EVFILT_GRAPHICS_CORE; + kernel_event.event.flags = 1; + kernel_event.event.fflags = 0; + kernel_event.event.data = id; + kernel_event.event.udata = udata; + eq->addEvent(kernel_event); + + liverpool->eop_callback = [=]() { + eq->triggerEvent(SceKernelEvent::Type::GfxEop, EVFILT_GRAPHICS_CORE, nullptr); + }; return ORBIS_OK; } @@ -131,8 +149,15 @@ int PS4_SYSV_ABI sceGnmDebugHardwareStatus() { return ORBIS_OK; } -int PS4_SYSV_ABI sceGnmDeleteEqEvent() { - LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) { + LOG_TRACE(Lib_GnmDriver, "called"); + ASSERT_MSG(id == SceKernelEvent::Type::GfxEop); + + if (!eq) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + eq->removeEvent(id); return ORBIS_OK; } diff --git a/src/core/libraries/gnmdriver/gnmdriver.h b/src/core/libraries/gnmdriver/gnmdriver.h index 1f25649a..36e33eb3 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.h +++ b/src/core/libraries/gnmdriver/gnmdriver.h @@ -4,6 +4,7 @@ #pragma once #include "common/types.h" +#include "core/libraries/kernel/event_queues.h" namespace Core::Loader { class SymbolsResolver; @@ -11,7 +12,9 @@ class SymbolsResolver; namespace Libraries::GnmDriver { -int PS4_SYSV_ABI sceGnmAddEqEvent(); +using namespace Kernel; + +s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata); int PS4_SYSV_ABI sceGnmAreSubmitsAllowed(); int PS4_SYSV_ABI sceGnmBeginWorkload(); s32 PS4_SYSV_ABI sceGnmComputeWaitOnAddress(u32* cmdbuf, u32 size, uintptr_t addr, u32 mask, @@ -28,7 +31,7 @@ int PS4_SYSV_ABI sceGnmDebuggerSetAddressWatch(); int PS4_SYSV_ABI sceGnmDebuggerWriteGds(); int PS4_SYSV_ABI sceGnmDebuggerWriteSqIndirectRegister(); int PS4_SYSV_ABI sceGnmDebugHardwareStatus(); -int PS4_SYSV_ABI sceGnmDeleteEqEvent(); +s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id); int PS4_SYSV_ABI sceGnmDestroyWorkloadStream(); int PS4_SYSV_ABI sceGnmDingDong(); int PS4_SYSV_ABI sceGnmDingDongForWorkload(); diff --git a/src/core/libraries/kernel/event_queue.cpp b/src/core/libraries/kernel/event_queue.cpp index 8fd70106..8642af96 100644 --- a/src/core/libraries/kernel/event_queue.cpp +++ b/src/core/libraries/kernel/event_queue.cpp @@ -20,6 +20,14 @@ int EqueueInternal::addEvent(const EqueueEvent& event) { return 0; } +int EqueueInternal::removeEvent(u64 id) { + const auto& event_q = std::find_if(m_events.cbegin(), m_events.cend(), + [id](auto& ev) { return ev.event.ident == id; }); + ASSERT(event_q != m_events.cend()); + m_events.erase(event_q); + return 0; +} + int EqueueInternal::waitForEvents(SceKernelEvent* ev, int num, u32 micros) { std::unique_lock lock{m_mutex}; int ret = 0; diff --git a/src/core/libraries/kernel/event_queue.h b/src/core/libraries/kernel/event_queue.h index 12151a0c..745a0ac0 100644 --- a/src/core/libraries/kernel/event_queue.h +++ b/src/core/libraries/kernel/event_queue.h @@ -42,11 +42,22 @@ using ResetFunc = void (*)(EqueueEvent* event); using DeleteFunc = void (*)(EqueueInternal* eq, EqueueEvent* event); struct SceKernelEvent { + enum Type : u64 { + Compute0RelMem = 0x00, + Compute1RelMem = 0x01, + Compute2RelMem = 0x02, + Compute3RelMem = 0x03, + Compute4RelMem = 0x04, + Compute5RelMem = 0x05, + Compute6RelMem = 0x06, + GfxEop = 0x40 + }; + u64 ident = 0; /* identifier for this event */ s16 filter = 0; /* filter for event */ u16 flags = 0; u32 fflags = 0; - s64 data = 0; + u64 data = 0; void* udata = nullptr; /* opaque user data identifier */ }; @@ -80,6 +91,7 @@ public: this->m_name = m_name; } int addEvent(const EqueueEvent& event); + int removeEvent(u64 id); int waitForEvents(SceKernelEvent* ev, int num, u32 micros); bool triggerEvent(u64 ident, s16 filter, void* trigger_data); int getTriggeredEvents(SceKernelEvent* ev, int num); diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 229b5804..44c2a526 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -3,10 +3,12 @@ #pragma once -#include #include "common/bit_field.h" #include "common/types.h" +#include +#include + namespace AmdGpu { #define GFX6_3D_REG_INDEX(field_name) (offsetof(AmdGpu::Liverpool::Regs, field_name) / sizeof(u32)) @@ -611,6 +613,8 @@ public: Liverpool(); void ProcessCmdList(u32* cmdbuf, u32 size_in_bytes); + + std::function eop_callback{}; }; static_assert(GFX6_3D_REG_INDEX(ps_program) == 0x2C08);