Files
totk-pc-recomp/installer/hostcheck.c
T

66 lines
2.8 KiB
C

// Host check of the installer's first step, compiled with the bundled clang at install time: does the CPU run
// -march=x86-64-v3 code, and does a Vulkan 1.3 device exist. Prints one JSON object on stdout.
// The Vulkan loader is opened at run time, so a machine without one gets "loader": false instead of a failed start.
#include <stdio.h>
#include <string.h>
#include <vulkan/vulkan.h>
#ifdef _WIN32
#include <windows.h>
#define open_lib() LoadLibraryA("vulkan-1.dll")
#define lib_sym(l, n) ((void *)GetProcAddress((l), (n)))
#else
#include <dlfcn.h>
#define open_lib() dlopen("libvulkan.so.1", RTLD_NOW)
#define lib_sym(l, n) dlsym((l), (n))
#endif
static void json_string(const char *s) {
putchar('"');
for (; *s; s++) {
if (*s == '"' || *s == '\\') printf("\\%c", *s);
else if ((unsigned char)*s < 0x20) printf("\\u%04x", *s);
else putchar(*s);
}
putchar('"');
}
int main(void) {
__builtin_cpu_init();
printf("{\"x86_64_v3\": %s, ", __builtin_cpu_supports("x86-64-v3") ? "true" : "false");
void *lib = open_lib();
PFN_vkGetInstanceProcAddr gipa = lib ? (PFN_vkGetInstanceProcAddr)lib_sym(lib, "vkGetInstanceProcAddr") : NULL;
if (!gipa) {
printf("\"loader\": false, \"devices\": []}\n");
return 0;
}
printf("\"loader\": true, ");
PFN_vkCreateInstance create = (PFN_vkCreateInstance)gipa(NULL, "vkCreateInstance");
VkApplicationInfo app = {.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pApplicationName = "totk-install",
.apiVersion = VK_API_VERSION_1_3};
VkInstanceCreateInfo ci = {.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &app};
VkInstance inst = VK_NULL_HANDLE;
VkResult r = create ? create(&ci, NULL, &inst) : VK_ERROR_INITIALIZATION_FAILED;
if (r != VK_SUCCESS) {
printf("\"instance\": %d, \"devices\": []}\n", (int)r);
return 0;
}
PFN_vkEnumeratePhysicalDevices enumerate = (PFN_vkEnumeratePhysicalDevices)gipa(inst, "vkEnumeratePhysicalDevices");
PFN_vkGetPhysicalDeviceProperties props = (PFN_vkGetPhysicalDeviceProperties)gipa(inst, "vkGetPhysicalDeviceProperties");
PFN_vkDestroyInstance destroy = (PFN_vkDestroyInstance)gipa(inst, "vkDestroyInstance");
VkPhysicalDevice devs[16];
uint32_t n = 16;
if (enumerate(inst, &n, devs) < 0) n = 0;
printf("\"instance\": 0, \"devices\": [");
for (uint32_t i = 0; i < n; i++) {
VkPhysicalDeviceProperties p;
props(devs[i], &p);
printf("%s{\"name\": ", i ? ", " : "");
json_string(p.deviceName);
printf(", \"api\": [%u, %u, %u], \"type\": %d}", VK_API_VERSION_MAJOR(p.apiVersion),
VK_API_VERSION_MINOR(p.apiVersion), VK_API_VERSION_PATCH(p.apiVersion), (int)p.deviceType);
}
printf("]}\n");
destroy(inst, NULL);
return 0;
}