mirror of
https://github.com/libretro/ppsspp.git
synced 2025-01-19 15:13:10 +00:00
Another frameskipping attempt. Now: 0=no frameskip, 1=auto frameskipt, 2-9=fixed frameskip.
There is still some flicker remaining in non-buffered rendering that I can't seem to get rid off.
This commit is contained in:
parent
94096976ff
commit
664d74a9b7
@ -21,6 +21,7 @@
|
||||
// TODO: Move the relevant parts into common. Don't want the core
|
||||
// to be dependent on "native", I think. Or maybe should get rid of common
|
||||
// and move everything into native...
|
||||
#include "base/logging.h"
|
||||
#include "base/timeutil.h"
|
||||
|
||||
#include "Common/Thread.h"
|
||||
@ -321,7 +322,7 @@ void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) {
|
||||
if (!throttle) {
|
||||
doFrameSkip = true;
|
||||
skipFrame = true;
|
||||
if (numSkippedFrames >= 6) {
|
||||
if (numSkippedFrames >= 7) {
|
||||
skipFrame = false;
|
||||
}
|
||||
return;
|
||||
@ -337,13 +338,21 @@ void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) {
|
||||
if (nextFrameTime == 0.0)
|
||||
nextFrameTime = time_now_d() + timestep;
|
||||
|
||||
if (curFrameTime > nextFrameTime && doFrameSkip) {
|
||||
// Argh, we are falling behind! Let's skip a frame and see if we catch up.
|
||||
skipFrame = true;
|
||||
// INFO_LOG(HLE,"FRAMESKIP %i", numSkippedFrames);
|
||||
|
||||
if (g_Config.iFrameSkip == 1) {
|
||||
// 1 == autoframeskip
|
||||
if (curFrameTime > nextFrameTime && doFrameSkip) {
|
||||
skipFrame = true;
|
||||
}
|
||||
} else if (g_Config.iFrameSkip > 1) {
|
||||
// Other values = fixed frameskip
|
||||
if (numSkippedFrames >= g_Config.iFrameSkip - 1)
|
||||
skipFrame = false;
|
||||
else
|
||||
skipFrame = true;
|
||||
}
|
||||
|
||||
|
||||
if (curFrameTime < nextFrameTime && throttle)
|
||||
{
|
||||
// If time gap is huge just jump (somebody unthrottled)
|
||||
@ -371,12 +380,6 @@ void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) {
|
||||
} else {
|
||||
nextFrameTime = nextFrameTime + timestep;
|
||||
}
|
||||
|
||||
// Max 4 skipped frames in a row - 15 fps is really the bare minimum for playability.
|
||||
// We check for 3 here so it's 3 skipped frames, 1 non skipped, 3 skipped, etc.
|
||||
if (numSkippedFrames >= g_Config.iFrameSkip) {
|
||||
skipFrame = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -404,6 +407,15 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
|
||||
|
||||
CoreTiming::ScheduleEvent(msToCycles(vblankMs) - cyclesLate, leaveVblankEvent, vbCount + 1);
|
||||
|
||||
gpuStats.numVBlanks++;
|
||||
|
||||
numVBlanksSinceFlip++;
|
||||
|
||||
if (g_Config.iShowFPSCounter) {
|
||||
CalculateFPS();
|
||||
}
|
||||
|
||||
|
||||
// TODO: Should this be done here or in hleLeaveVblank?
|
||||
if (framebufIsLatched) {
|
||||
DEBUG_LOG(HLE, "Setting latched framebuffer %08x (prev: %08x)", latchedFramebuf.topaddr, framebuf.topaddr);
|
||||
@ -413,49 +425,47 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
|
||||
gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat);
|
||||
}
|
||||
}
|
||||
|
||||
gpuStats.numVBlanks++;
|
||||
|
||||
numVBlanksSinceFlip++;
|
||||
|
||||
if (g_Config.iShowFPSCounter) {
|
||||
CalculateFPS();
|
||||
}
|
||||
|
||||
// We flip only if the framebuffer was dirty. This eliminates flicker when using
|
||||
// non-buffered rendering. The interaction with frame skipping seems to need
|
||||
// some work.
|
||||
if (gpu->FramebufferDirty()) {
|
||||
gpuStats.numFlips++;
|
||||
// Setting CORE_NEXTFRAME causes a swap.
|
||||
// Check first though, might've just quit / been paused.
|
||||
if (gpu->FramebufferReallyDirty()) {
|
||||
if (coreState == CORE_RUNNING) {
|
||||
coreState = CORE_NEXTFRAME;
|
||||
gpu->CopyDisplayToOutput();
|
||||
}
|
||||
}
|
||||
|
||||
bool wasSkipped = (gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) != 0;
|
||||
gstate_c.skipDrawReason &= ~SKIPDRAW_SKIPFRAME;
|
||||
gpuStats.numFlips++;
|
||||
|
||||
bool throttle, skipFrame;
|
||||
DoFrameTiming(throttle, skipFrame, (float)numVBlanksSinceFlip * (1.0f / 60.0f));
|
||||
|
||||
// Max 4 skipped frames in a row - 15 fps is really the bare minimum for playability.
|
||||
// We check for 3 here so it's 3 skipped frames, 1 non skipped, 3 skipped, etc.
|
||||
int maxFrameskip = throttle ? g_Config.iFrameSkip : 8;
|
||||
if (numSkippedFrames >= maxFrameskip) {
|
||||
skipFrame = false;
|
||||
}
|
||||
|
||||
if (skipFrame) {
|
||||
gstate_c.skipDrawReason |= SKIPDRAW_SKIPFRAME;
|
||||
numSkippedFrames++;
|
||||
} else {
|
||||
// bool wasSkipped = (gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) != 0;
|
||||
gstate_c.skipDrawReason &= ~SKIPDRAW_SKIPFRAME;
|
||||
numSkippedFrames = 0;
|
||||
}
|
||||
|
||||
// Setting CORE_NEXTFRAME causes a swap.
|
||||
// Check first though, might've just quit / been paused.
|
||||
if (!wasSkipped) {
|
||||
if (coreState == CORE_RUNNING) {
|
||||
coreState = CORE_NEXTFRAME;
|
||||
gpu->CopyDisplayToOutput();
|
||||
}
|
||||
}
|
||||
|
||||
// Returning here with coreState == CORE_NEXTFRAME causes a buffer flip to happen (next frame).
|
||||
// Right after, we regain control for a little bit in hleAfterFlip. I think that's a great
|
||||
// place to do housekeeping.
|
||||
CoreTiming::ScheduleEvent(0 - cyclesLate, afterFlipEvent, 0);
|
||||
numVBlanksSinceFlip = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void hleAfterFlip(u64 userdata, int cyclesLate)
|
||||
|
@ -132,7 +132,7 @@ public:
|
||||
//if(dl->status < 0 || dl->status > PSP_GE_LIST_PAUSED)
|
||||
// ERROR_LOG(HLE, "Weird DL status after signal suspend %x", dl->status);
|
||||
if (newState != PSP_GE_DL_STATE_RUNNING)
|
||||
WARN_LOG_REPORT(HLE, "GE Interrupt: newState might be %d", newState);
|
||||
INFO_LOG_REPORT(HLE, "GE Interrupt: newState might be %d", newState);
|
||||
|
||||
dl->state = PSP_GE_DL_STATE_RUNNING;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "gfx_es2/gl_state.h"
|
||||
|
||||
#include "Core/MemMap.h"
|
||||
@ -313,8 +314,31 @@ bool GLES_GPU::FramebufferDirty() {
|
||||
}
|
||||
|
||||
VirtualFramebuffer *vfb = framebufferManager_.GetDisplayFBO();
|
||||
if (vfb)
|
||||
return vfb->dirtyAfterDisplay;
|
||||
if (vfb) {
|
||||
bool dirty = vfb->dirtyAfterDisplay;
|
||||
vfb->dirtyAfterDisplay = false;
|
||||
return dirty;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLES_GPU::FramebufferReallyDirty() {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
if (g_Config.bSeparateCPUThread) {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
ScheduleEvent(GPU_EVENT_PROCESS_QUEUE);
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
VirtualFramebuffer *vfb = framebufferManager_.GetDisplayFBO();
|
||||
if (vfb) {
|
||||
bool dirty = vfb->reallyDirtyAfterDisplay;
|
||||
vfb->reallyDirtyAfterDisplay = false;
|
||||
return dirty;
|
||||
} else {
|
||||
ILOG("reallydirty: No display FBO");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -354,7 +378,11 @@ void GLES_GPU::FastRunLoop(DisplayList &list) {
|
||||
u32 cmd = op >> 24;
|
||||
|
||||
u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
CheckFlushOp(cmd, diff);
|
||||
// Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check.
|
||||
u8 flushCmd = flushBeforeCommand_[cmd];
|
||||
if (flushCmd == 1 || (diff && flushCmd == 2)) {
|
||||
transformDraw_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op;
|
||||
ExecuteOp(op, diff);
|
||||
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
return textureCache_.DecodeTexture(dest, state);
|
||||
}
|
||||
virtual bool FramebufferDirty();
|
||||
virtual bool FramebufferReallyDirty();
|
||||
|
||||
virtual void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) {
|
||||
primaryInfo = reportingPrimaryInfo_;
|
||||
|
@ -451,6 +451,9 @@ void FramebufferManager::DestroyFramebuf(VirtualFramebuffer *v) {
|
||||
void FramebufferManager::SetRenderFrameBuffer() {
|
||||
if (!gstate_c.framebufChanged && currentRenderVfb_) {
|
||||
currentRenderVfb_->last_frame_used = gpuStats.numFlips;
|
||||
currentRenderVfb_->dirtyAfterDisplay = true;
|
||||
if (!gstate_c.skipDrawReason)
|
||||
currentRenderVfb_->reallyDirtyAfterDisplay = true;
|
||||
return;
|
||||
}
|
||||
gstate_c.framebufChanged = false;
|
||||
@ -515,6 +518,8 @@ void FramebufferManager::SetRenderFrameBuffer() {
|
||||
vfb->format = fmt;
|
||||
vfb->usageFlags = FB_USAGE_RENDERTARGET;
|
||||
vfb->dirtyAfterDisplay = true;
|
||||
if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0)
|
||||
vfb->reallyDirtyAfterDisplay = true;
|
||||
vfb->memoryUpdated = false;
|
||||
|
||||
if (g_Config.bTrueColor) {
|
||||
@ -584,6 +589,8 @@ void FramebufferManager::SetRenderFrameBuffer() {
|
||||
vfb->last_frame_used = gpuStats.numFlips;
|
||||
frameLastFramebufUsed = gpuStats.numFlips;
|
||||
vfb->dirtyAfterDisplay = true;
|
||||
if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0)
|
||||
vfb->reallyDirtyAfterDisplay = true;
|
||||
vfb->memoryUpdated = false;
|
||||
|
||||
if (useBufferedRendering_) {
|
||||
@ -631,6 +638,9 @@ void FramebufferManager::SetRenderFrameBuffer() {
|
||||
} else {
|
||||
vfb->last_frame_used = gpuStats.numFlips;
|
||||
frameLastFramebufUsed = gpuStats.numFlips;
|
||||
vfb->dirtyAfterDisplay = true;
|
||||
if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0)
|
||||
vfb->reallyDirtyAfterDisplay = true;
|
||||
}
|
||||
|
||||
// ugly...
|
||||
@ -663,6 +673,7 @@ void FramebufferManager::CopyDisplayToOutput() {
|
||||
|
||||
vfb->usageFlags |= FB_USAGE_DISPLAYED_FRAMEBUFFER;
|
||||
vfb->dirtyAfterDisplay = false;
|
||||
vfb->reallyDirtyAfterDisplay = false;
|
||||
|
||||
if (prevDisplayFramebuf_ != displayFramebuf_) {
|
||||
prevPrevDisplayFramebuf_ = prevDisplayFramebuf_;
|
||||
@ -672,6 +683,10 @@ void FramebufferManager::CopyDisplayToOutput() {
|
||||
}
|
||||
displayFramebuf_ = vfb;
|
||||
|
||||
if (resized_) {
|
||||
ClearBuffer();
|
||||
}
|
||||
|
||||
if (vfb->fbo) {
|
||||
glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight);
|
||||
DEBUG_LOG(HLE, "Displaying FBO %08x", vfb->fb_address);
|
||||
@ -679,16 +694,12 @@ void FramebufferManager::CopyDisplayToOutput() {
|
||||
|
||||
fbo_bind_color_as_texture(vfb->fbo, 0);
|
||||
|
||||
// These are in the output display coordinates
|
||||
// These are in the output display coordinates
|
||||
float x, y, w, h;
|
||||
CenterRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight);
|
||||
DrawActiveTexture(x, y, w, h, true, 480.0f / (float)vfb->width, 272.0f / (float)vfb->height);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
if (resized_) {
|
||||
ClearBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManager::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync) {
|
||||
|
@ -87,6 +87,7 @@ struct VirtualFramebuffer {
|
||||
FBO *fbo;
|
||||
|
||||
bool dirtyAfterDisplay;
|
||||
bool reallyDirtyAfterDisplay; // takes frame skipping into account
|
||||
};
|
||||
|
||||
void CenterRect(float *x, float *y, float *w, float *h,
|
||||
|
@ -39,6 +39,10 @@ public:
|
||||
SyncThread();
|
||||
return true;
|
||||
}
|
||||
virtual bool FramebufferReallyDirty() {
|
||||
SyncThread();
|
||||
return true;
|
||||
}
|
||||
virtual u32 Continue();
|
||||
virtual u32 Break(int mode);
|
||||
virtual void ReapplyGfxState();
|
||||
|
@ -230,6 +230,7 @@ public:
|
||||
// Called by the window system if the window size changed. This will be reflected in PSPCoreParam.pixel*.
|
||||
virtual void Resized() = 0;
|
||||
virtual bool FramebufferDirty() = 0;
|
||||
virtual bool FramebufferReallyDirty() = 0;
|
||||
|
||||
// Debugging
|
||||
virtual void DumpNextFrame() = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user