diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index d18955ddde..9757186a0b 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -15,10 +15,11 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include -#include -#include #include +#include +#include +#include +#include // TODO: Move this somewhere else, cleanup. #ifndef _WIN32 @@ -130,7 +131,10 @@ std::map vblankPausedWaits; // STATE END // Called when vblank happens (like an internal interrupt.) Not part of state, should be static. -std::vector vblankListeners; +static std::mutex listenersLock; +static std::vector vblankListeners; +typedef std::pair FlipListener; +static std::vector flipListeners; // The vblank period is 731.5 us (0.7315 ms) const double vblankMs = 0.7315; @@ -343,21 +347,43 @@ void __DisplayDoState(PointerWrap &p) { } void __DisplayShutdown() { + std::lock_guard guard(listenersLock); vblankListeners.clear(); + flipListeners.clear(); vblankWaitingThreads.clear(); } void __DisplayListenVblank(VblankCallback callback) { + std::lock_guard guard(listenersLock); vblankListeners.push_back(callback); } -static void __DisplayFireVblank() { - for (std::vector::iterator iter = vblankListeners.begin(), end = vblankListeners.end(); iter != end; ++iter) { - VblankCallback cb = *iter; +void __DisplayListenFlip(FlipCallback callback, void *userdata) { + std::lock_guard guard(listenersLock); + flipListeners.push_back(std::make_pair(callback, userdata)); +} + +void __DisplayForgetFlip(FlipCallback callback, void *userdata) { + std::lock_guard guard(listenersLock); + flipListeners.erase(std::remove_if(flipListeners.begin(), flipListeners.end(), [&](FlipListener item) { + return item.first == callback && item.second == userdata; + }), flipListeners.end()); +} + +static void DisplayFireVblank() { + std::lock_guard guard(listenersLock); + for (VblankCallback cb : vblankListeners) { cb(); } } +static void DisplayFireFlip() { + std::lock_guard guard(listenersLock); + for (auto cb : flipListeners) { + cb.first(cb.second); + } +} + void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId) { SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; @@ -742,6 +768,7 @@ void __DisplayFlip(int cyclesLate) { if (fbDirty || noRecentFlip || postEffectRequiresFlip) { int frameSleepPos = frameTimeHistoryPos; CalculateFPS(); + DisplayFireFlip(); // Let the user know if we're running slow, so they know to adjust settings. // Sometimes users just think the sound emulation is broken. @@ -848,7 +875,7 @@ void hleLeaveVblank(u64 userdata, int cyclesLate) { CoreTiming::ScheduleEvent(msToCycles(frameMs - vblankMs) - cyclesLate, enterVblankEvent, userdata); // Fire the vblank listeners after the vblank completes. - __DisplayFireVblank(); + DisplayFireVblank(); } void hleLagSync(u64 userdata, int cyclesLate) { diff --git a/Core/HLE/sceDisplay.h b/Core/HLE/sceDisplay.h index 47294c56d7..ab0871894e 100644 --- a/Core/HLE/sceDisplay.h +++ b/Core/HLE/sceDisplay.h @@ -25,16 +25,16 @@ void __DisplayShutdown(); void Register_sceDisplay(); -// will return true once after every end-of-frame. -bool __DisplayFrameDone(); - // Get information about the current framebuffer. bool __DisplayGetFramebuf(PSPPointer *topaddr, u32 *linesize, u32 *pixelFormat, int mode); void __DisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync); typedef void (*VblankCallback)(); -// Listen for vblank events. Only register during init. +// Listen for vblank events. void __DisplayListenVblank(VblankCallback callback); +typedef void (*FlipCallback)(void *userdata); +void __DisplayListenFlip(FlipCallback callback, void *userdata); +void __DisplayForgetFlip(FlipCallback callback, void *userdata); void __DisplayGetDebugStats(char stats[], size_t bufsize); void __DisplayGetFPS(float *out_vps, float *out_fps, float *out_actual_fps);