mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-06-03 06:05:01 -06:00
Lib.VideoOut: Properly remove events on close (#4456)
* Fix flip status on close * Store equeues by handle instead of pointer As is, a game could call sceKernelDeleteEqueue on the equeue registered for flip/vblank events, and terminate the equeue while our VideoOut driver retains a valid pointer to it. Changing to storing the equeue handle means we can check if the equeue still exists and prevent this. * Remove flip and vblank events on sceVideoOutClose * Don't forget to clear vectors * Oops Intended to erase the memset on FlipStatus, not VblankStatus.
This commit is contained in:
parent
f95edd27e0
commit
03ebac577b
@ -70,8 +70,8 @@ void VideoOutDriver::Close(s32 handle) {
|
||||
// Clear port information
|
||||
std::memset(main_port.buffer_labels.data(), 0, sizeof(main_port.buffer_labels));
|
||||
std::memset(main_port.groups.data(), 0, sizeof(main_port.groups));
|
||||
std::memset(&main_port.flip_status, 0, sizeof(main_port.flip_status));
|
||||
std::memset(&main_port.vblank_status, 0, sizeof(main_port.vblank_status));
|
||||
main_port.flip_status = FlipStatus{};
|
||||
|
||||
// Re-initialize buffers
|
||||
std::memset(main_port.buffer_slots.data(), 0, sizeof(main_port.buffer_slots));
|
||||
@ -79,9 +79,23 @@ void VideoOutDriver::Close(s32 handle) {
|
||||
buffer.group_index = -1;
|
||||
}
|
||||
|
||||
// TODO: Remove events?
|
||||
ASSERT(main_port.flip_events.empty());
|
||||
ASSERT(main_port.vblank_events.empty());
|
||||
// Clear events
|
||||
for (auto event : main_port.flip_events) {
|
||||
auto equeue = Kernel::GetEqueue(event);
|
||||
if (equeue != nullptr) {
|
||||
equeue->RemoveEvent(static_cast<u64>(OrbisVideoOutInternalEventId::Flip),
|
||||
Kernel::OrbisKernelEvent::Filter::VideoOut);
|
||||
}
|
||||
}
|
||||
main_port.flip_events.clear();
|
||||
for (auto event : main_port.vblank_events) {
|
||||
auto equeue = Kernel::GetEqueue(event);
|
||||
if (equeue != nullptr) {
|
||||
equeue->RemoveEvent(static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
|
||||
Kernel::OrbisKernelEvent::Filter::VideoOut);
|
||||
}
|
||||
}
|
||||
main_port.vblank_events.clear();
|
||||
}
|
||||
|
||||
VideoOutPort* VideoOutDriver::GetPort(int handle) {
|
||||
@ -243,9 +257,10 @@ void VideoOutDriver::Flip(const Request& req) {
|
||||
}
|
||||
|
||||
// Trigger flip events for the port.
|
||||
for (auto& event : port->flip_events) {
|
||||
if (event != nullptr) {
|
||||
event->TriggerEvent(
|
||||
for (auto event : port->flip_events) {
|
||||
auto equeue = Kernel::GetEqueue(event);
|
||||
if (equeue != nullptr) {
|
||||
equeue->TriggerEvent(
|
||||
static_cast<u64>(OrbisVideoOutInternalEventId::Flip),
|
||||
Kernel::OrbisKernelEvent::Filter::VideoOut,
|
||||
reinterpret_cast<void*>(static_cast<u64>(OrbisVideoOutInternalEventId::Flip) |
|
||||
@ -372,13 +387,15 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
||||
std::scoped_lock lock{main_port.vo_mutex};
|
||||
|
||||
// Trigger flip events for the port
|
||||
for (auto& event : main_port.vblank_events) {
|
||||
if (event != nullptr) {
|
||||
event->TriggerEvent(static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
|
||||
Kernel::OrbisKernelEvent::Filter::VideoOut,
|
||||
reinterpret_cast<void*>(
|
||||
static_cast<u64>(OrbisVideoOutInternalEventId::Vblank) |
|
||||
(vblank_status.count << 16)));
|
||||
for (auto event : main_port.vblank_events) {
|
||||
auto equeue = Kernel::GetEqueue(event);
|
||||
if (equeue != nullptr) {
|
||||
equeue->TriggerEvent(
|
||||
static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
|
||||
Kernel::OrbisKernelEvent::Filter::VideoOut,
|
||||
reinterpret_cast<void*>(
|
||||
static_cast<u64>(OrbisVideoOutInternalEventId::Vblank) |
|
||||
(vblank_status.count << 16)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -25,8 +25,8 @@ struct VideoOutPort {
|
||||
std::array<BufferAttributeGroup, MaxDisplayBufferGroups> groups;
|
||||
FlipStatus flip_status;
|
||||
SceVideoOutVblankStatus vblank_status;
|
||||
std::vector<Kernel::EqueueInternal*> flip_events;
|
||||
std::vector<Kernel::EqueueInternal*> vblank_events;
|
||||
std::vector<Kernel::OrbisKernelEqueue> flip_events;
|
||||
std::vector<Kernel::OrbisKernelEqueue> vblank_events;
|
||||
std::mutex vo_mutex;
|
||||
std::mutex port_mutex;
|
||||
std::condition_variable vo_cv;
|
||||
|
||||
@ -61,7 +61,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::OrbisKernelEqueue eq, s32 handl
|
||||
event.data = port;
|
||||
equeue->AddEvent(event);
|
||||
|
||||
port->flip_events.push_back(equeue);
|
||||
port->flip_events.push_back(eq);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ s32 PS4_SYSV_ABI sceVideoOutDeleteFlipEvent(Kernel::OrbisKernelEqueue eq, s32 ha
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||
}
|
||||
equeue->RemoveEvent(handle, Kernel::OrbisKernelEvent::Filter::VideoOut);
|
||||
port->flip_events.erase(find(port->flip_events.begin(), port->flip_events.end(), equeue));
|
||||
port->flip_events.erase(find(port->flip_events.begin(), port->flip_events.end(), eq));
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -103,7 +103,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::OrbisKernelEqueue eq, s32 han
|
||||
event.data = port;
|
||||
equeue->AddEvent(event);
|
||||
|
||||
port->vblank_events.push_back(equeue);
|
||||
port->vblank_events.push_back(eq);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ s32 PS4_SYSV_ABI sceVideoOutDeleteVblankEvent(Kernel::OrbisKernelEqueue eq, s32
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||
}
|
||||
equeue->RemoveEvent(handle, Kernel::OrbisKernelEvent::Filter::VideoOut);
|
||||
port->vblank_events.erase(find(port->vblank_events.begin(), port->vblank_events.end(), equeue));
|
||||
port->vblank_events.erase(find(port->vblank_events.begin(), port->vblank_events.end(), eq));
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user