Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-debugger

This commit is contained in:
fgsfds committed 2023-11-15 22:36:28 +01:00
commit aa6ac4b5cc
16 files changed
+124 -39

No files matched your search

+61 -16
View File
@@ -1,19 +1,31 @@
#include <stdio.h>
#include <SDL.h>
#ifdef __MINGW32__
// mingw has its nanosleep implementation in pthread.h for some reson
#include <pthread.h>
#else
#include <unistd.h>
#include <time.h>
#endif
#include "platform.h"
#include "system.h"
#include "gfx_window_manager_api.h"
#include "gfx_screen_config.h"
#define GFX_BACKEND_NAME "SDL"
// define a way to yield the cpu when in a busy wait
#ifdef PLATFORM_WIN32
// winapi provides a yield macro
#include <windows.h>
#define DO_YIELD() YieldProcessor()
#elif defined(PLATFORM_X86) || defined(PLATFORM_X86_64)
// this should work even if the code is not built with SSE enabled, at least on gcc and clang,
// but if it doesn't we'll have to use __builtin_ia32_pause() or something
#include <immintrin.h>
#define DO_YIELD() _mm_pause()
#elif defined(PLATFORM_ARM)
// same as YieldProcessor() on ARM Windows
#define DO_YIELD() __asm__ volatile("dmb ishst\n\tyield":::"memory")
#else
// fuck it
#define DO_YIELD() do { } while (0)
#endif
static SDL_Window* wnd;
static SDL_GLContext ctx;
@@ -27,15 +39,32 @@ static bool fullscreen_state;
static bool is_running = true;
static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen);
static uint64_t previous_time;
static int target_fps = 120; // above 60 since vsync is enabled by default
static uint64_t previous_time;
static uint64_t qpc_freq;
#ifdef PLATFORM_WIN32
// on win32 we use waitable timers instead of nanosleep
typedef HANDLE WINAPI (*CREATEWAITABLETIMEREXAFN)(LPSECURITY_ATTRIBUTES, LPCSTR, DWORD, DWORD);
static HANDLE timer;
static CREATEWAITABLETIMEREXAFN pfnCreateWaitableTimerExA;
#endif
#define FRAME_INTERVAL_US_NUMERATOR 1000000
#define FRAME_INTERVAL_US_DENOMINATOR (target_fps)
static inline void do_sleep(const int64_t left) {
#ifdef PLATFORM_WIN32
static LARGE_INTEGER li;
li.QuadPart = -left;
SetWaitableTimer(timer, &li, 0, nullptr, nullptr, false);
WaitForSingleObject(timer, INFINITE);
#else
const timespec spec = { 0, left * 100 };
nanosleep(&spec, nullptr);
#endif
}
static void set_fullscreen(bool on, bool call_callback) {
if (fullscreen_state == on) {
return;
@@ -55,11 +84,6 @@ static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) {
*refresh_rate = mode.refresh_rate;
}
static inline void do_sleep(const uint64_t ns) {
const timespec spec = { 0, ns };
nanosleep(&spec, nullptr);
}
static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, uint32_t width,
uint32_t height, int32_t posX, int32_t posY) {
window_width = width;
@@ -143,6 +167,20 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s
qpc_freq = SDL_GetPerformanceFrequency();
#ifdef PLATFORM_WIN32
// this function is only present on Vista+, so try to import it from kernel32 by hand
pfnCreateWaitableTimerExA = (CREATEWAITABLETIMEREXAFN)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateWaitableTimerExA");
if (pfnCreateWaitableTimerExA) {
// function exists, try to create a hires timer
timer = pfnCreateWaitableTimerExA(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
}
if (!timer) {
// no function or hires timers not supported, fallback to lower resolution timer
sysLogPrintf(LOG_WARNING, "SDL: hires waitable timers not available");
timer = CreateWaitableTimerA(nullptr, false, nullptr);
}
#endif
set_fullscreen(start_in_fullscreen, false);
}
@@ -211,11 +249,18 @@ static inline void sync_framerate_with_timer(void) {
t = qpc_to_100ns(SDL_GetPerformanceCounter());
const int64_t next = previous_time + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR;
const int64_t left = next - t;
int64_t left = next - t;
// We want to exit a bit early, so we can busy-wait the rest to never miss the deadline
left -= 15000UL;
if (left > 0) {
do_sleep(left * 100);
do_sleep(left);
}
do {
DO_YIELD();
t = qpc_to_100ns(SDL_GetPerformanceCounter());
} while ((int64_t)t < next);
t = qpc_to_100ns(SDL_GetPerformanceCounter());
if (left > 0 && t - next < 10000) {
// In case it takes some time for the application to wake up after sleep,
+3
View File
@@ -35,6 +35,8 @@ u32 g_VmNumPageMisses = 0;
u32 g_VmNumPageReplaces = 0;
u8 g_VmShowStats = 0;
s32 g_TickRateDiv = 1;
extern s32 g_StageNum;
s32 bootGetMemSize(void)
@@ -136,6 +138,7 @@ PD_CONSTRUCTOR static void gameConfigInit(void)
configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048);
configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 1);
configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f);
configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10);
for (s32 j = 0; j < MAX_PLAYERS; ++j) {
const s32 i = j + 1;
configRegisterFloat(strFmt("Game.Player%d.FovY", i), &g_PlayerExtCfg[j].fovy, 5.f, 175.f);
+1 -1
View File
@@ -495,7 +495,7 @@ void mainLoop(void)
while (g_MainChangeToStageNum < 0) {
const s32 cycles = osGetCount() - g_Vars.thisframestartt;
if (cycles >= g_Vars.mininc60 * CYCLES_PER_FRAME - CYCLES_PER_FRAME / 2) {
if (!g_Vars.mininc60 || (cycles >= g_Vars.mininc60 * CYCLES_PER_FRAME - CYCLES_PER_FRAME / 2)) {
schedStartFrame(&g_Sched);
mainTick();
schedEndFrame(&g_Sched);
+2 -2
View File
@@ -411,7 +411,7 @@ void amTick(void)
// Update alpha of slots so they fade in
if (g_AmMenus[g_AmIndex].alphafrac < 1) {
g_AmMenus[g_AmIndex].alphafrac += LVUPDATE60FREAL() / 30.0f;
g_AmMenus[g_AmIndex].alphafrac += (f32)g_Vars.lvupdate240 / (4.f * 30.0f);
}
if (g_AmMenus[g_AmIndex].alphafrac > 1) {
@@ -419,7 +419,7 @@ void amTick(void)
}
// Make selection border pulsate
g_AmMenus[g_AmIndex].selpulse += LVUPDATE60FREAL() / 5.0f;
g_AmMenus[g_AmIndex].selpulse += (f32)g_Vars.lvupdate240 / (4.f * 5.0f);
if (g_AmMenus[g_AmIndex].selpulse > 18.849555969238f) {
g_AmMenus[g_AmIndex].selpulse -= 18.849555969238f;
-2
View File
@@ -922,8 +922,6 @@ void eyespyProcessInput(bool allowbuttons)
f32 mdx, mdy;
inputMouseGetScaledDelta(&mdx, &mdy);
if (mdx || mdy) {
mdx *= g_Vars.lvupdate60freal;
mdy *= g_Vars.lvupdate60freal;
if (g_Vars.currentplayerstats && !optionsGetForwardPitch(g_Vars.currentplayerstats->mpindex)) {
mdy = -mdy;
}
+12 -1
View File
@@ -10918,6 +10918,7 @@ void bgunRender(Gfx **gdlptr)
struct modelrenderdata renderdata = {NULL, true, 3}; // 10c
struct player *player;
s32 i;
const u32 wnorm = mtx00016dcc(0, 300);
static bool renderhand = true; // var800702dc
@@ -10983,7 +10984,7 @@ void bgunRender(Gfx **gdlptr)
gSPLookAt(gdl++, camGetLookAt());
}
gSPPerspNormalize(gdl++, mtx00016dcc(0, 300));
gSPPerspNormalize(gdl++, wnorm);
// There is support for guns having a TV screen on them
// but no guns have this model part so it's not used.
@@ -11158,7 +11159,17 @@ void bgunRender(Gfx **gdlptr)
}
}
#ifndef PLATFORM_N64
// put the casings into the same Z range as the gun
gSPPerspNormalize(gdl++, wnorm);
#endif
casingsRender(&gdl);
#ifndef PLATFORM_N64
gSPPerspNormalize(gdl++, viGetPerspScale());
#endif
zbufSwap();
gdl = zbufConfigureRdp(gdl);
+3 -2
View File
@@ -714,6 +714,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
#ifndef PLATFORM_N64
const bool allowmlook = (g_Vars.currentplayernum == 0) && (allowc1x || allowc1y);
bool allowmcross = false;
const f32 mlookscale = g_Vars.lvupdate240 ? (4.f / (f32)g_Vars.lvupdate240) : 4.f;
#endif
controlmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex);
@@ -2017,7 +2018,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
}
#ifndef PLATFORM_N64
fVar25 += movedata.freelookdy;
fVar25 += movedata.freelookdy * mlookscale;
#endif
g_Vars.currentplayer->speedverta = -fVar25 * tmp;
@@ -2058,7 +2059,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
}
#ifndef PLATFORM_N64
fVar25 += movedata.freelookdx;
fVar25 += movedata.freelookdx * mlookscale;
#endif
g_Vars.currentplayer->speedthetacontrol = fVar25 * tmp;
+4 -3
View File
@@ -177,9 +177,10 @@ void footstepCheckDefault(struct chrdata *chr)
chr->footstep = 2;
}
} else {
#ifndef PLATFORM_N64 // fix spamming footsteps for 60fps port
if (g_Vars.lvupdate240 == LV_SLOMO_TICK_CAP) {
s32 roundedframe = (s32)(frame*2);
#ifndef PLATFORM_N64
// fix spamming footsteps at >= 60fps
if (g_Vars.lvupdate240 < 4) {
const s32 roundedframe = (s32)(frame * (4.f / (f32)g_Vars.lvupdate240));
if (roundedframe == (g_FootstepAnims[i].frame1*2) && prevframe < g_FootstepAnims[i].frame1) {
chr->footstep = 1;
} else if (roundedframe == (g_FootstepAnims[i].frame2*2) && prevframe < g_FootstepAnims[i].frame2) {
+5 -5
View File
@@ -2057,7 +2057,7 @@ void lvTick(void)
g_Vars.lvupdate240 = 0;
for (j = 0; j < PLAYERCOUNT(); j++) {
g_Vars.players[j]->joybutinhibit = 0xefffffff;
g_Vars.players[j]->joybutinhibit = 0xffffefff;
}
} else {
s32 slowmo = lvGetSlowMotionType();
@@ -2066,7 +2066,7 @@ void lvTick(void)
if (slowmo == SLOWMOTION_ON) {
if (g_Vars.speedpillon == false || g_Vars.in_cutscene) {
if (g_Vars.lvupdate240 > LV_SLOMO_TICK_CAP) {
g_Vars.lvupdate240 = LV_SLOMO_TICK_CAP;
g_Vars.lvupdate240 = LV_SLOMO_TICK_RATE;
}
}
} else if (slowmo == SLOWMOTION_SMART) {
@@ -2097,7 +2097,7 @@ void lvTick(void)
if (foundnearbychr) {
if (g_Vars.lvupdate240 > LV_SLOMO_TICK_CAP) {
g_Vars.lvupdate240 = LV_SLOMO_TICK_CAP;
g_Vars.lvupdate240 = LV_SLOMO_TICK_RATE;
}
} else {
if (g_Vars.lvupdate240 > TICKS(8)) {
@@ -2106,7 +2106,7 @@ void lvTick(void)
}
} else {
if (g_Vars.lvupdate240 > LV_SLOMO_TICK_CAP) {
g_Vars.lvupdate240 = LV_SLOMO_TICK_CAP;
g_Vars.lvupdate240 = LV_SLOMO_TICK_RATE;
}
}
}
@@ -2114,7 +2114,7 @@ void lvTick(void)
// Slow motion settings are off
if (g_Vars.speedpillon && g_Vars.in_cutscene == false) {
if (g_Vars.lvupdate240 > LV_SLOMO_TICK_CAP) {
g_Vars.lvupdate240 = LV_SLOMO_TICK_CAP;
g_Vars.lvupdate240 = LV_SLOMO_TICK_RATE;
}
}
}
+2 -2
View File
@@ -3593,8 +3593,8 @@ void playerTick(bool arg0)
if (g_Vars.currentplayerstats && !optionsGetForwardPitch(g_Vars.currentplayerstats->mpindex)) {
mdy = -mdy;
}
sp178 += mdy * LVUPDATE60FREAL() * 0.00025f;
sp174 -= mdx * LVUPDATE60FREAL() * 0.00025f;
sp178 += mdy * 0.00025f;
sp174 -= mdx * 0.00025f;
}
}
#endif
+15
View File
@@ -7679,7 +7679,12 @@ void doorTick(struct prop *doorprop)
}
// Update frac
#ifdef PLATFORM_N64
if (door->lastcalc60 < g_Vars.lvframe60 || g_Vars.lvupdate240 == 0) {
#else
// lastcalc60 actually stores lvframe240
if (door->lastcalc60 < g_Vars.lvframe240 || g_Vars.lvupdate240 == 0) {
#endif
doorsCalcFrac(door);
}
@@ -9010,6 +9015,12 @@ void autogunInitMatrices(struct prop *prop, Mtxf *mtx)
void autogunTickShoot(struct prop *autogunprop)
{
#ifndef PLATFORM_N64
// HACK: fire every other tick at 60+ fps and every tick at <60 fps
if (g_Vars.lvupdate240 <= TICKS(4) && (g_Vars.lvframe60 & 1)) {
return;
}
#endif
if (!lvIsPaused()) {
struct autogunobj *autogun = (struct autogunobj *) autogunprop->obj;
struct defaultobj *obj = autogunprop->obj;
@@ -20345,7 +20356,11 @@ void doorsCalcFrac(struct doorobj *door)
func0f08d460(loopdoor);
}
#ifdef PLATFORM_N64
loopdoor->lastcalc60 = g_Vars.lvframe60;
#else
loopdoor->lastcalc60 = g_Vars.lvframe240; // actually use the 240hz counter for higher framerates
#endif
loopdoor = loopdoor->sibling;
if (loopdoor == door) {
+5 -1
View File
@@ -41,12 +41,16 @@ void frametimeCalculate(void)
diffframe60 = (g_Vars.lostframetime60t + diffframet + CYCLES_PER_FRAME / 2) / CYCLES_PER_FRAME;
diffframe240 = (g_Vars.lostframetime240t + diffframet + CYCLES_PER_FRAME / 2 / 4) / (CYCLES_PER_FRAME / 4);
} while (diffframe60 < g_Vars.mininc60);
} while (g_Vars.mininc60 && diffframe60 < g_Vars.mininc60);
g_Vars.lostframetime60t = g_Vars.lostframetime60t + diffframet - diffframe60 * CYCLES_PER_FRAME;
g_Vars.lostframetime240t = g_Vars.lostframetime240t + diffframet - diffframe240 * (CYCLES_PER_FRAME / 4);
#ifdef PLATFORM_N64
g_Vars.mininc60 = 1;
#else
g_Vars.mininc60 = g_TickRateDiv;
#endif
frametimeApply(diffframe60, diffframe240, count);
}
+1
View File
@@ -545,6 +545,7 @@ extern u32 g_HudAlignModeR;
extern s32 g_PrevFrameFb;
extern s32 g_BlurFb;
extern s32 g_BlurFbCapTimer;
extern s32 g_TickRateDiv;
#define PLAYER_EXTCFG() g_PlayerExtCfg[g_Vars.currentplayerstats->mpindex & 3]
#define PLAYER_DEFAULT_FOV (PLAYER_EXTCFG().fovy)
+5 -3
View File
@@ -6,10 +6,12 @@
#ifdef PLATFORM_N64
// game runs at ~30, so slomo = 1/2 of 30fps
#define LV_SLOMO_TICK_CAP TICKS(4)
#define LV_SLOMO_TICK_CAP 4
#define LV_SLOMO_TICK_RATE LV_SLOMO_TICK_CAP
#else
// game runs at 60+, so slomo = 1/2 of 60fps
#define LV_SLOMO_TICK_CAP TICKS(2)
// game runs at 60+, so slomo = 1/2 of whatever framerate we're running at
#define LV_SLOMO_TICK_CAP 1 // capping at >= 240fps would make it explode
#define LV_SLOMO_TICK_RATE (g_Vars.lvupdate240 / 2)
#endif
u32 getVar80084040(void);
+1 -1
View File
@@ -1523,7 +1523,7 @@ struct doorobj { // objtype 0x01
/*0xc4*/ s16 portalnum;
/*0xc6*/ s8 soundtype;
/*0xc7*/ s8 fadetime60; // counts down
/*0xc8*/ s32 lastcalc60;
/*0xc8*/ s32 lastcalc60; // port: actually stores 240hz frame number
/*0xcc*/ u8 laserfade;
/*0xcd*/ u8 unusedmaybe[3];
/*0xd0*/ u8 shadeinfo1[4]; // player 1
+4
View File
@@ -28,7 +28,11 @@ void varsInit(void)
g_Vars.lostframetime60t = 0;
g_Vars.lostframetime240t = 0;
g_Vars.lvupdate240rem = 2;
#ifdef PLATFORM_N64
g_Vars.mininc60 = 1;
#else
g_Vars.mininc60 = g_TickRateDiv;
#endif
g_Vars.roomportalrecursionlimit = 254;
g_Vars.diffframe240f = 4;
g_Vars.diffframe240freal = 4;