From 8677972505c1f38d77f41ae14ef8e6202f52e677 Mon Sep 17 00:00:00 2001 From: psucien Date: Tue, 14 May 2024 21:33:20 +0200 Subject: [PATCH] graphics: separate IRQ for GPU driven flips --- src/core/libraries/gnmdriver/gnmdriver.cpp | 15 ++++--- src/core/libraries/videoout/video_out.cpp | 11 ++--- src/core/platform.h | 52 +++++++++++++--------- src/video_core/amdgpu/liverpool.cpp | 18 +++++++- 4 files changed, 63 insertions(+), 33 deletions(-) diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index 141aff6f..b5dca74b 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -49,12 +49,13 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) { kernel_event.event.udata = udata; eq->addEvent(kernel_event); - Platform::IrqC::Instance()->Register([=](Platform::InterruptId irq) { - ASSERT_MSG(irq == Platform::InterruptId::GfxEop, - "An unexpected IRQ occured"); // We need to conver IRQ# to event id and do proper - // filtering in trigger function - eq->triggerEvent(SceKernelEvent::Type::GfxEop, EVFILT_GRAPHICS_CORE, nullptr); - }); + Platform::IrqC::Instance()->Register( + Platform::InterruptId::GfxEop, [=](Platform::InterruptId irq) { + ASSERT_MSG(irq == Platform::InterruptId::GfxEop, + "An unexpected IRQ occured"); // We need to conver IRQ# to event id and do + // proper filtering in trigger function + eq->triggerEvent(SceKernelEvent::Type::GfxEop, EVFILT_GRAPHICS_CORE, nullptr); + }); return ORBIS_OK; } @@ -164,7 +165,7 @@ s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) { eq->removeEvent(id); - Platform::IrqC::Instance()->Unregister(); + Platform::IrqC::Instance()->Unregister(Platform::InterruptId::GfxEop); return ORBIS_OK; } diff --git a/src/core/libraries/videoout/video_out.cpp b/src/core/libraries/videoout/video_out.cpp index e5995ab2..6f5ccc39 100644 --- a/src/core/libraries/videoout/video_out.cpp +++ b/src/core/libraries/videoout/video_out.cpp @@ -223,11 +223,12 @@ s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, u32 arg, void** u return 0x8029000b; } - Platform::IrqC::Instance()->RegisterOnce([=](Platform::InterruptId irq) { - ASSERT_MSG(irq == Platform::InterruptId::GfxEop, "An unexpected IRQ occured"); - const auto result = driver->SubmitFlip(port, buf_id, arg, true); - ASSERT_MSG(result, "EOP flip submission failed"); - }); + Platform::IrqC::Instance()->RegisterOnce( + Platform::InterruptId::GfxFlip, [=](Platform::InterruptId irq) { + ASSERT_MSG(irq == Platform::InterruptId::GfxFlip, "An unexpected IRQ occured"); + const auto result = driver->SubmitFlip(port, buf_id, arg, true); + ASSERT_MSG(result, "EOP flip submission failed"); + }); return ORBIS_OK; } diff --git a/src/core/platform.h b/src/core/platform.h index 4d3f4b96..24b267da 100644 --- a/src/core/platform.h +++ b/src/core/platform.h @@ -24,51 +24,63 @@ enum class InterruptId : u32 { Compute4RelMem = 4u, Compute5RelMem = 5u, Compute6RelMem = 6u, - GfxEop = 0x40u + GfxEop = 7u, + GfxFlip = 8u }; using IrqHandler = std::function; struct IrqController { - void RegisterOnce(IrqHandler handler) { - std::unique_lock lock{m_lock}; - one_time_subscribers.emplace(handler); + void RegisterOnce(InterruptId irq, IrqHandler handler) { + ASSERT_MSG(static_cast(irq) < irq_contexts.size(), "Invalid IRQ number"); + auto& ctx = irq_contexts[static_cast(irq)]; + std::unique_lock lock{ctx.m_lock}; + ctx.one_time_subscribers.emplace(handler); } - void Register(IrqHandler handler) { - ASSERT_MSG(!persistent_handler.has_value(), + void Register(InterruptId irq, IrqHandler handler) { + ASSERT_MSG(static_cast(irq) < irq_contexts.size(), "Invalid IRQ number"); + auto& ctx = irq_contexts[static_cast(irq)]; + ASSERT_MSG(!ctx.persistent_handler.has_value(), "Too many persistent handlers"); // Add a slot map if so - std::unique_lock lock{m_lock}; - persistent_handler.emplace(handler); + std::unique_lock lock{ctx.m_lock}; + ctx.persistent_handler.emplace(handler); } - void Unregister() { - std::unique_lock lock{m_lock}; - persistent_handler.reset(); + void Unregister(InterruptId irq) { + ASSERT_MSG(static_cast(irq) < irq_contexts.size(), "Invalid IRQ number"); + auto& ctx = irq_contexts[static_cast(irq)]; + std::unique_lock lock{ctx.m_lock}; + ctx.persistent_handler.reset(); } void Signal(InterruptId irq) { - std::unique_lock lock{m_lock}; + ASSERT_MSG(static_cast(irq) < irq_contexts.size(), "Unexpected IRQ signaled"); + auto& ctx = irq_contexts[static_cast(irq)]; + std::unique_lock lock{ctx.m_lock}; LOG_TRACE(Core, "IRQ signaled: {}", magic_enum::enum_name(irq)); - if (persistent_handler) { - persistent_handler.value()(irq); + if (ctx.persistent_handler) { + ctx.persistent_handler.value()(irq); } - while (!one_time_subscribers.empty()) { - const auto& h = one_time_subscribers.front(); + while (!ctx.one_time_subscribers.empty()) { + const auto& h = ctx.one_time_subscribers.front(); h(irq); - one_time_subscribers.pop(); + ctx.one_time_subscribers.pop(); } } private: - std::optional persistent_handler{}; - std::queue one_time_subscribers{}; - std::mutex m_lock{}; + struct IrqContext { + std::optional persistent_handler{}; + std::queue one_time_subscribers{}; + std::mutex m_lock{}; + }; + std::array()> irq_contexts{}; }; using IrqC = Common::Singleton; diff --git a/src/video_core/amdgpu/liverpool.cpp b/src/video_core/amdgpu/liverpool.cpp index 58e36017..62e12fa2 100644 --- a/src/video_core/amdgpu/liverpool.cpp +++ b/src/video_core/amdgpu/liverpool.cpp @@ -25,8 +25,24 @@ void Liverpool::ProcessCmdList(u32* cmdbuf, u32 size_in_bytes) { const PM4ItOpcode opcode = header->type3.opcode; const u32 count = header->type3.NumWords(); switch (opcode) { - case PM4ItOpcode::Nop: + case PM4ItOpcode::Nop: { + const auto* nop = reinterpret_cast(header); + if (nop->header.count.Value() == 0) { + break; + } + + switch (nop->data_block[0]) { + case PM4CmdNop::PayloadType::PatchedFlip: { + // There is no evidence that GPU CP drives flip events by parsing + // special NOP packets. For convenience lets assume that it does. + Platform::IrqC::Instance()->Signal(Platform::InterruptId::GfxFlip); + break; + } + default: + break; + } break; + } case PM4ItOpcode::SetContextReg: { const auto* set_data = reinterpret_cast(header); std::memcpy(®s.reg_array[ContextRegWordOffset + set_data->reg_offset],