mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-06-03 14:14:59 -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
|
// Clear port information
|
||||||
std::memset(main_port.buffer_labels.data(), 0, sizeof(main_port.buffer_labels));
|
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.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));
|
std::memset(&main_port.vblank_status, 0, sizeof(main_port.vblank_status));
|
||||||
|
main_port.flip_status = FlipStatus{};
|
||||||
|
|
||||||
// Re-initialize buffers
|
// Re-initialize buffers
|
||||||
std::memset(main_port.buffer_slots.data(), 0, sizeof(main_port.buffer_slots));
|
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;
|
buffer.group_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove events?
|
// Clear events
|
||||||
ASSERT(main_port.flip_events.empty());
|
for (auto event : main_port.flip_events) {
|
||||||
ASSERT(main_port.vblank_events.empty());
|
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) {
|
VideoOutPort* VideoOutDriver::GetPort(int handle) {
|
||||||
@ -243,9 +257,10 @@ void VideoOutDriver::Flip(const Request& req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trigger flip events for the port.
|
// Trigger flip events for the port.
|
||||||
for (auto& event : port->flip_events) {
|
for (auto event : port->flip_events) {
|
||||||
if (event != nullptr) {
|
auto equeue = Kernel::GetEqueue(event);
|
||||||
event->TriggerEvent(
|
if (equeue != nullptr) {
|
||||||
|
equeue->TriggerEvent(
|
||||||
static_cast<u64>(OrbisVideoOutInternalEventId::Flip),
|
static_cast<u64>(OrbisVideoOutInternalEventId::Flip),
|
||||||
Kernel::OrbisKernelEvent::Filter::VideoOut,
|
Kernel::OrbisKernelEvent::Filter::VideoOut,
|
||||||
reinterpret_cast<void*>(static_cast<u64>(OrbisVideoOutInternalEventId::Flip) |
|
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};
|
std::scoped_lock lock{main_port.vo_mutex};
|
||||||
|
|
||||||
// Trigger flip events for the port
|
// Trigger flip events for the port
|
||||||
for (auto& event : main_port.vblank_events) {
|
for (auto event : main_port.vblank_events) {
|
||||||
if (event != nullptr) {
|
auto equeue = Kernel::GetEqueue(event);
|
||||||
event->TriggerEvent(static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
|
if (equeue != nullptr) {
|
||||||
Kernel::OrbisKernelEvent::Filter::VideoOut,
|
equeue->TriggerEvent(
|
||||||
reinterpret_cast<void*>(
|
static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
|
||||||
static_cast<u64>(OrbisVideoOutInternalEventId::Vblank) |
|
Kernel::OrbisKernelEvent::Filter::VideoOut,
|
||||||
(vblank_status.count << 16)));
|
reinterpret_cast<void*>(
|
||||||
|
static_cast<u64>(OrbisVideoOutInternalEventId::Vblank) |
|
||||||
|
(vblank_status.count << 16)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,8 +25,8 @@ struct VideoOutPort {
|
|||||||
std::array<BufferAttributeGroup, MaxDisplayBufferGroups> groups;
|
std::array<BufferAttributeGroup, MaxDisplayBufferGroups> groups;
|
||||||
FlipStatus flip_status;
|
FlipStatus flip_status;
|
||||||
SceVideoOutVblankStatus vblank_status;
|
SceVideoOutVblankStatus vblank_status;
|
||||||
std::vector<Kernel::EqueueInternal*> flip_events;
|
std::vector<Kernel::OrbisKernelEqueue> flip_events;
|
||||||
std::vector<Kernel::EqueueInternal*> vblank_events;
|
std::vector<Kernel::OrbisKernelEqueue> vblank_events;
|
||||||
std::mutex vo_mutex;
|
std::mutex vo_mutex;
|
||||||
std::mutex port_mutex;
|
std::mutex port_mutex;
|
||||||
std::condition_variable vo_cv;
|
std::condition_variable vo_cv;
|
||||||
|
|||||||
@ -61,7 +61,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::OrbisKernelEqueue eq, s32 handl
|
|||||||
event.data = port;
|
event.data = port;
|
||||||
equeue->AddEvent(event);
|
equeue->AddEvent(event);
|
||||||
|
|
||||||
port->flip_events.push_back(equeue);
|
port->flip_events.push_back(eq);
|
||||||
return ORBIS_OK;
|
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;
|
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||||
}
|
}
|
||||||
equeue->RemoveEvent(handle, Kernel::OrbisKernelEvent::Filter::VideoOut);
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::OrbisKernelEqueue eq, s32 han
|
|||||||
event.data = port;
|
event.data = port;
|
||||||
equeue->AddEvent(event);
|
equeue->AddEvent(event);
|
||||||
|
|
||||||
port->vblank_events.push_back(equeue);
|
port->vblank_events.push_back(eq);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ s32 PS4_SYSV_ABI sceVideoOutDeleteVblankEvent(Kernel::OrbisKernelEqueue eq, s32
|
|||||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||||
}
|
}
|
||||||
equeue->RemoveEvent(handle, Kernel::OrbisKernelEvent::Filter::VideoOut);
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user