mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Display: Move core counters/stats to HW file.
This separates things better, so not everything is pulling in HLE.
This commit is contained in:
parent
ad2e380987
commit
48b597a1b9
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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)
|
||||
//
|
||||
|
@ -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 = {
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/GPU/Shader.h"
|
||||
|
||||
struct CardboardSettings {
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user