Merge pull request #132 from shadps4-emu/gpu_flip
graphics: separate IRQ for GPU driven flips
This commit is contained in:
commit
055ffff463
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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(®s.reg_array[ContextRegWordOffset + set_data->reg_offset],
|
std::memcpy(®s.reg_array[ContextRegWordOffset + set_data->reg_offset],
|
||||||
|
|
Loading…
Reference in New Issue