mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Restructure Windows "gameloop" to be more similar to others.
This commit is contained in:
parent
f8058e4bae
commit
cbb786c7f0
@ -22,6 +22,9 @@
|
||||
#include "Core.h"
|
||||
#include "MemMap.h"
|
||||
#include "MIPS/MIPS.h"
|
||||
#ifdef _WIN32
|
||||
#include "Windows/OpenGLBase.h"
|
||||
#endif
|
||||
|
||||
#include "Host.h"
|
||||
|
||||
@ -64,7 +67,16 @@ bool Core_IsStepping()
|
||||
|
||||
void Core_RunLoop()
|
||||
{
|
||||
currentMIPS->RunLoopUntil(0xFFFFFFFFFFFFFFFULL);
|
||||
while (!coreState) {
|
||||
currentMIPS->RunLoopUntil(0xFFFFFFFFFFFFFFFULL);
|
||||
if (coreState == CORE_NEXTFRAME)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
GL_SwapBuffers();
|
||||
#endif
|
||||
coreState = CORE_RUNNING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Core_DoSingleStep()
|
||||
|
@ -80,6 +80,7 @@ static bool framebufIsLatched;
|
||||
|
||||
static int enterVblankEvent = -1;
|
||||
static int leaveVblankEvent = -1;
|
||||
static int afterFlipEvent = -1;
|
||||
|
||||
static int hCount;
|
||||
static int hCountTotal; //unused
|
||||
@ -107,6 +108,7 @@ enum {
|
||||
|
||||
void hleEnterVblank(u64 userdata, int cyclesLate);
|
||||
void hleLeaveVblank(u64 userdata, int cyclesLate);
|
||||
void hleAfterFlip(u64 userdata, int cyclesLate);
|
||||
|
||||
void __DisplayInit() {
|
||||
gpuStats.reset();
|
||||
@ -118,6 +120,7 @@ void __DisplayInit() {
|
||||
|
||||
enterVblankEvent = CoreTiming::RegisterEvent("EnterVBlank", &hleEnterVblank);
|
||||
leaveVblankEvent = CoreTiming::RegisterEvent("LeaveVBlank", &hleLeaveVblank);
|
||||
afterFlipEvent = CoreTiming::RegisterEvent("AfterFlip", &hleAfterFlip);
|
||||
|
||||
CoreTiming::ScheduleEvent(msToCycles(frameMs - vblankMs), enterVblankEvent, 0);
|
||||
isVblank = 0;
|
||||
@ -202,6 +205,93 @@ float calculateFPS()
|
||||
return fps;
|
||||
}
|
||||
|
||||
void DebugStats()
|
||||
{
|
||||
gpu->UpdateStats();
|
||||
char stats[2048];
|
||||
|
||||
sprintf(stats,
|
||||
"Frames: %i\n"
|
||||
"DL processing time: %0.2f ms\n"
|
||||
"Kernel processing time: %0.2f ms\n"
|
||||
"Slowest syscall: %s : %0.2f ms\n"
|
||||
"Most active syscall: %s : %0.2f ms\n"
|
||||
"Draw calls: %i, flushes %i\n"
|
||||
"Cached Draw calls: %i\n"
|
||||
"Num Tracked Vertex Arrays: %i\n"
|
||||
"Vertices Submitted: %i\n"
|
||||
"Cached Vertices Drawn: %i\n"
|
||||
"Uncached Vertices Drawn: %i\n"
|
||||
"FBOs active: %i\n"
|
||||
"Textures active: %i, decoded: %i\n"
|
||||
"Texture invalidations: %i\n"
|
||||
"Vertex shaders loaded: %i\n"
|
||||
"Fragment shaders loaded: %i\n"
|
||||
"Combined shaders loaded: %i\n",
|
||||
gpuStats.numFrames,
|
||||
gpuStats.msProcessingDisplayLists * 1000.0f,
|
||||
kernelStats.msInSyscalls * 1000.0f,
|
||||
kernelStats.slowestSyscallName ? kernelStats.slowestSyscallName : "(none)",
|
||||
kernelStats.slowestSyscallTime * 1000.0f,
|
||||
kernelStats.summedSlowestSyscallName ? kernelStats.summedSlowestSyscallName : "(none)",
|
||||
kernelStats.summedSlowestSyscallTime * 1000.0f,
|
||||
gpuStats.numDrawCalls,
|
||||
gpuStats.numFlushes,
|
||||
gpuStats.numCachedDrawCalls,
|
||||
gpuStats.numTrackedVertexArrays,
|
||||
gpuStats.numVertsSubmitted,
|
||||
gpuStats.numCachedVertsDrawn,
|
||||
gpuStats.numUncachedVertsDrawn,
|
||||
gpuStats.numFBOs,
|
||||
gpuStats.numTextures,
|
||||
gpuStats.numTexturesDecoded,
|
||||
gpuStats.numTextureInvalidations,
|
||||
gpuStats.numVertexShaders,
|
||||
gpuStats.numFragmentShaders,
|
||||
gpuStats.numShaders
|
||||
);
|
||||
|
||||
float zoom = 0.3f; /// g_Config.iWindowZoom;
|
||||
float soff = 0.3f;
|
||||
PPGeBegin();
|
||||
PPGeDrawText(stats, soff, soff, 0, zoom, 0xCC000000);
|
||||
PPGeDrawText(stats, -soff, -soff, 0, zoom, 0xCC000000);
|
||||
PPGeDrawText(stats, 0, 0, 0, zoom, 0xFFFFFFFF);
|
||||
PPGeEnd();
|
||||
|
||||
gpuStats.resetFrame();
|
||||
kernelStats.ResetFrame();
|
||||
}
|
||||
|
||||
// Let's collect all the throttling and frameskipping logic here.
|
||||
void DoFrameTiming(bool &throttle) {
|
||||
#ifdef _WIN32
|
||||
throttle = !GetAsyncKeyState(VK_TAB);
|
||||
#else
|
||||
throttle = false;
|
||||
#endif
|
||||
if (PSP_CoreParameter().headLess)
|
||||
throttle = false;
|
||||
|
||||
if (throttle) {
|
||||
// Best place to throttle the frame rate on non vsynced platforms is probably here. Let's try it.
|
||||
time_update();
|
||||
if (lastFrameTime == 0.0)
|
||||
lastFrameTime = time_now_d();
|
||||
|
||||
// First, check if we are already behind.
|
||||
// Wait until it's time.
|
||||
while (time_now_d() < lastFrameTime + 1.0 / 60.0) {
|
||||
Common::SleepCurrentThread(1);
|
||||
time_update();
|
||||
}
|
||||
// Advance lastFrameTime by a constant amount each frame,
|
||||
// but don't let it get too far behind.
|
||||
lastFrameTime = std::max(lastFrameTime + 1.0 / 60.0, time_now_d() - 1.5 / 60.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hleEnterVblank(u64 userdata, int cyclesLate) {
|
||||
int vbCount = userdata;
|
||||
|
||||
@ -223,7 +313,7 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
|
||||
// Trigger VBlank interrupt handlers.
|
||||
__TriggerInterrupt(PSP_INTR_IMMEDIATE | PSP_INTR_ONLY_IF_ENABLED | PSP_INTR_ALWAYS_RESCHED, PSP_VBLANK_INTR, PSP_INTR_SUB_ALL);
|
||||
|
||||
CoreTiming::ScheduleEvent(msToCycles(vblankMs) - cyclesLate, leaveVblankEvent, vbCount+1);
|
||||
CoreTiming::ScheduleEvent(msToCycles(vblankMs) - cyclesLate, leaveVblankEvent, vbCount + 1);
|
||||
|
||||
// TODO: Should this be done here or in hleLeaveVblank?
|
||||
if (framebufIsLatched) {
|
||||
@ -233,65 +323,11 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
|
||||
gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat);
|
||||
}
|
||||
|
||||
// Draw screen overlays before blitting. Saves and restores the Ge context.
|
||||
gpuStats.numFrames++;
|
||||
|
||||
// Now we can subvert the Ge engine in order to draw custom overlays like stat counters etc.
|
||||
if (g_Config.bShowDebugStats && gpuStats.numDrawCalls) {
|
||||
gpu->UpdateStats();
|
||||
char stats[2048];
|
||||
|
||||
sprintf(stats,
|
||||
"Frames: %i\n"
|
||||
"DL processing time: %0.2f ms\n"
|
||||
"Kernel processing time: %0.2f ms\n"
|
||||
"Slowest syscall: %s : %0.2f ms\n"
|
||||
"Most active syscall: %s : %0.2f ms\n"
|
||||
"Draw calls: %i, flushes %i\n"
|
||||
"Cached Draw calls: %i\n"
|
||||
"Num Tracked Vertex Arrays: %i\n"
|
||||
"Vertices Submitted: %i\n"
|
||||
"Cached Vertices Drawn: %i\n"
|
||||
"Uncached Vertices Drawn: %i\n"
|
||||
"FBOs active: %i\n"
|
||||
"Textures active: %i, decoded: %i\n"
|
||||
"Texture invalidations: %i\n"
|
||||
"Vertex shaders loaded: %i\n"
|
||||
"Fragment shaders loaded: %i\n"
|
||||
"Combined shaders loaded: %i\n",
|
||||
gpuStats.numFrames,
|
||||
gpuStats.msProcessingDisplayLists * 1000.0f,
|
||||
kernelStats.msInSyscalls * 1000.0f,
|
||||
kernelStats.slowestSyscallName ? kernelStats.slowestSyscallName : "(none)",
|
||||
kernelStats.slowestSyscallTime * 1000.0f,
|
||||
kernelStats.summedSlowestSyscallName ? kernelStats.summedSlowestSyscallName : "(none)",
|
||||
kernelStats.summedSlowestSyscallTime * 1000.0f,
|
||||
gpuStats.numDrawCalls,
|
||||
gpuStats.numFlushes,
|
||||
gpuStats.numCachedDrawCalls,
|
||||
gpuStats.numTrackedVertexArrays,
|
||||
gpuStats.numVertsSubmitted,
|
||||
gpuStats.numCachedVertsDrawn,
|
||||
gpuStats.numUncachedVertsDrawn,
|
||||
gpuStats.numFBOs,
|
||||
gpuStats.numTextures,
|
||||
gpuStats.numTexturesDecoded,
|
||||
gpuStats.numTextureInvalidations,
|
||||
gpuStats.numVertexShaders,
|
||||
gpuStats.numFragmentShaders,
|
||||
gpuStats.numShaders
|
||||
);
|
||||
|
||||
float zoom = 0.3f; /// g_Config.iWindowZoom;
|
||||
float soff = 0.3f;
|
||||
PPGeBegin();
|
||||
PPGeDrawText(stats, soff, soff, 0, zoom, 0xCC000000);
|
||||
PPGeDrawText(stats, -soff, -soff, 0, zoom, 0xCC000000);
|
||||
PPGeDrawText(stats, 0, 0, 0, zoom, 0xFFFFFFFF);
|
||||
PPGeEnd();
|
||||
|
||||
gpuStats.resetFrame();
|
||||
kernelStats.ResetFrame();
|
||||
DebugStats();
|
||||
}
|
||||
|
||||
if (g_Config.bShowFPSCounter) {
|
||||
@ -313,41 +349,32 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
|
||||
PPGeEnd();
|
||||
}
|
||||
|
||||
// Draw screen overlays before blitting. Saves and restores the Ge context.
|
||||
// Yeah, this has to be the right moment to end the frame. Give the graphics backend opportunity
|
||||
// to blit the framebuffer, in order to support half-framerate games that otherwise wouldn't have
|
||||
// anything to draw here.
|
||||
gpu->CopyDisplayToOutput();
|
||||
|
||||
host->EndFrame();
|
||||
bool throttle;
|
||||
|
||||
DoFrameTiming(throttle);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Best place to throttle the frame rate on non vsynced platforms is probably here. Let's try it.
|
||||
time_update();
|
||||
if (lastFrameTime == 0.0)
|
||||
lastFrameTime = time_now_d();
|
||||
if (!GetAsyncKeyState(VK_TAB) && !PSP_CoreParameter().headLess) {
|
||||
while (time_now_d() < lastFrameTime + 1.0 / 60.0) {
|
||||
Common::SleepCurrentThread(1);
|
||||
time_update();
|
||||
}
|
||||
// Advance lastFrameTime by a constant amount each frame,
|
||||
// but don't let it get too far behind.
|
||||
lastFrameTime = std::max(lastFrameTime + 1.0 / 60.0, time_now_d() - 1.5 / 60.0);
|
||||
}
|
||||
|
||||
// We are going to have to do something about audio timing for platforms that
|
||||
// are vsynced to something that's not exactly 60fps..
|
||||
|
||||
#endif
|
||||
|
||||
host->BeginFrame();
|
||||
gpu->BeginFrame();
|
||||
|
||||
// Tell the emu core that it's time to stop emulating
|
||||
// Win32 doesn't need this.
|
||||
#ifndef _WIN32
|
||||
// Setting CORE_NEXTFRAME causes a swap.
|
||||
coreState = CORE_NEXTFRAME;
|
||||
#endif
|
||||
|
||||
CoreTiming::ScheduleEvent(0 - cyclesLate, afterFlipEvent, 0);
|
||||
|
||||
// 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.
|
||||
}
|
||||
|
||||
void hleAfterFlip(u64 userdata, int cyclesLate)
|
||||
{
|
||||
// This checks input on PC. Fine to do even if not calling BeginFrame.
|
||||
host->BeginFrame();
|
||||
|
||||
gpu->BeginFrame(); // doesn't really matter if begin or end of frame.
|
||||
}
|
||||
|
||||
void hleLeaveVblank(u64 userdata, int cyclesLate) {
|
||||
|
@ -46,7 +46,6 @@ public:
|
||||
|
||||
virtual void InitGL() = 0;
|
||||
virtual void BeginFrame() {}
|
||||
virtual void EndFrame() {}
|
||||
virtual void ShutdownGL() = 0;
|
||||
|
||||
virtual void InitSound(PMixer *mixer) = 0;
|
||||
|
@ -49,14 +49,7 @@ void GL_Resized() // Resize And Initialize The GL Window
|
||||
glstate.viewport.restore();
|
||||
}
|
||||
|
||||
|
||||
void GL_BeginFrame()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GL_EndFrame()
|
||||
void GL_SwapBuffers()
|
||||
{
|
||||
SwapBuffers(hDC);
|
||||
}
|
||||
|
@ -2,9 +2,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
bool GL_Init(HWND window);
|
||||
void GL_Shutdown();
|
||||
void GL_Resized();
|
||||
void GL_BeginFrame();
|
||||
void GL_EndFrame();
|
||||
void GL_SwapBuffers();
|
||||
|
@ -117,11 +117,6 @@ void WindowsHost::BeginFrame()
|
||||
for (auto iter = this->input.begin(); iter != this->input.end(); iter++)
|
||||
if ((*iter)->UpdateState() == 0)
|
||||
break; // *iter is std::shared_ptr, **iter is InputDevice
|
||||
GL_BeginFrame();
|
||||
}
|
||||
void WindowsHost::EndFrame()
|
||||
{
|
||||
GL_EndFrame();
|
||||
}
|
||||
|
||||
void WindowsHost::BootDone()
|
||||
|
@ -21,7 +21,6 @@ public:
|
||||
|
||||
void InitGL();
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
void ShutdownGL();
|
||||
|
||||
void InitSound(PMixer *mixer);
|
||||
|
@ -101,7 +101,6 @@ public:
|
||||
|
||||
virtual void InitGL() {}
|
||||
virtual void BeginFrame() {}
|
||||
virtual void EndFrame() {}
|
||||
virtual void ShutdownGL() {}
|
||||
|
||||
virtual void InitSound(PMixer *mixer);
|
||||
|
@ -4,12 +4,13 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../Core/Config.h"
|
||||
#include "../Core/Core.h"
|
||||
#include "../Core/CoreTiming.h"
|
||||
#include "../Core/System.h"
|
||||
#include "../Core/MIPS/MIPS.h"
|
||||
#include "../Core/Host.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Windows/OpenGLBase.h"
|
||||
#include "Log.h"
|
||||
#include "LogManager.h"
|
||||
|
||||
@ -46,6 +47,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Temporary hack around annoying linking error.
|
||||
void GL_SwapBuffers() { }
|
||||
|
||||
void printUsage(const char *progname, const char *reason)
|
||||
{
|
||||
if (reason != NULL)
|
||||
@ -192,8 +196,10 @@ int main(int argc, const char* argv[])
|
||||
mipsr4k.RunLoopUntil(nowTicks + frameTicks);
|
||||
|
||||
// If we were rendering, this might be a nice time to do something about it.
|
||||
if (coreState == CORE_NEXTFRAME)
|
||||
if (coreState == CORE_NEXTFRAME) {
|
||||
headlessHost->SwapBuffers();
|
||||
coreState = CORE_RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
host->ShutdownGL();
|
||||
|
@ -35,7 +35,6 @@ public:
|
||||
|
||||
virtual void InitGL() {}
|
||||
virtual void BeginFrame() {}
|
||||
virtual void EndFrame() {}
|
||||
virtual void ShutdownGL() {}
|
||||
|
||||
virtual void InitSound(PMixer *mixer) {}
|
||||
@ -53,4 +52,9 @@ public:
|
||||
virtual void SetComparisonScreenshot(const std::string &filename) {}
|
||||
|
||||
virtual bool isGLWorking() { return false; }
|
||||
|
||||
|
||||
// Unique for HeadlessHost
|
||||
virtual void SwapBuffers() {}
|
||||
|
||||
};
|
@ -218,7 +218,7 @@ void WindowsHeadlessHost::BeginFrame()
|
||||
|
||||
}
|
||||
|
||||
void WindowsHeadlessHost::EndFrame()
|
||||
void WindowsHeadlessHost::SwapBuffers()
|
||||
{
|
||||
SwapBuffers(hDC);
|
||||
::SwapBuffers(hDC);
|
||||
}
|
||||
|
@ -30,10 +30,11 @@ class WindowsHeadlessHost : public HeadlessHost
|
||||
public:
|
||||
virtual void InitGL();
|
||||
virtual void BeginFrame();
|
||||
virtual void EndFrame();
|
||||
virtual void ShutdownGL();
|
||||
virtual bool isGLWorking() { return glOkay; }
|
||||
|
||||
virtual void SwapBuffers();
|
||||
|
||||
virtual void SendDebugOutput(const std::string &output);
|
||||
virtual void SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h);
|
||||
virtual void SetComparisonScreenshot(const std::string &filename);
|
||||
|
Loading…
Reference in New Issue
Block a user