Skip to content

Commit

Permalink
Fix VideoOut events (#2330)
Browse files Browse the repository at this point in the history
* Fix event data for VideoOut events

Fix is based on some decompilation work shared by red_prig.

* Cleanup

* Oops

* Style fixes

* Clang

* Fix libSceVideoOut event idents

Based on some decompilation work, events coming from libSceVideoOut use a separate set of values for identifiers. These values are only converted to OrbisVideoOutEventId values during calls to sceVideoOutGetEventId.
For convenience, I've placed all relevant identifiers into a enum called OrbisVideoOutInternalEventId.
Thanks to @red_prig for the tips.

* Fix?

Seems like `static_cast<u32>(hint) & 0xFF == event.ident` here, and doing those right shifts on the event.ident winds up breaking stuff.
Without this change, the if always fails because event_id was getting set to 0 instead.

* Clang
  • Loading branch information
StevenMiller123 authored Feb 3, 2025
1 parent 02ad2b7 commit 8ad6505
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 10 deletions.
6 changes: 5 additions & 1 deletion src/core/libraries/kernel/equeue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
std::scoped_lock lock{m_mutex};
for (auto& event : m_events) {
if (event.event.ident == ident && event.event.filter == filter) {
event.Trigger(trigger_data);
if (filter == SceKernelEvent::Filter::VideoOut) {
event.TriggerDisplay(trigger_data);
} else {
event.Trigger(trigger_data);
}
has_found = true;
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/core/libraries/kernel/equeue.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <vector>
#include <boost/asio/steady_timer.hpp>

#include "common/rdtsc.h"
#include "common/types.h"

namespace Core::Loader {
Expand Down Expand Up @@ -81,6 +82,25 @@ struct EqueueEvent {
event.data = reinterpret_cast<uintptr_t>(data);
}

void TriggerDisplay(void* data) {
is_triggered = true;
auto hint = reinterpret_cast<u64>(data);
if (hint != 0) {
auto hint_h = static_cast<u32>(hint >> 8) & 0xFFFFFF;
auto ident_h = static_cast<u32>(event.ident >> 40);
if ((static_cast<u32>(hint) & 0xFF) == event.ident && event.ident != 0xFE &&
((hint_h ^ ident_h) & 0xFF) == 0) {
auto time = Common::FencedRDTSC();
auto mask = 0xF000;
if ((static_cast<u32>(event.data) & 0xF000) != 0xF000) {
mask = (static_cast<u32>(event.data) + 0x1000) & 0xF000;
}
event.data = (mask | static_cast<u64>(static_cast<u32>(time) & 0xFFF) |
(hint & 0xFFFFFFFFFFFF0000));
}
}
}

bool IsTriggered() const {
return is_triggered;
}
Expand Down
10 changes: 6 additions & 4 deletions src/core/libraries/videoout/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,11 @@ void VideoOutDriver::Flip(const Request& req) {
// Trigger flip events for the port.
for (auto& event : port->flip_events) {
if (event != nullptr) {
event->TriggerEvent(u64(OrbisVideoOutEventId::Flip),
Kernel::SceKernelEvent::Filter::VideoOut,
reinterpret_cast<void*>(req.flip_arg));
event->TriggerEvent(
static_cast<u64>(OrbisVideoOutInternalEventId::Flip),
Kernel::SceKernelEvent::Filter::VideoOut,
reinterpret_cast<void*>(static_cast<u64>(OrbisVideoOutInternalEventId::Flip) |
(req.flip_arg << 16)));
}
}

Expand Down Expand Up @@ -323,7 +325,7 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
// Trigger flip events for the port.
for (auto& event : main_port.vblank_events) {
if (event != nullptr) {
event->TriggerEvent(u64(OrbisVideoOutEventId::Vblank),
event->TriggerEvent(static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
Kernel::SceKernelEvent::Filter::VideoOut, nullptr);
}
}
Expand Down
26 changes: 22 additions & 4 deletions src/core/libraries/videoout/video_out.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
}

Kernel::EqueueEvent event{};
event.event.ident = u64(OrbisVideoOutEventId::Flip);
event.event.ident = static_cast<u64>(OrbisVideoOutInternalEventId::Flip);
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
event.event.flags = Kernel::SceKernelEvent::Flags::Add;
event.event.udata = udata;
Expand All @@ -76,7 +76,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl
}

Kernel::EqueueEvent event{};
event.event.ident = u64(OrbisVideoOutEventId::Vblank);
event.event.ident = static_cast<u64>(OrbisVideoOutInternalEventId::Vblank);
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
event.event.flags = Kernel::SceKernelEvent::Flags::Add;
event.event.udata = udata;
Expand Down Expand Up @@ -156,9 +156,27 @@ int PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev) {
return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS;
}
if (ev->filter != Kernel::SceKernelEvent::Filter::VideoOut) {
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT;
}

OrbisVideoOutInternalEventId internal_event_id =
static_cast<OrbisVideoOutInternalEventId>(ev->ident);
switch (internal_event_id) {
case OrbisVideoOutInternalEventId::Flip:
return static_cast<s32>(OrbisVideoOutEventId::Flip);
case OrbisVideoOutInternalEventId::Vblank:
case OrbisVideoOutInternalEventId::SysVblank:
return static_cast<s32>(OrbisVideoOutEventId::Vblank);
case OrbisVideoOutInternalEventId::PreVblankStart:
return static_cast<s32>(OrbisVideoOutEventId::PreVblankStart);
case OrbisVideoOutInternalEventId::SetMode:
return static_cast<s32>(OrbisVideoOutEventId::SetMode);
case OrbisVideoOutInternalEventId::Position:
return static_cast<s32>(OrbisVideoOutEventId::Position);
default: {
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT;
}
}
return ev->ident;
}

int PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, int64_t* data) {
Expand Down
17 changes: 16 additions & 1 deletion src/core/libraries/videoout/video_out.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,22 @@ constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_NONE = 0;
constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_VR = 7;
constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY = 8;

enum class OrbisVideoOutEventId : s16 { Flip = 0, Vblank = 1, PreVblankStart = 2 };
enum class OrbisVideoOutEventId : s16 {
Flip = 0,
Vblank = 1,
PreVblankStart = 2,
SetMode = 8,
Position = 12,
};

enum class OrbisVideoOutInternalEventId : s16 {
Flip = 0x6,
Vblank = 0x7,
SetMode = 0x51,
Position = 0x58,
PreVblankStart = 0x59,
SysVblank = 0x63,
};

enum class AspectRatioMode : s32 {
Ratio16_9 = 0,
Expand Down

0 comments on commit 8ad6505

Please sign in to comment.