Skip to content

Commit

Permalink
Restructure Windows "gameloop" to be more similar to others.
Browse files Browse the repository at this point in the history
  • Loading branch information
hrydgard committed Feb 18, 2013
1 parent f8058e4 commit cbb786c
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 111 deletions.
14 changes: 13 additions & 1 deletion Core/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
#include "Core.h"
#include "MemMap.h"
#include "MIPS/MIPS.h"
#ifdef _WIN32
#include "Windows/OpenGLBase.h"
#endif

#include "Host.h"

Expand Down Expand Up @@ -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;

This comment has been minimized.

Copy link
@unknownbrackets

unknownbrackets Feb 19, 2013

Collaborator

I think this should be inside the ifdef, or it'll never exit. Made Qt not draw anything, at least.

-[Unknown]

This comment has been minimized.

Copy link
@hrydgard

hrydgard Feb 19, 2013

Author Owner

Hum yes, you're right. I can't fix it from where I am right now but feel free to send a pull or just fix it.

}
}
}

void Core_DoSingleStep()
Expand Down
189 changes: 108 additions & 81 deletions Core/HLE/sceDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand All @@ -118,6 +120,7 @@ void __DisplayInit() {

enterVblankEvent = CoreTiming::RegisterEvent("EnterVBlank", &hleEnterVblank);
leaveVblankEvent = CoreTiming::RegisterEvent("LeaveVBlank", &hleLeaveVblank);
afterFlipEvent = CoreTiming::RegisterEvent("AfterFlip", &hleAfterFlip);

This comment has been minimized.

Copy link
@unknownbrackets

unknownbrackets Feb 18, 2013

Collaborator

Needs to restore the event in __DisplayDoState() as well.

-[Unknown]

This comment has been minimized.

Copy link
@hrydgard

hrydgard Feb 19, 2013

Author Owner

Yes, of course, fixing.


CoreTiming::ScheduleEvent(msToCycles(frameMs - vblankMs), enterVblankEvent, 0);
isVblank = 0;
Expand Down Expand Up @@ -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;

Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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();

#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);
}
bool throttle;

DoFrameTiming(throttle);

// We are going to have to do something about audio timing for platforms that
// are vsynced to something that's not exactly 60fps..
// Setting CORE_NEXTFRAME causes a swap.
coreState = CORE_NEXTFRAME;

CoreTiming::ScheduleEvent(0 - cyclesLate, afterFlipEvent, 0);

#endif
// 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();

// Tell the emu core that it's time to stop emulating
// Win32 doesn't need this.
#ifndef _WIN32
coreState = CORE_NEXTFRAME;
#endif
gpu->BeginFrame(); // doesn't really matter if begin or end of frame.
}

void hleLeaveVblank(u64 userdata, int cyclesLate) {
Expand Down
1 change: 0 additions & 1 deletion Core/Host.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class Host

virtual void InitGL() = 0;
virtual void BeginFrame() {}
virtual void EndFrame() {}
virtual void ShutdownGL() = 0;

virtual void InitSound(PMixer *mixer) = 0;
Expand Down
9 changes: 1 addition & 8 deletions Windows/OpenGLBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
5 changes: 3 additions & 2 deletions Windows/OpenGLBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
5 changes: 0 additions & 5 deletions Windows/WindowsHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
1 change: 0 additions & 1 deletion Windows/WindowsHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ class WindowsHost : public Host

void InitGL();
void BeginFrame();
void EndFrame();
void ShutdownGL();

void InitSound(PMixer *mixer);
Expand Down
1 change: 0 additions & 1 deletion android/jni/NativeApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ class NativeHost : public Host

virtual void InitGL() {}
virtual void BeginFrame() {}
virtual void EndFrame() {}
virtual void ShutdownGL() {}

virtual void InitSound(PMixer *mixer);
Expand Down
20 changes: 13 additions & 7 deletions headless/Headless.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -46,6 +47,9 @@ class PrintfLogger : public LogListener
}
};

// Temporary hack around annoying linking error.
void GL_SwapBuffers() { }

This comment has been minimized.

Copy link
@unknownbrackets

unknownbrackets Feb 19, 2013

Collaborator

Hmm, I think this will break the graphics tests... of which there are currently only one...

Or maybe not? Should this just call host->SwapBuffers() basically?

-[Unknown]

This comment has been minimized.

Copy link
@hrydgard

hrydgard Feb 19, 2013

Author Owner

No, this won't even get called.

I still call swapbuffers below:
headlessHost->SwapBuffers();

That said, I have to admit I didn't check whether the test broke :/

This comment has been minimized.

Copy link
@unknownbrackets

unknownbrackets Feb 19, 2013

Collaborator

Ah, okay, so just a linking annoyance.

-[Unknown]


void printUsage(const char *progname, const char *reason)
{
if (reason != NULL)
Expand Down Expand Up @@ -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();
Expand Down
Loading

0 comments on commit cbb786c

Please sign in to comment.