From b6cc4fe7f9e3521dc4653fbc6f2a83ec4454d886 Mon Sep 17 00:00:00 2001 From: Alex <270190108+CouchRiv@users.noreply.github.com> Date: Sat, 10 Oct 2026 20:08:38 -0400 Subject: [PATCH] feat(videoout): implement sceVideoOutDeleteOutputModeEvent Unsubscribe an event queue from the output mode events that sceVideoOutAddOutputModeEvent registers, the same way the flip and vblank events are removed. Deleting a registration that does not exist succeeds, and a null queue or an invalid handle throws. Co-Authored-By: Gemini 3.8 Flash Co-Authored-By: Claude Sonnet 5.5 --- core/libs/prx/libSceVideoOut/include/Event.hpp | 1 + core/libs/prx/libSceVideoOut/src/Event.cpp | 6 ++++++ core/libs/prx/libSceVideoOut/tests/Flip.cpp | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/core/libs/prx/libSceVideoOut/include/Event.hpp b/core/libs/prx/libSceVideoOut/include/Event.hpp index af8d10be4..46dade9d3 100644 --- a/core/libs/prx/libSceVideoOut/include/Event.hpp +++ b/core/libs/prx/libSceVideoOut/include/Event.hpp @@ -15,6 +15,7 @@ int APS5_VABI sceVideoOutAddVblankEvent(KernelEqueue eq, int handle, void* udata int APS5_VABI sceVideoOutAddVrrActiveStatusEvent(KernelEqueue eq, int handle, void* udata); int APS5_VABI sceVideoOutDeleteFlipEvent(KernelEqueue eq, int handle); +int APS5_VABI sceVideoOutDeleteOutputModeEvent(KernelEqueue eq, int handle); int APS5_VABI sceVideoOutDeletePreVblankStartEvent(KernelEqueue eq, int handle); int APS5_VABI sceVideoOutDeleteVblankEvent(KernelEqueue eq, int handle); diff --git a/core/libs/prx/libSceVideoOut/src/Event.cpp b/core/libs/prx/libSceVideoOut/src/Event.cpp index adef7235c..a4853cd0a 100644 --- a/core/libs/prx/libSceVideoOut/src/Event.cpp +++ b/core/libs/prx/libSceVideoOut/src/Event.cpp @@ -144,6 +144,12 @@ int APS5_VABI sceVideoOutDeleteFlipEvent(KernelEqueue eq, int handle) try { LibcAwaitExit_nid_postfix(); } +int APS5_VABI sceVideoOutDeleteOutputModeEvent(KernelEqueue eq, int handle) try { + return deleteVideoOutEvent(handle, eq, VIDEO_OUT_EVENT_SET_MODE); +} catch (const ProcessShutdown&) { + LibcAwaitExit_nid_postfix(); +} + int APS5_VABI sceVideoOutDeleteVblankEvent(KernelEqueue eq, int handle) try { return deleteVideoOutEvent(handle, eq, VIDEO_OUT_EVENT_VBLANK); } catch (const ProcessShutdown&) { diff --git a/core/libs/prx/libSceVideoOut/tests/Flip.cpp b/core/libs/prx/libSceVideoOut/tests/Flip.cpp index c883e240c..607870626 100644 --- a/core/libs/prx/libSceVideoOut/tests/Flip.cpp +++ b/core/libs/prx/libSceVideoOut/tests/Flip.cpp @@ -307,6 +307,14 @@ void testControls() { check(owner->GetTriggeredEvents(&event, 1) == 1, "initial output mode event missing"); int64_t mode = 0; check(sceVideoOutGetEventData(&event, &mode) == 0 && mode == VIDEO_OUT_OUTPUT_MODE_DEFAULT && sceVideoOutGetEventCount(&event) == 1, "initial output mode event encoding is wrong"); + check(sceVideoOutDeleteOutputModeEvent(queue, handle) == 0, "output mode unsubscription failed"); + { + std::lock_guard lock(cfg->mutex); + check(cfg->outputModeEvents.empty(), "output mode unsubscription did not clear registration"); + } + check(sceVideoOutDeleteOutputModeEvent(queue, handle) == 0, "duplicate output mode unsubscription failed"); + expectFailure([&] { sceVideoOutDeleteOutputModeEvent(0, handle); }); + expectFailure([&] { sceVideoOutDeleteOutputModeEvent(queue, -1); }); check(sceVideoOutAddVblankEvent(queue, handle, nullptr) == 0 && sceVideoOutAddVblankEvent(queue, handle, &settings) == 0, "vblank subscription failed"); { std::lock_guard lock(cfg->mutex);