Display: Move core counters/stats to HW file.

This separates things better, so not everything is pulling in HLE.
This commit is contained in:
Unknown W. Brackets 2022-01-30 10:37:50 -08:00
parent ad2e380987
commit 48b597a1b9
18 changed files with 313 additions and 236 deletions

View File

@ -17,6 +17,7 @@
#include <atomic>
#include <cstdio>
#include <cstring>
#include <mutex>
#include <set>
#include <vector>
@ -29,7 +30,6 @@
#include "Core/Core.h"
#include "Core/Config.h"
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/MIPS/MIPS.h"
#include "Core/Reporting.h"

View File

@ -18,7 +18,6 @@
#include <mutex>
#include <vector>
#include "Core/Debugger/WebSocket/GPUStatsSubscriber.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HW/Display.h"
#include "Core/System.h"

View File

@ -20,7 +20,7 @@
#include "Core/Debugger/WebSocket/InputSubscriber.h"
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
#include "Core/HLE/sceCtrl.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HW/Display.h"
// Button press state change (input.buttons)
//

View File

@ -21,7 +21,7 @@
#include "Core/Debugger/WebSocket/InputSubscriber.h"
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
#include "Core/HLE/sceCtrl.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HW/Display.h"
// This is also used in InputBroadcaster.
const std::unordered_map<std::string, uint32_t> buttonLookup = {

View File

@ -28,8 +28,8 @@
#include "Core/Dialog/PSPOskDialog.h"
#include "Core/Util/PPGeDraw.h"
#include "Core/HLE/sceCtrl.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HLE/sceUtility.h"
#include "Core/HW/Display.h"
#include "Core/Config.h"
#include "Core/Reporting.h"
#include "GPU/GPUState.h"

View File

@ -35,7 +35,6 @@
#include "Core/MIPS/MIPS.h"
#include "Core/MIPS/MIPSCodeUtils.h"
#include "Core/HLE/HLETables.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HLE/sceIo.h"
#include "Core/HLE/sceAudio.h"
#include "Core/HLE/sceKernelMemory.h"

View File

@ -93,11 +93,6 @@ static int lagSyncEvent = -1;
static double lastLagSync = 0.0;
static bool lagSyncScheduled = false;
// hCount is computed now.
static int vCount;
// The "AccumulatedHcount" can be adjusted, this is the base.
static u32 hCountBase;
static int isVblank;
static int numSkippedFrames;
static bool hasSetMode;
static int resumeMode;
@ -116,12 +111,8 @@ static const double timePerVblank = 1.001f / 60.0f;
static double curFrameTime;
static double lastFrameTime;
static double nextFrameTime;
static int numVBlanks;
static int numVBlanksSinceFlip;
static u64 frameStartTicks;
const int hCountPerVblank = 286;
const int PSP_DISPLAY_MODE_LCD = 0;
std::vector<WaitVBlankInfo> vblankWaitingThreads;
@ -143,24 +134,6 @@ enum {
PSP_DISPLAY_SETBUF_NEXTFRAME = 1
};
static int lastFpsFrame = 0;
static double lastFpsTime = 0.0;
static double fps = 0.0;
static double fpsHistory[120];
static int fpsHistorySize = (int)ARRAY_SIZE(fpsHistory);
static int fpsHistoryPos = 0;
static int fpsHistoryValid = 0;
static double frameTimeHistory[600];
static double frameSleepHistory[600];
static const int frameTimeHistorySize = (int)ARRAY_SIZE(frameTimeHistory);
static int frameTimeHistoryPos = 0;
static int frameTimeHistoryValid = 0;
static double lastFrameTimeHistory = 0.0;
static int lastNumFlips = 0;
static float flips = 0.0f;
static int actualFlips = 0; // taking frameskip into account
static int lastActualFlips = 0;
static float actualFps = 0;
// For the "max 60 fps" setting.
static int lastFlipsTooFrequent = 0;
static u64 lastFlipCycles = 0;
@ -173,9 +146,6 @@ void hleLagSync(u64 userdata, int cyclesLate);
void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId);
void __DisplayVblankEndCallback(SceUID threadID, SceUID prevCallbackId);
int __DisplayGetFlipCount() { return actualFlips; }
int __DisplayGetVCount() { return vCount; }
int __DisplayGetNumVblanks() { return numVBlanks; }
void __DisplayFlip(int cyclesLate);
@ -202,7 +172,6 @@ void __DisplayInit() {
width = 480;
height = 272;
numSkippedFrames = 0;
numVBlanks = 0;
numVBlanksSinceFlip = 0;
flippedThisFrame = false;
framebufIsLatched = false;
@ -223,25 +192,10 @@ void __DisplayInit() {
ScheduleLagSync();
CoreTiming::ScheduleEvent(msToCycles(frameMs - vblankMs), enterVblankEvent, 0);
isVblank = 0;
frameStartTicks = 0;
vCount = 0;
hCountBase = 0;
curFrameTime = 0.0;
nextFrameTime = 0.0;
lastFrameTime = 0.0;
flips = 0;
fps = 0.0;
actualFlips = 0;
lastActualFlips = 0;
lastNumFlips = 0;
fpsHistoryValid = 0;
fpsHistoryPos = 0;
frameTimeHistoryValid = 0;
frameTimeHistoryPos = 0;
lastFrameTimeHistory = 0.0;
__KernelRegisterWaitTypeFuncs(WAITTYPE_VBLANK, __DisplayVblankBeginCallback, __DisplayVblankEndCallback);
}
@ -259,16 +213,7 @@ void __DisplayDoState(PointerWrap &p) {
Do(p, framebuf);
Do(p, latchedFramebuf);
Do(p, framebufIsLatched);
Do(p, frameStartTicks);
Do(p, vCount);
if (s <= 2) {
double oldHCountBase;
Do(p, oldHCountBase);
hCountBase = (int) oldHCountBase;
} else {
Do(p, hCountBase);
}
Do(p, isVblank);
DisplayHWDoState(p, s <= 2);
Do(p, hasSetMode);
Do(p, mode);
Do(p, resumeMode);
@ -371,7 +316,7 @@ void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId) {
return;
}
vblankPausedWaits[pauseKey] = vCount + waitData.vcountUnblock;
vblankPausedWaits[pauseKey] = __DisplayGetVCount() + waitData.vcountUnblock;
DEBUG_LOG(SCEDISPLAY, "sceDisplayWaitVblankCB: Suspending vblank wait for callback");
}
@ -386,116 +331,16 @@ void __DisplayVblankEndCallback(SceUID threadID, SceUID prevCallbackId) {
int vcountUnblock = vblankPausedWaits[pauseKey];
vblankPausedWaits.erase(pauseKey);
if (vcountUnblock <= vCount) {
if (vcountUnblock <= __DisplayGetVCount()) {
__KernelResumeThreadFromWait(threadID, 0);
return;
}
// Still have to wait a bit longer.
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vcountUnblock - vCount));
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vcountUnblock - __DisplayGetVCount()));
DEBUG_LOG(SCEDISPLAY, "sceDisplayWaitVblankCB: Resuming vblank wait from callback");
}
// TODO: Also average actualFps
void __DisplayGetFPS(float *out_vps, float *out_fps, float *out_actual_fps) {
*out_vps = fps;
*out_fps = flips;
*out_actual_fps = actualFps;
}
void __DisplayGetVPS(float *out_vps) {
*out_vps = fps;
}
void __DisplayGetAveragedFPS(float *out_vps, float *out_fps) {
float avg = 0.0;
if (fpsHistoryValid > 0) {
for (int i = 0; i < fpsHistoryValid; ++i) {
avg += fpsHistory[i];
}
avg /= (double) fpsHistoryValid;
}
*out_vps = *out_fps = avg;
}
static bool IsRunningSlow() {
// Allow for some startup turbulence for 8 seconds before assuming things are bad.
if (fpsHistoryValid >= 8) {
// Look at only the last 15 samples (starting at the 14th sample behind current.)
int rangeStart = fpsHistoryPos - std::min(fpsHistoryValid, 14);
double best = 0.0;
for (int i = rangeStart; i <= fpsHistoryPos; ++i) {
// rangeStart may have been negative if near a wrap around.
int index = (fpsHistorySize + i) % fpsHistorySize;
best = std::max(fpsHistory[index], best);
}
return best < System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE) * 0.97;
}
return false;
}
static void CalculateFPS() {
double now = time_now_d();
if (now >= lastFpsTime + 1.0) {
double frames = (numVBlanks - lastFpsFrame);
actualFps = (actualFlips - lastActualFlips);
fps = frames / (now - lastFpsTime);
flips = 60.0 * (double) (gpuStats.numFlips - lastNumFlips) / frames;
lastFpsFrame = numVBlanks;
lastNumFlips = gpuStats.numFlips;
lastActualFlips = actualFlips;
lastFpsTime = now;
fpsHistory[fpsHistoryPos++] = fps;
fpsHistoryPos = fpsHistoryPos % fpsHistorySize;
if (fpsHistoryValid < fpsHistorySize) {
++fpsHistoryValid;
}
}
if (g_Config.bDrawFrameGraph || coreCollectDebugStats) {
frameTimeHistory[frameTimeHistoryPos++] = now - lastFrameTimeHistory;
lastFrameTimeHistory = now;
frameTimeHistoryPos = frameTimeHistoryPos % frameTimeHistorySize;
if (frameTimeHistoryValid < frameTimeHistorySize) {
++frameTimeHistoryValid;
}
frameSleepHistory[frameTimeHistoryPos] = 0.0;
}
}
double *__DisplayGetFrameTimes(int *out_valid, int *out_pos, double **out_sleep) {
*out_valid = frameTimeHistoryValid;
*out_pos = frameTimeHistoryPos;
*out_sleep = frameSleepHistory;
return frameTimeHistory;
}
void __DisplayGetDebugStats(char *stats, size_t bufsize) {
char statbuf[4096];
gpu->GetStats(statbuf, sizeof(statbuf));
snprintf(stats, bufsize,
"Kernel processing time: %0.2f ms\n"
"Slowest syscall: %s : %0.2f ms\n"
"Most active syscall: %s : %0.2f ms\n%s",
kernelStats.msInSyscalls * 1000.0f,
kernelStats.slowestSyscallName ? kernelStats.slowestSyscallName : "(none)",
kernelStats.slowestSyscallTime * 1000.0f,
kernelStats.summedSlowestSyscallName ? kernelStats.summedSlowestSyscallName : "(none)",
kernelStats.summedSlowestSyscallTime * 1000.0f,
statbuf);
}
void __DisplaySetWasPaused() {
wasPaused = true;
}
@ -524,18 +369,6 @@ static void DoFrameDropLogging(float scaledTimestep) {
}
}
static int CalculateFrameSkip() {
int frameSkipNum;
if (g_Config.iFrameSkipType == 1) {
// Calculate the frames to skip dynamically using the set percentage of the current fps
frameSkipNum = ceil( flips * (static_cast<double>(g_Config.iFrameSkip) / 100.00) );
} else {
// Use the set number of frames to skip
frameSkipNum = g_Config.iFrameSkip;
}
return frameSkipNum;
}
// Let's collect all the throttling and frameskipping logic here.
static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) {
PROFILE_THIS_SCOPE("timing");
@ -570,7 +403,7 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) {
}
// Auto-frameskip automatically if speed limit is set differently than the default.
int frameSkipNum = CalculateFrameSkip();
int frameSkipNum = DisplayCalculateFrameSkip();
if (g_Config.bAutoFrameSkip) {
// autoframeskip
// Argh, we are falling behind! Let's skip a frame and see if we catch up.
@ -646,7 +479,7 @@ static void DoFrameIdleTiming() {
}
if (g_Config.bDrawFrameGraph || coreCollectDebugStats) {
frameSleepHistory[frameTimeHistoryPos] += time_now_d() - before;
DisplayNotifySleep(time_now_d() - before);
}
}
}
@ -657,13 +490,7 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
VERBOSE_LOG(SCEDISPLAY, "Enter VBlank %i", vbCount);
isVblank = 1;
vCount++; // vCount increases at each VBLANK.
hCountBase += hCountPerVblank; // This is the "accumulated" hcount base.
if (hCountBase > 0x7FFFFFFF) {
hCountBase -= 0x80000000;
}
frameStartTicks = CoreTiming::GetTicks();
DisplayFireVblankStart();
CoreTiming::ScheduleEvent(msToCycles(vblankMs) - cyclesLate, leaveVblankEvent, vbCount + 1);
@ -688,7 +515,6 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
__KernelReSchedule("entered vblank");
}
numVBlanks++;
numVBlanksSinceFlip++;
// TODO: Should this be done here or in hleLeaveVblank?
@ -729,8 +555,8 @@ void __DisplayFlip(int cyclesLate) {
const bool fbDirty = gpu->FramebufferDirty();
if (fbDirty || noRecentFlip || postEffectRequiresFlip) {
int frameSleepPos = frameTimeHistoryPos;
CalculateFPS();
int frameSleepPos = DisplayGetSleepPos();
double frameSleepStart = time_now_d();
DisplayFireFlip();
// Let the user know if we're running slow, so they know to adjust settings.
@ -739,7 +565,7 @@ void __DisplayFlip(int cyclesLate) {
if (!g_Config.bHideSlowWarnings &&
!hasNotifiedSlow &&
PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL &&
IsRunningSlow()) {
DisplayIsRunningSlow()) {
#ifndef _DEBUG
auto err = GetI18NCategory("Error");
if (g_Config.bSoftwareRendering) {
@ -774,7 +600,7 @@ void __DisplayFlip(int cyclesLate) {
if (!forceNoFlip && Core_NextFrame()) {
gpu->CopyDisplayToOutput(fbReallyDirty);
if (fbReallyDirty) {
actualFlips++;
DisplayFireActualFlip();
}
}
}
@ -787,7 +613,7 @@ void __DisplayFlip(int cyclesLate) {
DoFrameTiming(throttle, skipFrame, (float)numVBlanksSinceFlip * timePerVblank);
int maxFrameskip = 8;
int frameSkipNum = CalculateFrameSkip();
int frameSkipNum = DisplayCalculateFrameSkip();
if (throttle) {
// 4 here means 1 drawn, 4 skipped - so 12 fps minimum.
maxFrameskip = frameSkipNum;
@ -813,7 +639,7 @@ void __DisplayFlip(int cyclesLate) {
if (g_Config.bDrawFrameGraph || coreCollectDebugStats) {
// Track how long we sleep (whether vsync or sleep_ms.)
frameSleepHistory[frameSleepPos] += time_now_d() - lastFrameTimeHistory;
DisplayNotifySleep(time_now_d() - frameSleepStart, frameSleepPos);
}
} else {
// Okay, there's no new frame to draw. But audio may be playing, so we need to time still.
@ -832,13 +658,12 @@ void hleAfterFlip(u64 userdata, int cyclesLate) {
}
void hleLeaveVblank(u64 userdata, int cyclesLate) {
isVblank = 0;
flippedThisFrame = false;
VERBOSE_LOG(SCEDISPLAY,"Leave VBlank %i", (int)userdata - 1);
CoreTiming::ScheduleEvent(msToCycles(frameMs - vblankMs) - cyclesLate, enterVblankEvent, userdata);
// Fire the vblank listeners after the vblank completes.
DisplayFireVblank();
DisplayFireVblankEnd();
}
void hleLagSync(u64 userdata, int cyclesLate) {
@ -877,16 +702,16 @@ void hleLagSync(u64 userdata, int cyclesLate) {
ScheduleLagSync(over - emuOver);
if (g_Config.bDrawFrameGraph || coreCollectDebugStats) {
frameSleepHistory[frameTimeHistoryPos] += now - before;
DisplayNotifySleep(now - before);
}
}
static u32 sceDisplayIsVblank() {
return hleLogSuccessI(SCEDISPLAY, isVblank);
return hleLogSuccessI(SCEDISPLAY, DisplayIsVblank());
}
static int DisplayWaitForVblanks(const char *reason, int vblanks, bool callbacks = false) {
const s64 ticksIntoFrame = CoreTiming::GetTicks() - frameStartTicks;
const s64 ticksIntoFrame = CoreTiming::GetTicks() - DisplayFrameStartTicks();
const s64 cyclesToNextVblank = msToCycles(frameMs) - ticksIntoFrame;
// These syscalls take about 115 us, so if the next vblank is before then, we're waiting extra.
@ -1066,7 +891,7 @@ static u32 sceDisplayWaitVblankStart() {
}
static u32 sceDisplayWaitVblank() {
if (!isVblank) {
if (!DisplayIsVblank()) {
return DisplayWaitForVblanks("vblank waited", 1);
} else {
hleEatCycles(1110);
@ -1088,7 +913,7 @@ static u32 sceDisplayWaitVblankStartMulti(int vblanks) {
}
static u32 sceDisplayWaitVblankCB() {
if (!isVblank) {
if (!DisplayIsVblank()) {
return DisplayWaitForVblanksCB("vblank waited", 1);
} else {
hleEatCycles(1110);
@ -1116,20 +941,7 @@ static u32 sceDisplayWaitVblankStartMultiCB(int vblanks) {
static u32 sceDisplayGetVcount() {
hleEatCycles(150);
hleReSchedule("get vcount");
return hleLogSuccessVerboseI(SCEDISPLAY, vCount);
}
static u32 __DisplayGetCurrentHcount() {
const int ticksIntoFrame = CoreTiming::GetTicks() - frameStartTicks;
const int ticksPerVblank = CoreTiming::GetClockFrequencyHz() / 60 / hCountPerVblank;
// Can't seem to produce a 0 on real hardware, offsetting by 1 makes things look right.
return 1 + (ticksIntoFrame / ticksPerVblank);
}
static u32 __DisplayGetAccumulatedHcount() {
// The hCount is always a positive int, and wraps from 0x7FFFFFFF -> 0.
int value = hCountBase + __DisplayGetCurrentHcount();
return value & 0x7FFFFFFF;
return hleLogSuccessVerboseI(SCEDISPLAY, __DisplayGetVCount());
}
static u32 sceDisplayGetCurrentHcount() {
@ -1145,7 +957,7 @@ static int sceDisplayAdjustAccumulatedHcount(int value) {
// Since it includes the current hCount, find the difference to apply to the base.
u32 accumHCount = __DisplayGetAccumulatedHcount();
int diff = value - accumHCount;
hCountBase += diff;
DisplayAdjustAccumulatedHcount(diff);
return hleLogSuccessI(SCEDISPLAY, 0);
}
@ -1179,8 +991,8 @@ static u32 sceDisplayGetMode(u32 modeAddr, u32 widthAddr, u32 heightAddr) {
static u32 sceDisplayIsVsync() {
u64 now = CoreTiming::GetTicks();
u64 start = frameStartTicks + msToCycles(vsyncStartMs);
u64 end = frameStartTicks + msToCycles(vsyncEndMs);
u64 start = DisplayFrameStartTicks() + msToCycles(vsyncStartMs);
u64 end = DisplayFrameStartTicks() + msToCycles(vsyncEndMs);
return hleLogSuccessI(SCEDISPLAY, now >= start && now <= end ? 1 : 0);
}

View File

@ -29,15 +29,6 @@ void Register_sceDisplay();
bool __DisplayGetFramebuf(PSPPointer<u8> *topaddr, u32 *linesize, u32 *pixelFormat, int mode);
void __DisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync);
void __DisplayGetDebugStats(char stats[], size_t bufsize);
void __DisplayGetFPS(float *out_vps, float *out_fps, float *out_actual_fps);
void __DisplayGetVPS(float *out_vps);
void __DisplayGetAveragedFPS(float *out_vps, float *out_fps);
double *__DisplayGetFrameTimes(int *out_valid, int *out_pos, double **out_sleep);
int __DisplayGetNumVblanks();
int __DisplayGetVCount();
int __DisplayGetFlipCount();
// Call this when resuming to avoid a small speedup burst
void __DisplaySetWasPaused();

View File

@ -16,9 +16,20 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include <cmath>
#include <mutex>
#include <vector>
#include "Common/Common.h"
#include "Common/Serialize/SerializeFuncs.h"
#include "Common/System/System.h"
#include "Common/TimeUtil.h"
#include "Core/Config.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/HLE/sceKernel.h"
#include "Core/HW/Display.h"
#include "GPU/GPU.h"
#include "GPU/GPUInterface.h"
// Called when vblank happens (like an internal interrupt.) Not part of state, should be static.
static std::mutex listenersLock;
@ -26,12 +37,204 @@ static std::vector<VblankCallback> vblankListeners;
typedef std::pair<FlipCallback, void *> FlipListener;
static std::vector<FlipListener> flipListeners;
void DisplayFireVblank() {
static uint64_t frameStartTicks;
static int numVBlanks;
// hCount is computed now.
static int vCount;
// The "AccumulatedHcount" can be adjusted, this is the base.
static uint32_t hCountBase;
static int isVblank;
static constexpr int hCountPerVblank = 286;
// FPS stats for frameskip, FPS display, etc.
static int lastFpsFrame = 0;
static double lastFpsTime = 0.0;
static double fps = 0.0;
static int lastNumFlips = 0;
static float flips = 0.0f;
static int actualFlips = 0; // taking frameskip into account
static int lastActualFlips = 0;
static float actualFps = 0;
// FPS stats for averaging.
static double fpsHistory[120];
static constexpr int fpsHistorySize = (int)ARRAY_SIZE(fpsHistory);
static int fpsHistoryPos = 0;
static int fpsHistoryValid = 0;
// Frame time stats.
static double frameTimeHistory[600];
static double frameSleepHistory[600];
static constexpr int frameTimeHistorySize = (int)ARRAY_SIZE(frameTimeHistory);
static int frameTimeHistoryPos = 0;
static int frameTimeHistoryValid = 0;
static double lastFrameTimeHistory = 0.0;
static void CalculateFPS() {
double now = time_now_d();
if (now >= lastFpsTime + 1.0) {
double frames = (numVBlanks - lastFpsFrame);
actualFps = (actualFlips - lastActualFlips);
fps = frames / (now - lastFpsTime);
flips = 60.0 * (double)(gpuStats.numFlips - lastNumFlips) / frames;
lastFpsFrame = numVBlanks;
lastNumFlips = gpuStats.numFlips;
lastActualFlips = actualFlips;
lastFpsTime = now;
fpsHistory[fpsHistoryPos++] = fps;
fpsHistoryPos = fpsHistoryPos % fpsHistorySize;
if (fpsHistoryValid < fpsHistorySize) {
++fpsHistoryValid;
}
}
if (g_Config.bDrawFrameGraph || coreCollectDebugStats) {
frameTimeHistory[frameTimeHistoryPos++] = now - lastFrameTimeHistory;
lastFrameTimeHistory = now;
frameTimeHistoryPos = frameTimeHistoryPos % frameTimeHistorySize;
if (frameTimeHistoryValid < frameTimeHistorySize) {
++frameTimeHistoryValid;
}
frameSleepHistory[frameTimeHistoryPos] = 0.0;
}
}
// TODO: Also average actualFps
void __DisplayGetFPS(float *out_vps, float *out_fps, float *out_actual_fps) {
*out_vps = fps;
*out_fps = flips;
*out_actual_fps = actualFps;
}
void __DisplayGetVPS(float *out_vps) {
*out_vps = fps;
}
void __DisplayGetAveragedFPS(float *out_vps, float *out_fps) {
float avg = 0.0;
if (fpsHistoryValid > 0) {
for (int i = 0; i < fpsHistoryValid; ++i) {
avg += fpsHistory[i];
}
avg /= (double)fpsHistoryValid;
}
*out_vps = *out_fps = avg;
}
int __DisplayGetFlipCount() {
return actualFlips;
}
int __DisplayGetNumVblanks() {
return numVBlanks;
}
int __DisplayGetVCount() {
return vCount;
}
bool DisplayIsVblank() {
return isVblank != 0;
}
uint64_t DisplayFrameStartTicks() {
return frameStartTicks;
}
uint32_t __DisplayGetCurrentHcount() {
const int ticksIntoFrame = CoreTiming::GetTicks() - frameStartTicks;
const int ticksPerVblank = CoreTiming::GetClockFrequencyHz() / 60 / hCountPerVblank;
// Can't seem to produce a 0 on real hardware, offsetting by 1 makes things look right.
return 1 + (ticksIntoFrame / ticksPerVblank);
}
uint32_t __DisplayGetAccumulatedHcount() {
// The hCount is always a positive int, and wraps from 0x7FFFFFFF -> 0.
int value = hCountBase + __DisplayGetCurrentHcount();
return value & 0x7FFFFFFF;
}
void DisplayAdjustAccumulatedHcount(uint32_t diff) {
hCountBase += diff;
}
double *__DisplayGetFrameTimes(int *out_valid, int *out_pos, double **out_sleep) {
*out_valid = frameTimeHistoryValid;
*out_pos = frameTimeHistoryPos;
*out_sleep = frameSleepHistory;
return frameTimeHistory;
}
int DisplayGetSleepPos() {
return frameTimeHistoryPos;
}
void DisplayNotifySleep(double t, int pos) {
if (pos < 0)
pos = frameTimeHistoryPos;
frameSleepHistory[pos] += t;
}
void __DisplayGetDebugStats(char *stats, size_t bufsize) {
char statbuf[4096];
gpu->GetStats(statbuf, sizeof(statbuf));
snprintf(stats, bufsize,
"Kernel processing time: %0.2f ms\n"
"Slowest syscall: %s : %0.2f ms\n"
"Most active syscall: %s : %0.2f ms\n%s",
kernelStats.msInSyscalls * 1000.0f,
kernelStats.slowestSyscallName ? kernelStats.slowestSyscallName : "(none)",
kernelStats.slowestSyscallTime * 1000.0f,
kernelStats.summedSlowestSyscallName ? kernelStats.summedSlowestSyscallName : "(none)",
kernelStats.summedSlowestSyscallTime * 1000.0f,
statbuf);
}
bool DisplayIsRunningSlow() {
// Allow for some startup turbulence for 8 seconds before assuming things are bad.
if (fpsHistoryValid >= 8) {
// Look at only the last 15 samples (starting at the 14th sample behind current.)
int rangeStart = fpsHistoryPos - std::min(fpsHistoryValid, 14);
double best = 0.0;
for (int i = rangeStart; i <= fpsHistoryPos; ++i) {
// rangeStart may have been negative if near a wrap around.
int index = (fpsHistorySize + i) % fpsHistorySize;
best = std::max(fpsHistory[index], best);
}
return best < System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE) * 0.97;
}
return false;
}
void DisplayFireVblankStart() {
frameStartTicks = CoreTiming::GetTicks();
numVBlanks++;
isVblank = 1;
vCount++; // vCount increases at each VBLANK.
hCountBase += hCountPerVblank; // This is the "accumulated" hcount base.
if (hCountBase > 0x7FFFFFFF) {
hCountBase -= 0x80000000;
}
}
void DisplayFireVblankEnd() {
std::vector<VblankCallback> toCall = [] {
std::lock_guard<std::mutex> guard(listenersLock);
return vblankListeners;
}();
isVblank = 0;
for (VblankCallback cb : toCall) {
cb();
}
@ -43,11 +246,18 @@ void DisplayFireFlip() {
return flipListeners;
}();
// This is also the right time to calculate FPS.
CalculateFPS();
for (FlipListener cb : toCall) {
cb.first(cb.second);
}
}
void DisplayFireActualFlip() {
actualFlips++;
}
void __DisplayListenVblank(VblankCallback callback) {
std::lock_guard<std::mutex> guard(listenersLock);
vblankListeners.push_back(callback);
@ -65,8 +275,37 @@ void __DisplayForgetFlip(FlipCallback callback, void *userdata) {
}), flipListeners.end());
}
void DisplayHWInit() {
int DisplayCalculateFrameSkip() {
int frameSkipNum;
if (g_Config.iFrameSkipType == 1) {
// Calculate the frames to skip dynamically using the set percentage of the current fps
frameSkipNum = ceil(flips * (static_cast<double>(g_Config.iFrameSkip) / 100.00));
} else {
// Use the set number of frames to skip
frameSkipNum = g_Config.iFrameSkip;
}
return frameSkipNum;
}
void DisplayHWInit() {
frameStartTicks = 0;
numVBlanks = 0;
isVblank = 0;
vCount = 0;
hCountBase = 0;
flips = 0;
fps = 0.0;
actualFlips = 0;
lastActualFlips = 0;
lastNumFlips = 0;
fpsHistoryValid = 0;
fpsHistoryPos = 0;
frameTimeHistoryValid = 0;
frameTimeHistoryPos = 0;
lastFrameTimeHistory = 0.0;
}
void DisplayHWShutdown() {
@ -74,3 +313,16 @@ void DisplayHWShutdown() {
vblankListeners.clear();
flipListeners.clear();
}
void DisplayHWDoState(PointerWrap &p, int hleCompatV2) {
Do(p, frameStartTicks);
Do(p, vCount);
if (hleCompatV2) {
double oldHCountBase;
Do(p, oldHCountBase);
hCountBase = (int)oldHCountBase;
} else {
Do(p, hCountBase);
}
Do(p, isVblank);
}

View File

@ -17,6 +17,10 @@
#pragma once
#include <cstdint>
class PointerWrap;
typedef void (*VblankCallback)();
// Listen for vblank events.
void __DisplayListenVblank(VblankCallback callback);
@ -24,8 +28,31 @@ typedef void (*FlipCallback)(void *userdata);
void __DisplayListenFlip(FlipCallback callback, void *userdata);
void __DisplayForgetFlip(FlipCallback callback, void *userdata);
void DisplayFireVblank();
int __DisplayGetFlipCount();
int __DisplayGetNumVblanks();
int __DisplayGetVCount();
bool DisplayIsVblank();
uint64_t DisplayFrameStartTicks();
uint32_t __DisplayGetCurrentHcount();
uint32_t __DisplayGetAccumulatedHcount();
void DisplayAdjustAccumulatedHcount(uint32_t diff);
void __DisplayGetDebugStats(char stats[], size_t bufsize);
void __DisplayGetAveragedFPS(float *out_vps, float *out_fps);
void __DisplayGetFPS(float *out_vps, float *out_fps, float *out_actual_fps);
void __DisplayGetVPS(float *out_vps);
double *__DisplayGetFrameTimes(int *out_valid, int *out_pos, double **out_sleep);
int DisplayGetSleepPos();
void DisplayNotifySleep(double t, int pos = -1);
bool DisplayIsRunningSlow();
void DisplayFireVblankStart();
void DisplayFireVblankEnd();
void DisplayFireFlip();
void DisplayFireActualFlip();
int DisplayCalculateFrameSkip();
void DisplayHWInit();
void DisplayHWShutdown();
void DisplayHWDoState(PointerWrap &p, int hleCompatV2);

View File

@ -33,7 +33,6 @@
#include "Core/MIPS/IR/IRJit.h"
#include "Core/Reporting.h"
#include "Core/System.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "Core/CoreTiming.h"

View File

@ -40,8 +40,8 @@
#include "Core/FileSystems/BlockDevices.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/HLE/Plugins.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HLE/sceKernelMemory.h"
#include "Core/HW/Display.h"
#include "Core/ELF/ParamSFO.h"
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"

View File

@ -40,8 +40,8 @@
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/ELF/ParamSFO.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HLE/ReplaceTables.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HLE/sceKernel.h"
#include "Core/HLE/sceUtility.h"
#include "Core/MemMap.h"

View File

@ -30,7 +30,7 @@
#include "Core/ConfigValues.h"
#include "Core/Host.h"
#include "Core/System.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HW/Display.h"
#include "GPU/Common/PostShader.h"
#include "GPU/Common/PresentationCommon.h"
#include "Common/GPU/ShaderTranslation.h"

View File

@ -17,6 +17,7 @@
#pragma once
#include "Common/Common.h"
#include "Common/GPU/Shader.h"
struct CardboardSettings {

View File

@ -34,7 +34,6 @@
#include "Core/ConfigValues.h"
#include "Core/System.h"
#include "Core/Reporting.h"
#include "Core/HLE/sceDisplay.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"

View File

@ -63,7 +63,6 @@ using namespace std::placeholders;
#include "GPU/Vulkan/DebugVisVulkan.h"
#endif
#include "Core/HLE/sceCtrl.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HLE/sceSas.h"
#include "Core/Debugger/SymbolMap.h"
#include "Core/SaveState.h"

View File

@ -62,7 +62,6 @@
#include "GPU/GPUInterface.h"
#include "Common/Data/Text/I18n.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HLE/sceUmd.h"
bool MainScreen::showHomebrewTab = false;