diff --git a/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp b/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp index 19adde40e..ee5fa36a2 100644 --- a/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp +++ b/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp @@ -394,6 +394,7 @@ void VideoOutDriver::processFlip(FlipRequest& req) { req.cfg->vblankCond.wait(lock, req.cfg->shutdownToken, [&] { return req.cfg->vblankStatus.count >= target || req.cfg->failure || req.cfg->closing; }); timing.Mark("vblank_wait"); checkConfig(*req.cfg); + req.cfg->lastFlipVblank = req.cfg->vblankStatus.count; } require(req.width != 0 && req.height != 0 && req.width <= static_cast(std::numeric_limits::max()) && req.height <= static_cast(std::numeric_limits::max()), "invalid window dimensions"); window.Ensure(req.width, req.height); @@ -444,7 +445,6 @@ void VideoOutDriver::processFlip(FlipRequest& req) { require(req.cfg->flipStatus.count != std::numeric_limits::max(), "flip counter overflow"); triggerEvents(*req.cfg, VIDEO_OUT_EVENT_FLIP, reinterpret_cast(req.flipArg)); ++req.cfg->flipStatus.count; - req.cfg->lastFlipVblank = req.cfg->vblankStatus.count; req.cfg->flipStatus.processTime = sceKernelGetProcessTime(); req.cfg->flipStatus.processTimeCounter = sceKernelGetProcessTimeCounter(); req.cfg->flipStatus.flipArg = req.flipArg; diff --git a/core/libs/prx/libSceVideoOut/tests/Flip.cpp b/core/libs/prx/libSceVideoOut/tests/Flip.cpp index 3949f3575..ba4c375fa 100644 --- a/core/libs/prx/libSceVideoOut/tests/Flip.cpp +++ b/core/libs/prx/libSceVideoOut/tests/Flip.cpp @@ -273,6 +273,31 @@ void testBackToBack() { LibcRunShutdown_nid_postfix(); } +void testReleaseVblank() { + const int handle = sceVideoOutOpen(255, 0, 0, nullptr); + auto cfg = VideoOutDriver::Get().GetConfig(handle); + std::vector allocation(6 * 65536 + 65535); + const auto storage = alignedBuffer(allocation); + fillBuffer(storage, 259, 137); + VideoOutBuffers buffer{storage.data(), nullptr, {nullptr, nullptr}}; + VideoOutBufferAttribute2 attribute{}; + sceVideoOutSetBufferAttribute2(&attribute, 0x8000000000000000ull, 0, 259, 137, 0, 0, 0); + sceVideoOutRegisterBuffers2(handle, 0, 0, &buffer, 1, &attribute, 0, nullptr); + check(sceVideoOutSetFlipRate(handle, 2) == 0, "flip rate was not applied"); + sceVideoOutSubmitFlip(handle, 0, 1, 1); + { + std::unique_lock lock(cfg->mutex); + const bool done = cfg->vblankCond.wait_for(lock, std::chrono::seconds(15), [&] { return cfg->failure || cfg->flipStatus.count == 1; }); + if (cfg->failure) std::rethrow_exception(cfg->failure); + check(done, "the flip did not complete"); + check(cfg->vblankStatus.count > 3, "the first presentation did not outlast the vblank it was released at"); + check(cfg->lastFlipVblank == 3, "the next flip is not paced from the vblank this flip was released at"); + } + sceVideoOutUnregisterBuffers(handle, 0); + sceVideoOutClose(handle); + LibcRunShutdown_nid_postfix(); +} + } int main(int argc, char** argv) { @@ -281,6 +306,7 @@ int main(int argc, char** argv) { else if (argc == 2 && std::string(argv[1]) == "controls") testControls(); else if (argc == 2 && std::string(argv[1]) == "present") testPresentation(false); else if (argc == 2 && std::string(argv[1]) == "backtoback") testBackToBack(); + else if (argc == 2 && std::string(argv[1]) == "pacing") testReleaseVblank(); else if (argc == 2 && std::string(argv[1]) == "unavailable") testPresentation(true); else testLifetime(argc == 2 && std::string(argv[1]) == "reopen"); std::puts("VideoOut flip tests passed");