diff --git a/src/Core/PS4/HLE/ErrorCodes.h b/src/Core/PS4/HLE/ErrorCodes.h index 9b7d65b8..04edb64e 100644 --- a/src/Core/PS4/HLE/ErrorCodes.h +++ b/src/Core/PS4/HLE/ErrorCodes.h @@ -1,7 +1,7 @@ #pragma once constexpr int SCE_OK = 0; -constexpr int SCE_KERNEL_ERROR_EBADF = 0x80020009; +constexpr int SCE_KERNEL_ERROR_EBADF = 0x80020009; constexpr int SCE_KERNEL_ERROR_ENOMEM = 0x8002000c; // Insufficient memory constexpr int SCE_KERNEL_ERROR_EFAULT = 0x8002000e; // Invalid address pointer constexpr int SCE_KERNEL_ERROR_EINVAL = 0x80020016; // null or invalid states @@ -11,5 +11,7 @@ constexpr int SCE_KERNEL_ERROR_ENAMETOOLONG = 0x8002003f; // character strings // videoOut constexpr int SCE_VIDEO_OUT_ERROR_INVALID_VALUE = 0x80290001; // invalid argument constexpr int SCE_VIDEO_OUT_ERROR_RESOURCE_BUSY = 0x80290009; // already opened +constexpr int SCE_VIDEO_OUT_ERROR_INVALID_INDEX = 0x8029000A; // invalid buffer index constexpr int SCE_VIDEO_OUT_ERROR_INVALID_HANDLE = 0x8029000B; // invalid handle constexpr int SCE_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE = 0x8029000C; // Invalid event queue +constexpr int SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = 0x80290012; // flip queue is full diff --git a/src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.cpp b/src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.cpp index ccf25e92..cdcdfeed 100644 --- a/src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.cpp +++ b/src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.cpp @@ -1,4 +1,5 @@ #include "video_out_ctx.h" +#include namespace HLE::Graphics::Objects { @@ -38,5 +39,28 @@ void FlipQueue::getFlipStatus(VideoConfigInternal* cfg, SceVideoOutFlipStatus* o *out = cfg->m_flip_status; } +bool FlipQueue::submitFlip(VideoConfigInternal* cfg, s32 index, s64 flip_arg) { + Lib::LockMutexGuard lock(m_mutex); + + if (m_requests.size() >= 2) { + return false; + } + + Request r{}; + r.cfg = cfg; + r.index = index; + r.flip_arg = flip_arg; + r.submit_tsc = HLE::Libs::LibKernel::sceKernelReadTsc(); + + m_requests.push_back(r); + + cfg->m_flip_status.flipPendingNum = static_cast(m_requests.size()); + cfg->m_flip_status.gcQueueNum = 0; + + m_submit_cond.SignalCondVar(); + + return true; +} + }; // namespace HLE::Graphics::Objects diff --git a/src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.h b/src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.h index 477ce3eb..570898f2 100644 --- a/src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.h +++ b/src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.h @@ -24,9 +24,19 @@ class FlipQueue { virtual ~FlipQueue() {} void getFlipStatus(VideoConfigInternal* cfg, SceVideoOutFlipStatus* out); - + bool submitFlip(VideoConfigInternal* cfg, s32 index, s64 flip_arg); private: + struct Request { + VideoConfigInternal* cfg; + int index; + int64_t flip_arg; + uint64_t submit_tsc; + }; + Lib::Mutex m_mutex; + Lib::ConditionVariable m_submit_cond; + Lib::ConditionVariable m_done_cond; + std::vector m_requests; }; class VideoOutCtx { diff --git a/src/Core/PS4/HLE/Graphics/video_out.cpp b/src/Core/PS4/HLE/Graphics/video_out.cpp index 26b5813a..1c4020a3 100644 --- a/src/Core/PS4/HLE/Graphics/video_out.cpp +++ b/src/Core/PS4/HLE/Graphics/video_out.cpp @@ -116,9 +116,30 @@ s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle) { return 0; } s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode, s64 flipArg) { - // BREAKPOINT(); - PRINT_DUMMY_FUNCTION_NAME(); - return 0; + PRINT_FUNCTION_NAME(); + auto* videoOut = Singleton::Instance(); + auto* ctx = videoOut->getCtx(handle); + + if (flipMode != 1) { + BREAKPOINT(); // only flipmode==1 is supported + } + if (bufferIndex == -1) { + BREAKPOINT(); // blank output not supported + } + if (bufferIndex < -1 || bufferIndex > 15) { + LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip invalid bufferIndex {}\n",bufferIndex); + return SCE_VIDEO_OUT_ERROR_INVALID_INDEX; + } + LOG_INFO_IF(log_file_videoout, "bufferIndex = {}\n", bufferIndex); + LOG_INFO_IF(log_file_videoout, "flipMode = {}\n", flipMode); + LOG_INFO_IF(log_file_videoout, "flipArg = {}\n", flipArg); + + if (!videoOut->getFlipQueue().submitFlip(ctx, bufferIndex, flipArg)) { + LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flip queue is full\n"); + return SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL; + } + + return SCE_OK; } s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, SceVideoOutFlipStatus* status) { PRINT_FUNCTION_NAME(); diff --git a/src/Core/PS4/HLE/LibKernel.cpp b/src/Core/PS4/HLE/LibKernel.cpp index a35fcb4b..cc86aedb 100644 --- a/src/Core/PS4/HLE/LibKernel.cpp +++ b/src/Core/PS4/HLE/LibKernel.cpp @@ -21,6 +21,11 @@ namespace HLE::Libs::LibKernel { static PS4_SYSV_ABI void stack_chk_fail() { BREAKPOINT(); } + u64 PS4_SYSV_ABI sceKernelReadTsc() { + LARGE_INTEGER c; + QueryPerformanceCounter(&c); + return c.QuadPart; + } void LibKernel_Register(SymbolsResolver* sym) { //obj LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &HLE::Libs::LibKernel::g_stack_chk_guard); @@ -35,6 +40,8 @@ namespace HLE::Libs::LibKernel { //misc LIB_FUNCTION("WslcK1FQcGI", "libkernel", 1, "libkernel", 1, 1, CPUManagement::sceKernelIsNeoMode); LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail); + //time + LIB_FUNCTION("-2IRUCO--PM", "libkernel", 1, "libkernel", 1, 1, sceKernelReadTsc); } }; \ No newline at end of file diff --git a/src/Core/PS4/HLE/LibKernel.h b/src/Core/PS4/HLE/LibKernel.h index 4f4f851a..903aef84 100644 --- a/src/Core/PS4/HLE/LibKernel.h +++ b/src/Core/PS4/HLE/LibKernel.h @@ -6,6 +6,6 @@ void LibKernel_Register(SymbolsResolver* sym); // functions - +u64 PS4_SYSV_ABI sceKernelReadTsc(); int32_t PS4_SYSV_ABI sceKernelReleaseDirectMemory(off_t start, size_t len); }; // namespace HLE::Libs::LibKernel \ No newline at end of file