diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 1504ae371..38cc024bb 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -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) diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index 405682b57..fd59923dc 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -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; } diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index a022903ec..edc913f7b 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -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); diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index 76a496948..675cb2bff 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -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_; diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 791539795..c56f9b603 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -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) { diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index 3326f4a0f..f7d0243dd 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -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, diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 055706976..8dda336cf 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.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(); diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 9da055b53..0776279bf 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -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;