Display: Allow threadsafe listeners.
Also add a flip listener.
This commit is contained in:
parent
ce3b80dcea
commit
a06efdd222
2 changed files with 39 additions and 12 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue