feat(libSceVideoOut): register the VRR status event and accept the VRR status call
LibwuIonIBw registers video out event id 16, which the host never triggers because its VRR state does not change; kP2L8t3j-aM returns 0 without effect.
This commit is contained in:
parent
bbc4438183
commit
04dec3ddbc
|
|
@ -12,6 +12,7 @@ int APS5_VABI sceVideoOutAddFlipEvent(KernelEqueue eq, int handle, void* udata);
|
|||
int APS5_VABI sceVideoOutAddOutputModeEvent(KernelEqueue eq, int handle, void* udata);
|
||||
int APS5_VABI sceVideoOutAddPreVblankStartEvent(KernelEqueue eq, int handle, void* udata);
|
||||
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 sceVideoOutDeletePreVblankStartEvent(KernelEqueue eq, int handle);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ static constexpr int VIDEO_OUT_EVENT_FLIP = 0;
|
|||
static constexpr int VIDEO_OUT_EVENT_VBLANK = 1;
|
||||
static constexpr int VIDEO_OUT_EVENT_PRE_VBLANK_START = 2;
|
||||
static constexpr int VIDEO_OUT_EVENT_SET_MODE = 8;
|
||||
static constexpr int VIDEO_OUT_EVENT_VRR_STATUS = 16;
|
||||
|
||||
static constexpr int VIDEO_OUT_FLIP_MODE_VSYNC = 1;
|
||||
static constexpr int VIDEO_OUT_FLIP_MODE_VSYNC_MULTI = 4;
|
||||
|
|
@ -116,6 +117,7 @@ struct VideoOutConfig {
|
|||
std::vector<EventRegistration> vblankEvents;
|
||||
std::vector<EventRegistration> preVblankEvents;
|
||||
std::vector<EventRegistration> outputModeEvents;
|
||||
std::vector<EventRegistration> vrrStatusEvents;
|
||||
|
||||
uint32_t width = VIDEO_OUT_DEFAULT_WIDTH;
|
||||
uint32_t height = VIDEO_OUT_DEFAULT_HEIGHT;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ static std::vector<EventRegistration>* getEventList(VideoOutConfig& cfg, int16_t
|
|||
if (eventKind == VIDEO_OUT_EVENT_VBLANK) return &cfg.vblankEvents;
|
||||
if (eventKind == VIDEO_OUT_EVENT_PRE_VBLANK_START) return &cfg.preVblankEvents;
|
||||
if (eventKind == VIDEO_OUT_EVENT_SET_MODE) return &cfg.outputModeEvents;
|
||||
if (eventKind == VIDEO_OUT_EVENT_VRR_STATUS) return &cfg.vrrStatusEvents;
|
||||
throw std::runtime_error("getEventList: unknown event kind");
|
||||
}
|
||||
|
||||
|
|
@ -134,6 +135,13 @@ int APS5_VABI sceVideoOutAddOutputModeEvent(KernelEqueue eq, int handle, void* u
|
|||
LibcAwaitExit_nid_postfix();
|
||||
}
|
||||
|
||||
APS5_EXPORT("LibwuIonIBw", sceVideoOutAddVrrActiveStatusEvent);
|
||||
int APS5_VABI sceVideoOutAddVrrActiveStatusEvent(KernelEqueue eq, int handle, void* udata) try {
|
||||
return registerVideoOutEvent(handle, eq, VIDEO_OUT_EVENT_VRR_STATUS, udata);
|
||||
} catch (const ProcessShutdown&) {
|
||||
LibcAwaitExit_nid_postfix();
|
||||
}
|
||||
|
||||
int APS5_VABI sceVideoOutDeleteFlipEvent(KernelEqueue eq, int handle) try {
|
||||
return deleteVideoOutEvent(handle, eq, VIDEO_OUT_EVENT_FLIP);
|
||||
} catch (const ProcessShutdown&) {
|
||||
|
|
@ -160,7 +168,7 @@ int APS5_VABI sceVideoOutGetEventId(const KernelEvent* ev) {
|
|||
throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_EVENT");
|
||||
}
|
||||
const int ident = static_cast<int>(ev->ident);
|
||||
if (ident != VIDEO_OUT_EVENT_FLIP && ident != VIDEO_OUT_EVENT_VBLANK && ident != VIDEO_OUT_EVENT_PRE_VBLANK_START && ident != VIDEO_OUT_EVENT_SET_MODE) {
|
||||
if (ident != VIDEO_OUT_EVENT_FLIP && ident != VIDEO_OUT_EVENT_VBLANK && ident != VIDEO_OUT_EVENT_PRE_VBLANK_START && ident != VIDEO_OUT_EVENT_SET_MODE && ident != VIDEO_OUT_EVENT_VRR_STATUS) {
|
||||
throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_EVENT");
|
||||
}
|
||||
return ident;
|
||||
|
|
|
|||
|
|
@ -290,20 +290,9 @@ int APS5_VABI sceVideoOutVrrPegToFixedRate() try {
|
|||
LibcAwaitExit_nid_postfix();
|
||||
}
|
||||
|
||||
APS5_EXPORT("kP2L8t3j-aM", sceVideoOutUnknown00);
|
||||
int APS5_VABI sceVideoOutUnknown00() try {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
APS5_EXPORT("kP2L8t3j-aM", sceVideoOutAddVrrStatusFlagsPrivilege);
|
||||
int APS5_VABI sceVideoOutAddVrrStatusFlagsPrivilege() {
|
||||
return 0;
|
||||
} catch (const ProcessShutdown&) {
|
||||
LibcAwaitExit_nid_postfix();
|
||||
}
|
||||
|
||||
APS5_EXPORT("LibwuIonIBw", sceVideoOutUnknown01);
|
||||
int APS5_VABI sceVideoOutUnknown01() try {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
} catch (const ProcessShutdown&) {
|
||||
LibcAwaitExit_nid_postfix();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -342,10 +342,12 @@ bool VideoOutDriver::close(int handle) {
|
|||
removeEvents(cfg->vblankEvents, VIDEO_OUT_EVENT_VBLANK);
|
||||
removeEvents(cfg->preVblankEvents, VIDEO_OUT_EVENT_PRE_VBLANK_START);
|
||||
removeEvents(cfg->outputModeEvents, VIDEO_OUT_EVENT_SET_MODE);
|
||||
removeEvents(cfg->vrrStatusEvents, VIDEO_OUT_EVENT_VRR_STATUS);
|
||||
cfg->flipEvents.clear();
|
||||
cfg->vblankEvents.clear();
|
||||
cfg->preVblankEvents.clear();
|
||||
cfg->outputModeEvents.clear();
|
||||
cfg->vrrStatusEvents.clear();
|
||||
cfg->vblankCond.notify_all();
|
||||
flipQueue->changed.notify_all();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -256,6 +256,11 @@ void testControls() {
|
|||
std::lock_guard lock(cfg->mutex);
|
||||
check(cfg->vblankEvents.size() == 1, "duplicate vblank subscription");
|
||||
}
|
||||
check(sceVideoOutAddVrrActiveStatusEvent(queue, handle, &settings) == 0, "VRR status subscription failed");
|
||||
{
|
||||
std::lock_guard lock(cfg->mutex);
|
||||
check(cfg->vrrStatusEvents.size() == 1, "VRR status subscription was not recorded");
|
||||
}
|
||||
check(sceVideoOutWaitVblank(handle) == 0, "vblank wait failed");
|
||||
check(owner->GetTriggeredEvents(&event, 1) == 1 && event.udata == &settings && sceVideoOutGetEventId(&event) == VIDEO_OUT_EVENT_VBLANK, "vblank event or updated user data missing");
|
||||
std::vector<std::byte> allocation(65536 + 65535);
|
||||
|
|
@ -267,6 +272,11 @@ void testControls() {
|
|||
attribute.pixel_format = 0x8000000000000000ull;
|
||||
check(sceVideoOutRegisterBuffers2(handle, 0, 0, &buffer, 1, &attribute, 0, nullptr) == 0, "buffers with set reserved pointers were rejected");
|
||||
check(sceVideoOutUnregisterBuffers(handle, 0) == 0, "buffer unregistration failed");
|
||||
check(owner->GetTriggeredEvents(&event, 1) == 0, "VRR status event triggered without a VRR change");
|
||||
KernelEvent vrrStatus{};
|
||||
vrrStatus.ident = VIDEO_OUT_EVENT_VRR_STATUS;
|
||||
vrrStatus.filter = EVFILT_VIDEO_OUT;
|
||||
check(sceVideoOutGetEventId(&vrrStatus) == VIDEO_OUT_EVENT_VRR_STATUS, "VRR status event id rejected");
|
||||
sceVideoOutClose(handle);
|
||||
check(owner->GetTriggeredEvents(&event, 1) == 0, "closed port retained pending events");
|
||||
check(sceKernelDeleteEqueue(queue) == 0, "event queue deletion failed");
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- [libSceSystemService](../../core/libs/prx/libSceSystemService/Export.cpp) - `sceSystemServicePowerTick`, `sceSystemServiceReportAbnormalTermination`, `sceSystemServiceDisableMusicPlayer`, `sceSystemServiceReenableMusicPlayer`, `sceSystemServiceDisableMediaPlay` and `sceSystemServiceReenableMediaPlay` return success and do nothing: the host has no auto power-off timer to reset, no system crash reporter to notify, no system music player to pause or resume and no system media playback to disable. PPSA01521 calls `sceSystemServiceDisableMediaPlay` during start-up, and its wrappers for both pass no arguments
|
||||
- [libSceBluetoothHid](../../core/libs/prx/libSceBluetoothHid/Export.cpp) implements only the no-device path: initialization and callback and device registration succeed, the callback is never called because no device connects, and calls that need a connected device throw
|
||||
- [sceVideoOutOpen](../../core/libs/prx/libSceVideoOut/src/Output.cpp) validates the priority and CPU affinity that the open param requests for the VideoOut service thread but does not apply them: the port's present and vblank threads are host threads, and guest priorities and affinities do not reach host scheduling
|
||||
- [sceVideoOutAddVrrStatusFlagsPrivilege](../../core/libs/prx/libSceVideoOut/src/Output.cpp) returns 0 and does nothing: the host output has no VRR state to report. The name comes from an assert message in a title that requires `SCE_VIDEO_OUT_OK`; the NID hashes to it, the arguments are unknown (it is called without any)
|
||||
- Without `VK_KHR_fragment_shader_barycentric` the shader recompiler [does not load the barycentric VGPRs](../../core/shader/recompiler/Translation/src/InstructionTranslator.cpp): [`v_interp_p1_f32` is dropped and `v_interp_p2_f32` reads the attribute Vulkan interpolated](../../core/shader/recompiler/Translation/src/AttributeInstructions.cpp), so pixel shaders that use the barycentrics for anything other than `v_interp` get wrong values.
|
||||
- [libSceAudio3d](../../core/libs/prx/libSceAudio3d/Export.cpp) - the port produces no sound: objects can be reserved but the library has no bed exports or `sceAudio3dObjectSetAttributes` to give them audio, so `sceAudio3dPortPush` only paces the queue at `granularity` samples per frame at 48 kHz. `sceAudio3dPortSetAttribute` accepts the late reverb level and the downmix spread attributes and ignores them
|
||||
- [libSceTextToSpeech2](../../core/libs/prx/libSceTextToSpeech2/Export.cpp) has no speech engine: `sceTextToSpeech2Initialize` fails and the other exports throw. PPSA01317 skips its narration set-up when initialization fails
|
||||
|
|
@ -97,8 +98,6 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- [sceUserServiceGetNpAccountId](../../core/libs/prx/libSceUserService/Export.cpp) (libSceUserService) - the account id for a user with no linked PSN account is assumed to be 0 with success; libSceNpManager's `sceNpGetAccountIdA` answers the same question with `SCE_NP_ERROR_SIGNED_OUT`
|
||||
- [sceUserServiceGetUserColor](../../core/libs/prx/libSceUserService/Export.cpp) (libSceUserService) - the default profile colour is assumed to be blue (0)
|
||||
- [libSceVdecsw](../../core/libs/prx/libSceVdecsw/Export.cpp) (libSceVdecsw) - structure layouts follow shadPS4's `vdecsw.h` and were checked against PPSA05684's movie decoder (`movie-decoder-vdecsw.cpp`), which asserts `pictureCount == 1` at offset 0xb of `OutputInfo` and reads `InputResult` offset 0x10 as the number of frames an access unit produced. The compute, decoder memory and decode input structures and the first 0x28 bytes of the 0x50-byte decoder config are those of libSceVideodec2, and decoding goes through it. The 0x78-byte AVC picture info is filled with Videodec2's leading fields and the cropping fields only. OUTPUT_PENDING (0x81510115), INPUT_QUEUE_EMPTY (0x81510116) and DECODE_PENDING (0x81510117) follow from the codes each call's assert accepts. At most four decoded pictures are queued and the last one is held until `sceVdecswFinalizeDecodeSequence`; the console's queue depth is unknown
|
||||
- [kP2L8t3j-aM](../../core/libs/prx/libSceVideoOut/src/Output.cpp) (libSceVideoOut) - unknown name, signature
|
||||
- [LibwuIonIBw](../../core/libs/prx/libSceVideoOut/src/Output.cpp) (libSceVideoOut) - unknown name, signature
|
||||
- [sceAgcDriverGetEqContextId](../../core/libs/prx/libSceAgcDriver/Eq/src/Query.cpp) (libSceAgcDriver) - returns `ident`: an end-of-pipe interrupt is delivered only to the registration whose id equals the raising queue, so `ident` is that context's id (titles register 0 or 1 for graphics and `0x20 + 8 * pipe + queue` for compute). The console's value is not known; KytyPS5 returns the event's `data`, which it fills with the interrupt's context id, whereas `data` here is the EV_CLEAR trigger count. Other event filters throw
|
||||
- [sceAgcSetSubmitMode](../../core/libs/prx/libSceAgc/Misc/src/Suspend.cpp) (libSceAgc) - mode values unknown; only 0 is accepted
|
||||
- [User data registers](../../core/libs/prx/libSceAgcDriver/Execution/src/Driver/Diagnostics.cpp) (AGC driver) - a `SPI_SHADER_USER_DATA_*` or `COMPUTE_USER_DATA_*` register the title never wrote reads as 0 when a stage's RSRC2 count covers it, as Kyty (zeroed `UserSgprInfo`) and SharpEmu (missing registers read 0) do, and as AMD PAL and Mesa initialize them; the console's value is not confirmed
|
||||
|
|
|
|||
Loading…
Reference in New Issue