Files
NX2navi/runtime/sysinfo.c
chrg6 c8738a948c Name the settings, files and tools NX2navi
The names are NX2NAVI, NX2navi or nx2navi: the settings prefix (NX2NAVI_*), the ini file
(nx2navi.ini), the shader translator (nx2navi_xlate), the Windows resources, the installer and the docs. The 8-byte
file magics keep their size (NX2NSANS, NX2NSPRG, NX2NSPRP, NX2NPKEY, NX2NRFS1), so caches and the RomFS index from
older builds are not read. cfg.c and the settings pages took the prefix length as 5; it now follows the prefix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 05:04:39 -05:00

94 lines
3.6 KiB
C

// What a bug report needs about the machine (sysinfo.h). The OS calls sit behind platform.h; the GPU and driver come
// from the Vulkan device the game renders on.
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#if defined(__x86_64__) || defined(__i386__)
#include <cpuid.h>
#endif
#include "cfg.h"
#include "host.h"
#include "platform/platform.h"
#include "sysinfo.h"
#include "vk.h"
void sysinfo_cpu_name(char *out, size_t n) {
out[0] = 0;
#if defined(__x86_64__) || defined(__i386__)
unsigned r[12];
if (__get_cpuid_max(0x80000000, NULL) < 0x80000004) return;
for (unsigned i = 0; i < 3; i++) __get_cpuid(0x80000002 + i, &r[i * 4], &r[i * 4 + 1], &r[i * 4 + 2], &r[i * 4 + 3]);
char b[49];
memcpy(b, r, 48);
b[48] = 0;
const char *p = b;
while (*p == ' ') p++;
snprintf(out, n, "%s", p);
for (char *e = out + strlen(out); e > out && e[-1] == ' '; e--) e[-1] = 0;
#endif
}
int sysinfo_log_folder(char *out, size_t n) {
const char *log = rt_log_path();
if (log) snprintf(out, n, "%s", log);
else if (!plat_stderr_path(out, n) && !plat_exe_path(out, n)) return 0;
char *s = strrchr(out, '\\'), *f = strrchr(out, '/');
if (f > s) s = f;
if (!s) return 0;
*s = 0;
return 1;
}
typedef struct { char *buf; size_t n, at; } Out;
static void put(Out *o, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
static void put(Out *o, const char *fmt, ...) {
if (o->at + 1 >= o->n) return;
va_list ap;
va_start(ap, fmt);
int k = vsnprintf(o->buf + o->at, o->n - o->at, fmt, ap);
va_end(ap);
if (k > 0) o->at = o->at + (size_t)k < o->n ? o->at + (size_t)k : o->n - 1;
}
static void put_setting(const char *key, const char *value, int from_env, void *ctx) {
put(ctx, from_env ? " NX2NAVI_%s=%s (environment)\n" : " %s = %s\n", key, value);
}
int sysinfo_text(char *buf, size_t n) {
if (!n) return 0;
Out o = {buf, n, 0};
buf[0] = 0;
char s[256];
put(&o, "NX2navi system info\n");
put(&o, "OS: %s\n", plat_os_version(s, sizeof s) ? s : "unknown");
sysinfo_cpu_name(s, sizeof s);
put(&o, "CPU: %s, %u logical processors\n", s[0] ? s : "unknown", plat_cpu_count());
float used, total, proc;
plat_mem_info(&used, &total, &proc);
if (total > 0) put(&o, "RAM: %.1f GB, %.1f GB in use, the game %.1f GB\n", total / 1024, used / 1024, proc / 1024);
VkCtx *c = vk_ctx();
if (c) {
VkPhysicalDeviceDriverProperties dp = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES};
VkPhysicalDeviceProperties2 p2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = &dp};
vkGetPhysicalDeviceProperties2(c->phys, &p2);
const VkPhysicalDeviceProperties *p = &p2.properties;
uint64_t vram = 0;
for (uint32_t h = 0; h < c->mem_props.memoryHeapCount; h++)
if (c->mem_props.memoryHeaps[h].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) vram += c->mem_props.memoryHeaps[h].size;
put(&o, "GPU: %s (vendor 0x%04x, device 0x%04x), %.1f GB device-local memory\n", p->deviceName, p->vendorID,
p->deviceID, vram / 1073741824.0);
put(&o, "Driver: %s %s, driver version 0x%08x, Vulkan %u.%u.%u\n", dp.driverName, dp.driverInfo,
p->driverVersion, VK_API_VERSION_MAJOR(p->apiVersion), VK_API_VERSION_MINOR(p->apiVersion),
VK_API_VERSION_PATCH(p->apiVersion));
} else {
put(&o, "GPU: no Vulkan device yet\n");
}
put(&o, "Settings with a value:\n");
size_t before = o.at;
cfg_each_active(put_setting, &o);
if (o.at == before) put(&o, " none\n");
return (int)o.at;
}