From c15e9f2a374366ace0cc2348d5b727ed31011466 Mon Sep 17 00:00:00 2001 From: babyhuey <7751607+babyhuey@users.noreply.github.com> Date: Mon, 12 Oct 2026 20:26:26 -0400 Subject: [PATCH] fix(libSceVideoOut): return RESOURCE_BUSY when a bus is opened twice --- core/libs/prx/libSceVideoOut/src/Output.cpp | 4 +--- core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp | 2 +- core/libs/tests/GuestVideoOutOutputMode.cpp | 2 ++ docs/dev/debt/libSceVideoOut.md | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/libs/prx/libSceVideoOut/src/Output.cpp b/core/libs/prx/libSceVideoOut/src/Output.cpp index f47aac9f3..2a333efcc 100644 --- a/core/libs/prx/libSceVideoOut/src/Output.cpp +++ b/core/libs/prx/libSceVideoOut/src/Output.cpp @@ -80,9 +80,7 @@ int APS5_VABI sceVideoOutOpen(int userId, int busType, int index, const void* pa throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_VALUE"); } const int handle = VideoOutDriver::Get().Open(busType); - if (handle < 0) { - throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_RESOURCE_BUSY"); - } + if (handle < 0) return VIDEO_OUT_ERROR_RESOURCE_BUSY; return handle; } catch (const ProcessShutdown&) { LibcAwaitExit_nid_postfix(); diff --git a/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp b/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp index f605f9dbb..ed2e7538b 100644 --- a/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp +++ b/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp @@ -336,7 +336,7 @@ int VideoOutDriver::Open(int busType) { uint64_t generation = 1; if (previous) { std::lock_guard cfgLock(previous->mutex); - require(!previous->opened, "port already open"); + if (previous->opened) return -1; require(previous->generation != std::numeric_limits::max(), "port generation overflow"); generation = previous->generation + 1; } diff --git a/core/libs/tests/GuestVideoOutOutputMode.cpp b/core/libs/tests/GuestVideoOutOutputMode.cpp index da708754d..4bed080a1 100644 --- a/core/libs/tests/GuestVideoOutOutputMode.cpp +++ b/core/libs/tests/GuestVideoOutOutputMode.cpp @@ -21,6 +21,7 @@ static constexpr int MAIN_BUS = 0; static constexpr int INVALID_VALUE = static_cast(0x80290001); static constexpr int INVALID_ADDRESS = static_cast(0x80290002); static constexpr int INVALID_HANDLE = static_cast(0x8029000B); +static constexpr int RESOURCE_BUSY = static_cast(0x80290009); static constexpr int UNSUPPORTED_OUTPUT_MODE = static_cast(0x80290016); static constexpr int UNKNOWN_OUTPUT_MODE = static_cast(0x8029001E); @@ -50,6 +51,7 @@ int main() { return 77; } Require(handle > 0); + Require(sceVideoOutOpen(SYSTEM_USER, MAIN_BUS, 0, nullptr) == RESOURCE_BUSY); Require(sceVideoOutIsOutputSupported(handle, 1, &options, nullptr, 0) == 1); Require(sceVideoOutIsOutputSupported(handle, 1, nullptr, nullptr, 0) == 1); const int highFrameRate = sceVideoOutIsOutputSupported(handle, 15, &options, nullptr, 0); diff --git a/docs/dev/debt/libSceVideoOut.md b/docs/dev/debt/libSceVideoOut.md index 3a7fc1e81..1d7c81853 100644 --- a/docs/dev/debt/libSceVideoOut.md +++ b/docs/dev/debt/libSceVideoOut.md @@ -20,4 +20,5 @@ ### Functional +- [sceVideoOutOpen](../../../core/libs/prx/libSceVideoOut/src/Output.cpp) (libSceVideoOut) - opening a bus that is already open returns `SCE_VIDEO_OUT_ERROR_RESOURCE_BUSY` (`0x80290009`), as [shadPS4's](https://github.com/shadps4-emu/shadPS4/blob/e0a466753a1aacbc8db8253be685bf7ab4d9daae/src/core/libraries/videoout/driver.cpp#L53-L60) PS4 driver does for its main port; the PS5 result is unverified. PPSA99764 opens the main bus twice and carries on, presenting through the first handle - [Overlay output bus](../../../core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp) (libSceVideoOut) - flips on a port opened with `SCE_VIDEO_OUT_BUS_TYPE_OVERLAY` complete and signal their events like main-bus flips, but their buffers are not shown: the overlay is not composited over the main output. Presenting them as whole frames made the window alternate between the two buses