videoout: added sceVideoOutWaitVblank

This commit is contained in:
psucien 2024-07-20 11:18:04 +02:00 committed by IndecisiveTurtle
parent 621d50e681
commit 4d3b993285
5 changed files with 31 additions and 32 deletions

View File

@ -78,9 +78,7 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
for (auto& event : m_events) { for (auto& event : m_events) {
ASSERT_MSG(event.event.filter == filter, if ((event.event.ident == ident) && (event.event.filter == filter)) {
"Event to trigger doesn't match to queue events");
if (event.event.ident == ident) {
event.Trigger(trigger_data); event.Trigger(trigger_data);
has_found = true; has_found = true;
} }

View File

@ -234,28 +234,10 @@ bool VideoOutDriver::SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg,
port->flip_status.flipPendingNum = static_cast<int>(requests.size()); port->flip_status.flipPendingNum = static_cast<int>(requests.size());
port->flip_status.gcQueueNum = 0; port->flip_status.gcQueueNum = 0;
submit_cond.notify_one();
return true; return true;
} }
void VideoOutDriver::Vblank() {
std::scoped_lock lock{mutex};
auto& vblank_status = main_port.vblank_status;
vblank_status.count++;
vblank_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
vblank_status.tsc = Libraries::Kernel::sceKernelReadTsc();
// Trigger flip events for the port.
for (auto& event : main_port.vblank_events) {
if (event != nullptr) {
event->TriggerEvent(SCE_VIDEO_OUT_EVENT_VBLANK,
Kernel::SceKernelEvent::Filter::VideoOut, nullptr);
}
}
}
void VideoOutDriver::PresentThread(std::stop_token token) { void VideoOutDriver::PresentThread(std::stop_token token) {
static constexpr std::chrono::microseconds VblankPeriod{16683}; static constexpr std::chrono::microseconds VblankPeriod{16683};
Common::SetCurrentThreadName("VblankThread"); Common::SetCurrentThreadName("VblankThread");
@ -283,9 +265,15 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
delay = Flip(request); delay = Flip(request);
FRAME_END; FRAME_END;
} }
{
// Needs lock here as can be concurrently read by `sceVideoOutGetVblankStatus`
std::unique_lock lock{main_port.vo_mutex};
vblank_status.count++; vblank_status.count++;
vblank_status.processTime = Libraries::Kernel::sceKernelGetProcessTime(); vblank_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
vblank_status.tsc = Libraries::Kernel::sceKernelReadTsc(); vblank_status.tsc = Libraries::Kernel::sceKernelReadTsc();
main_port.vblank_cv.notify_all();
}
// 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) {

View File

@ -3,11 +3,13 @@
#pragma once #pragma once
#include "common/debug.h"
#include "common/polyfill_thread.h"
#include "core/libraries/videoout/video_out.h"
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
#include <queue> #include <queue>
#include "common/polyfill_thread.h"
#include "core/libraries/videoout/video_out.h"
namespace Vulkan { namespace Vulkan {
struct Frame; struct Frame;
@ -28,6 +30,7 @@ struct VideoOutPort {
std::vector<Kernel::SceKernelEqueue> vblank_events; std::vector<Kernel::SceKernelEqueue> vblank_events;
std::mutex vo_mutex; std::mutex vo_mutex;
std::condition_variable vo_cv; std::condition_variable vo_cv;
std::condition_variable vblank_cv;
int flip_rate = 0; int flip_rate = 0;
s32 FindFreeGroup() const { s32 FindFreeGroup() const {
@ -84,8 +87,6 @@ public:
bool SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false); bool SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false);
void Vblank();
private: private:
struct Request { struct Request {
Vulkan::Frame* frame; Vulkan::Frame* frame;
@ -105,11 +106,8 @@ private:
std::mutex mutex; std::mutex mutex;
VideoOutPort main_port{}; VideoOutPort main_port{};
std::condition_variable_any submit_cond;
std::condition_variable done_cond;
std::jthread present_thread; std::jthread present_thread;
std::queue<Request> requests; std::queue<Request> requests;
bool is_neo{};
}; };
} // namespace Libraries::VideoOut } // namespace Libraries::VideoOut

View File

@ -183,6 +183,7 @@ s32 PS4_SYSV_ABI sceVideoOutGetVblankStatus(int handle, SceVideoOutVblankStatus*
return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE; return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE;
} }
std::unique_lock lock{port->vo_mutex};
*status = port->vblank_status; *status = port->vblank_status;
return ORBIS_OK; return ORBIS_OK;
} }
@ -258,6 +259,18 @@ s32 PS4_SYSV_ABI sceVideoOutGetDeviceCapabilityInfo(
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceVideoOutWaitVblank(s32 handle) {
auto* port = driver->GetPort(handle);
if (!port) {
return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE;
}
std::unique_lock lock{port->vo_mutex};
const auto prev_counter = port->vblank_status.count;
port->vblank_cv.wait(lock, [&]() { return prev_counter != port->vblank_status.count; });
return ORBIS_OK;
}
void RegisterLib(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
driver = std::make_unique<VideoOutDriver>(Config::getScreenWidth(), Config::getScreenHeight()); driver = std::make_unique<VideoOutDriver>(Config::getScreenWidth(), Config::getScreenHeight());
@ -286,6 +299,7 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
sceVideoOutGetVblankStatus); sceVideoOutGetVblankStatus);
LIB_FUNCTION("kGVLc3htQE8", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, LIB_FUNCTION("kGVLc3htQE8", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
sceVideoOutGetDeviceCapabilityInfo); sceVideoOutGetDeviceCapabilityInfo);
LIB_FUNCTION("j6RaAUlaLv0", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutWaitVblank);
// openOrbis appears to have libSceVideoOut_v1 module libSceVideoOut_v1.1 // openOrbis appears to have libSceVideoOut_v1 module libSceVideoOut_v1.1
LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutOpen); LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutOpen);

View File

@ -92,11 +92,12 @@ void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(BufferAttribute* attribute, Pixe
u32 tilingMode, u32 aspectRatio, u32 width, u32 tilingMode, u32 aspectRatio, u32 width,
u32 height, u32 pitchInPixel); u32 height, u32 pitchInPixel);
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata); s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata);
s32 PS4_SYSV_ABI sceVideoOutAddVBlankEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata); s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata);
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses, s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses,
s32 bufferNum, const BufferAttribute* attribute); s32 bufferNum, const BufferAttribute* attribute);
s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate); s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate);
s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle); s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle);
s32 PS4_SYSV_ABI sceVideoOutWaitVblank(s32 handle);
s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode, s64 flipArg); s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode, s64 flipArg);
s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, FlipStatus* status); s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, FlipStatus* status);
s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status); s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status);