Display: Allow threadsafe listeners.

Also add a flip listener.
This commit is contained in:
Unknown W. Brackets 2021-09-19 14:25:20 -07:00
parent ce3b80dcea
commit a06efdd222
2 changed files with 39 additions and 12 deletions

View file

@ -15,10 +15,11 @@
// Official git repository and contact information can be found at // Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <vector>
#include <map>
#include <cmath>
#include <algorithm> #include <algorithm>
#include <cmath>
#include <map>
#include <mutex>
#include <vector>
// TODO: Move this somewhere else, cleanup. // TODO: Move this somewhere else, cleanup.
#ifndef _WIN32 #ifndef _WIN32
@ -130,7 +131,10 @@ std::map<SceUID, int> vblankPausedWaits;
// STATE END // STATE END
// Called when vblank happens (like an internal interrupt.) Not part of state, should be static. // Called when vblank happens (like an internal interrupt.) Not part of state, should be static.
std::vector<VblankCallback> vblankListeners; static std::mutex listenersLock;
static std::vector<VblankCallback> vblankListeners;
typedef std::pair<FlipCallback, void *> FlipListener;
static std::vector<FlipListener> flipListeners;
// The vblank period is 731.5 us (0.7315 ms) // The vblank period is 731.5 us (0.7315 ms)
const double vblankMs = 0.7315; const double vblankMs = 0.7315;
@ -343,21 +347,43 @@ void __DisplayDoState(PointerWrap &p) {
} }
void __DisplayShutdown() { void __DisplayShutdown() {
std::lock_guard<std::mutex> guard(listenersLock);
vblankListeners.clear(); vblankListeners.clear();
flipListeners.clear();
vblankWaitingThreads.clear(); vblankWaitingThreads.clear();
} }
void __DisplayListenVblank(VblankCallback callback) { void __DisplayListenVblank(VblankCallback callback) {
std::lock_guard<std::mutex> guard(listenersLock);
vblankListeners.push_back(callback); vblankListeners.push_back(callback);
} }
static void __DisplayFireVblank() { void __DisplayListenFlip(FlipCallback callback, void *userdata) {
for (std::vector<VblankCallback>::iterator iter = vblankListeners.begin(), end = vblankListeners.end(); iter != end; ++iter) { std::lock_guard<std::mutex> guard(listenersLock);
VblankCallback cb = *iter; flipListeners.push_back(std::make_pair(callback, userdata));
}
void __DisplayForgetFlip(FlipCallback callback, void *userdata) {
std::lock_guard<std::mutex> 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<std::mutex> guard(listenersLock);
for (VblankCallback cb : vblankListeners) {
cb(); cb();
} }
} }
static void DisplayFireFlip() {
std::lock_guard<std::mutex> guard(listenersLock);
for (auto cb : flipListeners) {
cb.first(cb.second);
}
}
void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId) { void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId) {
SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId;
@ -742,6 +768,7 @@ void __DisplayFlip(int cyclesLate) {
if (fbDirty || noRecentFlip || postEffectRequiresFlip) { if (fbDirty || noRecentFlip || postEffectRequiresFlip) {
int frameSleepPos = frameTimeHistoryPos; int frameSleepPos = frameTimeHistoryPos;
CalculateFPS(); CalculateFPS();
DisplayFireFlip();
// Let the user know if we're running slow, so they know to adjust settings. // Let the user know if we're running slow, so they know to adjust settings.
// Sometimes users just think the sound emulation is broken. // 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); CoreTiming::ScheduleEvent(msToCycles(frameMs - vblankMs) - cyclesLate, enterVblankEvent, userdata);
// Fire the vblank listeners after the vblank completes. // Fire the vblank listeners after the vblank completes.
__DisplayFireVblank(); DisplayFireVblank();
} }
void hleLagSync(u64 userdata, int cyclesLate) { void hleLagSync(u64 userdata, int cyclesLate) {

View file

@ -25,16 +25,16 @@ void __DisplayShutdown();
void Register_sceDisplay(); void Register_sceDisplay();
// will return true once after every end-of-frame.
bool __DisplayFrameDone();
// Get information about the current framebuffer. // Get information about the current framebuffer.
bool __DisplayGetFramebuf(PSPPointer<u8> *topaddr, u32 *linesize, u32 *pixelFormat, int mode); bool __DisplayGetFramebuf(PSPPointer<u8> *topaddr, u32 *linesize, u32 *pixelFormat, int mode);
void __DisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync); void __DisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync);
typedef void (*VblankCallback)(); typedef void (*VblankCallback)();
// Listen for vblank events. Only register during init. // Listen for vblank events.
void __DisplayListenVblank(VblankCallback callback); 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 __DisplayGetDebugStats(char stats[], size_t bufsize);
void __DisplayGetFPS(float *out_vps, float *out_fps, float *out_actual_fps); void __DisplayGetFPS(float *out_vps, float *out_fps, float *out_actual_fps);