NVN: GPU timestamps in nanoseconds on the guest clock
- nvnDeviceGetTimestampInNanoseconds returned the counter's raw 19.2 MHz ticks; it now converts them to ns. GetCurrentTimestampInNanoseconds returned real ns, so a game subtracting one from the other (Engage calls both) got garbage. - Counter timestamps and GetCurrentTimestampInNanoseconds now come from the guest clock (guest_ns, the source of svc GetSystemTick / cntpct), as on hardware, where GPU timestamps and the CPU counter share one timebase. They came from CLOCK_MONOTONIC, which keeps running while the Mac sleeps while the guest clock does not. With ns units but the old clock, Mario dropped to 30 fps (it compares the GPU end time with a CPU frame-start tick at main+0x20a0394); on the guest clock it runs at 60 fps as before. - Mario regression t67 (60 fps, same scene; frame-time p95 matches a baseline run of the committed code, t70) and an Engage idle run (30 fps, same pacing as before) are clean; the iOS project compiles.
This commit is contained in:
1 parent
85bed8087b
commit
b1c814f676
2 files changed
+13
-6
No files matched your search
@@ -1451,12 +1451,14 @@ NVN(nvnTextureViewSetSwizzle, void, NVNtextureView *v, NVNtextureSwizzle r, NVNt
|
||||
NVN(nvnColorStateSetAlphaTest, void, NVNcolorState *s, NVNalphaFunc f) { ST(color_st, s)->alpha_func = (uint32_t)f; }
|
||||
NVN(nvnColorStateSetLogicOp, void, NVNcolorState *s, NVNlogicOp op) { ST(color_st, s)->logic_op = (uint32_t)op; }
|
||||
|
||||
// 设备:组合贴图句柄 = 贴图号 | 采样器号 << 20(与分离句柄同一编码);计时器数据里的时间戳宿主已是纳秒
|
||||
// Device: combined texture handle = texture id | sampler id << 20 (same encoding as the separate handles); the timestamp in counter data is already in nanoseconds on the host
|
||||
// 设备:组合贴图句柄 = 贴图号 | 采样器号 << 20(与分离句柄同一编码)
|
||||
// Device: combined texture handle = texture id | sampler id << 20 (same encoding as the separate handles)
|
||||
NVN(nvnDeviceGetTextureHandle, NVNtextureHandle, const NVNdevice *d, int tex, int samp) { (void)d; return (NVNtextureHandle)((uint64_t)(uint32_t)tex | (uint64_t)(uint32_t)samp << 20); }
|
||||
NVN(nvnDeviceGetTimestampInNanoseconds, uint64_t, const NVNdevice *d, const NVNcounterData *c) { (void)d; return c->timestamp; }
|
||||
// 当前 GPU 时刻(纳秒):宿主 GPU 计时与计数器时戳同一时钟源(CLOCK_MONOTONIC) | Current GPU time (ns): the host's GPU timing and counter timestamps share one clock source (CLOCK_MONOTONIC)
|
||||
NVN(nvnDeviceGetCurrentTimestampInNanoseconds, uint64_t, const NVNdevice *d) { (void)d; return clock_gettime_nsec_np(CLOCK_MONOTONIC); }
|
||||
// 计数器时戳是 19.2 MHz 的 GPU 计数(nvn_mtl.m gpu_ticks:纳秒 × 12 / 625),换回纳秒。原先原样返回,比 GetCurrentTimestampInNanoseconds 小约 52 倍,两者一减就是乱数
|
||||
// Counter timestamps are 19.2 MHz GPU ticks (nvn_mtl.m gpu_ticks: ns × 12 / 625); convert back to ns. They used to be returned as is, about 52 times smaller than GetCurrentTimestampInNanoseconds, so subtracting one from the other gave garbage
|
||||
NVN(nvnDeviceGetTimestampInNanoseconds, uint64_t, const NVNdevice *d, const NVNcounterData *c) { (void)d; return c->timestamp * 625 / 12; }
|
||||
// 当前 GPU 时刻(纳秒):与计数器时戳同一时钟——客体时钟(guest_ns,nvn_mtl.m gpu_ticks) | Current GPU time (ns): the same clock as the counter timestamps -- the guest clock (guest_ns, nvn_mtl.m gpu_ticks)
|
||||
NVN(nvnDeviceGetCurrentTimestampInNanoseconds, uint64_t, const NVNdevice *d) { (void)d; return guest_ns(); }
|
||||
NVN(nvnDeviceRegisterFastClearColor, NVNboolean, NVNdevice *d, const float *c, NVNformat f) { (void)d; (void)c; (void)f; return 1; }
|
||||
|
||||
// 窗口:活动交换链张数(宿主按创建时张数轮转,只记一次)
|
||||
|
||||
@@ -633,7 +633,12 @@ void mtl_sub_event(volatile uint32_t *val, uint32_t mode, uint32_t v) { post((po
|
||||
void mtl_sub_counter(uint64_t addr, uint32_t type) { post((post_op){2, NULL, 0, 0, addr, type, NULL}); }
|
||||
void mtl_counter_stats(uint64_t rep[32], uint64_t rst[32]) { memcpy(rep, g_cnt_report, sizeof g_cnt_report); memcpy(rst, g_cnt_reset, sizeof g_cnt_reset); }
|
||||
|
||||
static uint64_t gpu_ticks(void) { struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); return ((uint64_t)t.tv_sec * 1000000000ull + t.tv_nsec) * 12 / 625; }
|
||||
// 计数器时戳(19.2 MHz)取客体时钟(hle_os.c guest_ns,与 svc GetSystemTick / cntpct 同源):真机上 GPU 时戳与 CPU 计数同一时基,游戏会拿两者相比。
|
||||
// 原先取 CLOCK_MONOTONIC:它在 Mac 睡眠时照走,而客体时钟(mach_absolute_time)不走,两者差出睡眠时长;时戳换成纳秒后马力欧把帧率减半。图形单测里 guest_ns 是返回 0 的弱定义,退回单调时钟
|
||||
// Counter timestamps (19.2 MHz) are taken from the guest clock (hle_os.c guest_ns, the same source as svc GetSystemTick / cntpct): on hardware GPU timestamps and the CPU counter share one timebase, and games compare them.
|
||||
// They used to come from CLOCK_MONOTONIC, which keeps running while the Mac sleeps while the guest clock (mach_absolute_time) does not, so the two differed by the sleep time; once timestamps were converted to ns, Mario halved its frame rate. In graphics unit tests guest_ns is a weak definition returning 0; fall back to the monotonic clock
|
||||
uint64_t guest_ns(void);
|
||||
static uint64_t gpu_ticks(void) { uint64_t g = guest_ns(); if (!g) { struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); g = (uint64_t)t.tv_sec * 1000000000ull + t.tv_nsec; } return g * 12 / 625; }
|
||||
|
||||
// ---------- 启动埋点(DM_BOOTPROF=1):metallib 载入、管线创建(均在提交线程回放中同步发生)、贴图上传、首帧出图 ----------
|
||||
// ---------- Boot instrumentation (DM_BOOTPROF=1): metallib loading, pipeline creation (both happen synchronously during replay on the submit thread), texture upload, first-frame present ----------
|
||||
|
||||
Reference in new issue
Block a user