mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-27 07:20:49 +00:00
Merge pull request #18573 from hrydgard/defer-frame-waits
Defer frame waits if possible
This commit is contained in:
commit
e64299f8e7
@ -32,6 +32,19 @@
|
||||
|
||||
FrameTiming g_frameTiming;
|
||||
|
||||
void WaitUntil(double now, double timestamp) {
|
||||
#ifdef _WIN32
|
||||
while (time_now_d() < timestamp) {
|
||||
sleep_ms(1); // Sleep for 1ms on this thread
|
||||
}
|
||||
#else
|
||||
const double left = timestamp - now;
|
||||
if (left > 0.0) {
|
||||
usleep((long)(left * 1000000));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline Draw::PresentMode GetBestImmediateMode(Draw::PresentMode supportedModes) {
|
||||
if (supportedModes & Draw::PresentMode::MAILBOX) {
|
||||
return Draw::PresentMode::MAILBOX;
|
||||
@ -50,6 +63,22 @@ void FrameTiming::Reset(Draw::DrawContext *draw) {
|
||||
}
|
||||
}
|
||||
|
||||
void FrameTiming::DeferWaitUntil(double until, double *curTimePtr) {
|
||||
_dbg_assert_(until > 0.0);
|
||||
waitUntil_ = until;
|
||||
curTimePtr_ = curTimePtr;
|
||||
}
|
||||
|
||||
void FrameTiming::PostSubmit() {
|
||||
if (waitUntil_ != 0.0) {
|
||||
WaitUntil(time_now_d(), waitUntil_);
|
||||
if (curTimePtr_) {
|
||||
*curTimePtr_ = waitUntil_;
|
||||
}
|
||||
waitUntil_ = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
Draw::PresentMode ComputePresentMode(Draw::DrawContext *draw, int *interval) {
|
||||
Draw::PresentMode mode = Draw::PresentMode::FIFO;
|
||||
|
||||
|
@ -8,14 +8,23 @@ namespace Draw {
|
||||
class DrawContext;
|
||||
}
|
||||
|
||||
struct FrameTiming {
|
||||
class FrameTiming {
|
||||
public:
|
||||
void DeferWaitUntil(double until, double *curTimePtr);
|
||||
void PostSubmit();
|
||||
void Reset(Draw::DrawContext *draw);
|
||||
|
||||
// Some backends won't allow changing this willy nilly.
|
||||
Draw::PresentMode presentMode;
|
||||
int presentInterval;
|
||||
|
||||
void Reset(Draw::DrawContext *draw);
|
||||
private:
|
||||
double waitUntil_;
|
||||
double *curTimePtr_;
|
||||
};
|
||||
|
||||
extern FrameTiming g_frameTiming;
|
||||
|
||||
Draw::PresentMode ComputePresentMode(Draw::DrawContext *draw, int *interval);
|
||||
|
||||
void WaitUntil(double now, double timestamp);
|
||||
|
@ -391,7 +391,7 @@ static void DoFrameDropLogging(float scaledTimestep) {
|
||||
|
||||
// All the throttling and frameskipping logic is here.
|
||||
// This is called just before we drop out of the main loop, in order to allow the submit and present to happen.
|
||||
static void DoFrameTiming(bool throttle, bool *skipFrame, float scaledTimestep) {
|
||||
static void DoFrameTiming(bool throttle, bool *skipFrame, float scaledTimestep, bool endOfFrame) {
|
||||
PROFILE_THIS_SCOPE("timing");
|
||||
*skipFrame = false;
|
||||
|
||||
@ -438,16 +438,15 @@ static void DoFrameTiming(bool throttle, bool *skipFrame, float scaledTimestep)
|
||||
nextFrameTime = curFrameTime;
|
||||
} else {
|
||||
// Wait until we've caught up.
|
||||
while (time_now_d() < nextFrameTime) {
|
||||
#ifdef _WIN32
|
||||
sleep_ms(1); // Sleep for 1ms on this thread
|
||||
#else
|
||||
const double left = nextFrameTime - curFrameTime;
|
||||
usleep((long)(left * 1000000));
|
||||
#endif
|
||||
// If we're ending the frame here, we'll defer the sleep until after the command buffers
|
||||
// have been handed off to the render thread, for some more overlap.
|
||||
if (endOfFrame) {
|
||||
g_frameTiming.DeferWaitUntil(nextFrameTime, &curFrameTime);
|
||||
} else {
|
||||
WaitUntil(curFrameTime, nextFrameTime);
|
||||
curFrameTime = time_now_d(); // I guess we could also just set it to nextFrameTime...
|
||||
}
|
||||
}
|
||||
curFrameTime = time_now_d();
|
||||
}
|
||||
|
||||
lastFrameTime = nextFrameTime;
|
||||
@ -637,9 +636,14 @@ void __DisplayFlip(int cyclesLate) {
|
||||
|
||||
// Setting CORE_NEXTFRAME (which Core_NextFrame does) causes a swap.
|
||||
const bool fbReallyDirty = gpu->FramebufferReallyDirty();
|
||||
|
||||
bool nextFrame = false;
|
||||
|
||||
if (fbReallyDirty || noRecentFlip || postEffectRequiresFlip) {
|
||||
// Check first though, might've just quit / been paused.
|
||||
if (!forceNoFlip && Core_NextFrame()) {
|
||||
if (!forceNoFlip)
|
||||
nextFrame = Core_NextFrame();
|
||||
if (nextFrame) {
|
||||
gpu->CopyDisplayToOutput(fbReallyDirty);
|
||||
if (fbReallyDirty) {
|
||||
DisplayFireActualFlip();
|
||||
@ -659,7 +663,7 @@ void __DisplayFlip(int cyclesLate) {
|
||||
scaledTimestep *= (float)framerate / fpsLimit;
|
||||
}
|
||||
bool skipFrame;
|
||||
DoFrameTiming(throttle, &skipFrame, scaledTimestep);
|
||||
DoFrameTiming(throttle, &skipFrame, scaledTimestep, nextFrame);
|
||||
|
||||
int maxFrameskip = 8;
|
||||
int frameSkipNum = DisplayCalculateFrameSkip();
|
||||
|
@ -1117,6 +1117,7 @@ void NativeFrame(GraphicsContext *graphicsContext) {
|
||||
|
||||
// This, between EndFrame and Present, is where we should actually wait to do present time management.
|
||||
// There might not be a meaningful distinction here for all backends..
|
||||
g_frameTiming.PostSubmit();
|
||||
|
||||
if (renderCounter < 10 && ++renderCounter == 10) {
|
||||
// We're rendering fine, clear out failure info.
|
||||
|
Loading…
Reference in New Issue
Block a user