graphics: separate IRQ for GPU driven flips

This commit is contained in:
psucien 2024-05-14 21:33:20 +02:00
parent 98316575fb
commit 8677972505
4 changed files with 63 additions and 33 deletions

View File

@ -49,12 +49,13 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
kernel_event.event.udata = udata; kernel_event.event.udata = udata;
eq->addEvent(kernel_event); eq->addEvent(kernel_event);
Platform::IrqC::Instance()->Register([=](Platform::InterruptId irq) { Platform::IrqC::Instance()->Register(
ASSERT_MSG(irq == Platform::InterruptId::GfxEop, Platform::InterruptId::GfxEop, [=](Platform::InterruptId irq) {
"An unexpected IRQ occured"); // We need to conver IRQ# to event id and do proper ASSERT_MSG(irq == Platform::InterruptId::GfxEop,
// filtering in trigger function "An unexpected IRQ occured"); // We need to conver IRQ# to event id and do
eq->triggerEvent(SceKernelEvent::Type::GfxEop, EVFILT_GRAPHICS_CORE, nullptr); // proper filtering in trigger function
}); eq->triggerEvent(SceKernelEvent::Type::GfxEop, EVFILT_GRAPHICS_CORE, nullptr);
});
return ORBIS_OK; return ORBIS_OK;
} }
@ -164,7 +165,7 @@ s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) {
eq->removeEvent(id); eq->removeEvent(id);
Platform::IrqC::Instance()->Unregister(); Platform::IrqC::Instance()->Unregister(Platform::InterruptId::GfxEop);
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -223,11 +223,12 @@ s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, u32 arg, void** u
return 0x8029000b; return 0x8029000b;
} }
Platform::IrqC::Instance()->RegisterOnce([=](Platform::InterruptId irq) { Platform::IrqC::Instance()->RegisterOnce(
ASSERT_MSG(irq == Platform::InterruptId::GfxEop, "An unexpected IRQ occured"); Platform::InterruptId::GfxFlip, [=](Platform::InterruptId irq) {
const auto result = driver->SubmitFlip(port, buf_id, arg, true); ASSERT_MSG(irq == Platform::InterruptId::GfxFlip, "An unexpected IRQ occured");
ASSERT_MSG(result, "EOP flip submission failed"); const auto result = driver->SubmitFlip(port, buf_id, arg, true);
}); ASSERT_MSG(result, "EOP flip submission failed");
});
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -24,51 +24,63 @@ enum class InterruptId : u32 {
Compute4RelMem = 4u, Compute4RelMem = 4u,
Compute5RelMem = 5u, Compute5RelMem = 5u,
Compute6RelMem = 6u, Compute6RelMem = 6u,
GfxEop = 0x40u GfxEop = 7u,
GfxFlip = 8u
}; };
using IrqHandler = std::function<void(InterruptId)>; using IrqHandler = std::function<void(InterruptId)>;
struct IrqController { struct IrqController {
void RegisterOnce(IrqHandler handler) { void RegisterOnce(InterruptId irq, IrqHandler handler) {
std::unique_lock lock{m_lock}; ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Invalid IRQ number");
one_time_subscribers.emplace(handler); auto& ctx = irq_contexts[static_cast<u32>(irq)];
std::unique_lock lock{ctx.m_lock};
ctx.one_time_subscribers.emplace(handler);
} }
void Register(IrqHandler handler) { void Register(InterruptId irq, IrqHandler handler) {
ASSERT_MSG(!persistent_handler.has_value(), ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Invalid IRQ number");
auto& ctx = irq_contexts[static_cast<u32>(irq)];
ASSERT_MSG(!ctx.persistent_handler.has_value(),
"Too many persistent handlers"); // Add a slot map if so "Too many persistent handlers"); // Add a slot map if so
std::unique_lock lock{m_lock}; std::unique_lock lock{ctx.m_lock};
persistent_handler.emplace(handler); ctx.persistent_handler.emplace(handler);
} }
void Unregister() { void Unregister(InterruptId irq) {
std::unique_lock lock{m_lock}; ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Invalid IRQ number");
persistent_handler.reset(); auto& ctx = irq_contexts[static_cast<u32>(irq)];
std::unique_lock lock{ctx.m_lock};
ctx.persistent_handler.reset();
} }
void Signal(InterruptId irq) { void Signal(InterruptId irq) {
std::unique_lock lock{m_lock}; ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Unexpected IRQ signaled");
auto& ctx = irq_contexts[static_cast<u32>(irq)];
std::unique_lock lock{ctx.m_lock};
LOG_TRACE(Core, "IRQ signaled: {}", magic_enum::enum_name(irq)); LOG_TRACE(Core, "IRQ signaled: {}", magic_enum::enum_name(irq));
if (persistent_handler) { if (ctx.persistent_handler) {
persistent_handler.value()(irq); ctx.persistent_handler.value()(irq);
} }
while (!one_time_subscribers.empty()) { while (!ctx.one_time_subscribers.empty()) {
const auto& h = one_time_subscribers.front(); const auto& h = ctx.one_time_subscribers.front();
h(irq); h(irq);
one_time_subscribers.pop(); ctx.one_time_subscribers.pop();
} }
} }
private: private:
std::optional<IrqHandler> persistent_handler{}; struct IrqContext {
std::queue<IrqHandler> one_time_subscribers{}; std::optional<IrqHandler> persistent_handler{};
std::mutex m_lock{}; std::queue<IrqHandler> one_time_subscribers{};
std::mutex m_lock{};
};
std::array<IrqContext, magic_enum::enum_count<InterruptId>()> irq_contexts{};
}; };
using IrqC = Common::Singleton<IrqController>; using IrqC = Common::Singleton<IrqController>;

View File

@ -25,8 +25,24 @@ void Liverpool::ProcessCmdList(u32* cmdbuf, u32 size_in_bytes) {
const PM4ItOpcode opcode = header->type3.opcode; const PM4ItOpcode opcode = header->type3.opcode;
const u32 count = header->type3.NumWords(); const u32 count = header->type3.NumWords();
switch (opcode) { switch (opcode) {
case PM4ItOpcode::Nop: case PM4ItOpcode::Nop: {
const auto* nop = reinterpret_cast<PM4CmdNop*>(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; break;
}
case PM4ItOpcode::SetContextReg: { case PM4ItOpcode::SetContextReg: {
const auto* set_data = reinterpret_cast<PM4CmdSetData*>(header); const auto* set_data = reinterpret_cast<PM4CmdSetData*>(header);
std::memcpy(&regs.reg_array[ContextRegWordOffset + set_data->reg_offset], std::memcpy(&regs.reg_array[ContextRegWordOffset + set_data->reg_offset],