Vulkan module

This commit is contained in:
Linus Dierheimer
2022-06-01 00:04:58 +02:00
parent 032ba375b6
commit 0dffd8debf
15 changed files with 469 additions and 196 deletions
+2
View File
@@ -187,6 +187,8 @@ static void defaultConfig(FFinstance* instance)
ffStrbufInitA(&instance->config.dateFormat, 0);
ffStrbufInitA(&instance->config.timeKey, 0);
ffStrbufInitA(&instance->config.timeFormat, 0);
ffStrbufInitA(&instance->config.vulkanKey, 0);
ffStrbufInitA(&instance->config.vulkanFormat, 0);
ffStrbufInitA(&instance->config.libPCI, 0);
ffStrbufInitA(&instance->config.libVulkan, 0);
+26
View File
@@ -39,6 +39,32 @@ void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* mino
ffStrbufAppend(buffer, patch);
}
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2)
{
if(version1->major != version2->major)
return version1->major > version2->major ? 1 : -1;
if(version1->minor != version2->minor)
return version1->minor > version2->minor ? 1 : -1;
if(version1->patch != version2->patch)
return version1->patch > version2->patch ? 1 : -1;
return 0;
}
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty)
{
if(version->major > 0 || version->minor > 0 || version->patch > 0)
ffStrbufAppendF(pretty, "%u", version->major);
if(version->minor > 0 || version->patch > 0)
ffStrbufAppendF(pretty, ".%u", version->minor);
if(version->patch > 0)
ffStrbufAppendF(pretty, ".%u", version->patch);
}
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
{
if(gtk2->length > 0 && gtk3->length > 0 && gtk4->length > 0)
+2
View File
@@ -183,6 +183,7 @@
#--player-key Media Player
#--song-key Song
#--datetime-key Date Time
#--vulkan-key Vulkan
# Format options:
# Sets the format string for module values.
@@ -218,6 +219,7 @@
#--player-format
#--song-format
#--datetime-format
#--vulkan-format
# Library options:
# Sets an user specific path to a library to load.
+2
View File
@@ -76,6 +76,7 @@ Format options: Provide the format string for custom output. Use fastfetch --hel
--datetime-format <format>
--time-format <format>
--date-format <format>
--vulkan-format <format>
Key options: Provide a custom key for an output
--os-key <key>
@@ -109,6 +110,7 @@ Key options: Provide a custom key for an output
--datetime-key <key>
--time-key <key>
--date-key <key>
--vulkan-key <key>
Library options: Set the path of a library to load
--lib-PCI <path>
+1
View File
@@ -31,5 +31,6 @@ Theme
Time
Title
Uptime
Vulkan
WM
WMTheme
+223
View File
@@ -0,0 +1,223 @@
#include "fastfetch.h"
#include <pthread.h>
#ifdef FF_HAVE_VULKAN
#include <vulkan/vulkan.h>
static inline void applyVulkanVersion(uint32_t vulkanVersion, FFVersion* ffVersion)
{
ffVersion->major = VK_VERSION_MAJOR(vulkanVersion);
ffVersion->minor = VK_VERSION_MINOR(vulkanVersion);
ffVersion->patch = VK_VERSION_PATCH(vulkanVersion);
}
static void applyDriverName(VkPhysicalDeviceDriverProperties* properties, FFstrbuf* result)
{
if(!ffStrSet(properties->driverName))
return;
ffStrbufAppendS(result, properties->driverName);
if(!ffStrSet(properties->driverInfo))
return;
ffStrbufAppendS(result, " [");
ffStrbufAppendS(result, properties->driverInfo);
ffStrbufAppendC(result, ']');
}
static void detectVulkan(const FFinstance* instance, FFVulkanResult* result)
{
FF_LIBRARY_LOAD(vulkan, instance->config.libVulkan, , "libvulkan.so", 2)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkGetInstanceProcAddr,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkCreateInstance,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkDestroyInstance,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkEnumeratePhysicalDevices,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkGetPhysicalDeviceProperties,)
//Some drivers (nvdc) print messages to stdout
//and thats the best way i found to disable that
ffSuppressIO(true);
FFVersion instanceVersion = FF_VERSION_INIT;
//We need to get the function pointer this way, because it is only provided by vulkan 1.1 and higher.
//a dlsym would fail on 1.0 implementations
PFN_vkEnumerateInstanceVersion ffvkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion) ffvkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
if(ffvkEnumerateInstanceVersion != NULL)
{
uint32_t version;
if(ffvkEnumerateInstanceVersion(&version) == VK_SUCCESS)
applyVulkanVersion(version, &instanceVersion);
}
const uint32_t projectVersion = VK_MAKE_VERSION(
FASTFETCH_PROJECT_VERSION_MAJOR,
FASTFETCH_PROJECT_VERSION_MINOR,
FASTFETCH_PROJECT_VERSION_PATCH
);
//We need to request 1.2 to get physicalDeviceDriverProperties
uint32_t requestedVkVersion = VK_API_VERSION_1_0;
if(instanceVersion.minor >= 2)
requestedVkVersion = VK_API_VERSION_1_2;
const VkApplicationInfo applicationInfo = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = NULL,
.pApplicationName = FASTFETCH_PROJECT_NAME,
.applicationVersion = projectVersion,
.pEngineName = "vulkanPrintGPUs",
.engineVersion = projectVersion,
.apiVersion = requestedVkVersion
};
const VkInstanceCreateInfo instanceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = NULL,
.pApplicationInfo = &applicationInfo,
.enabledLayerCount = 0,
.ppEnabledLayerNames = NULL,
.enabledExtensionCount = 0,
.ppEnabledExtensionNames = NULL,
.flags = 0
};
VkInstance vkInstance;
if(ffvkCreateInstance(&instanceCreateInfo, NULL, &vkInstance) != VK_SUCCESS)
{
dlclose(vulkan);
ffSuppressIO(false);
return;
}
//if instance creation succeeded, but vkEnumerateInstanceVersion didn't, this means we are running against a vulkan 1.0 implementation
//explicitly set this version, if no device is found, so we still have at least this info
if(instanceVersion.major == 0 && instanceVersion.minor == 0 && instanceVersion.patch == 0)
instanceVersion.major = 1;
uint32_t physicalDeviceCount;
if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, NULL) != VK_SUCCESS)
{
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
VkPhysicalDevice* physicalDevices = malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, physicalDevices) != VK_SUCCESS)
{
free(physicalDevices);
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
PFN_vkGetPhysicalDeviceProperties2 ffvkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties2");
FFVersion maxDeviceApiVersion = FF_VERSION_INIT;
FFVersion maxDeviceConformanceVersion = FF_VERSION_INIT;
for(uint32_t i = 0; i < physicalDeviceCount; i++)
{
//Get device properties.
//On VK 1.2 and up, we use vkGetPhysicalDeviceProperties2, so we can put VkPhysicalDeviceDriverProperties in the pNext chain.
//This is required to get the driver name and conformance version.
VkPhysicalDeviceDriverProperties driverProperties;
driverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
driverProperties.pNext = NULL;
driverProperties.driverName[0] = '\0';
driverProperties.conformanceVersion = (VkConformanceVersion) {0, 0, 0, 0};
VkPhysicalDeviceProperties2 physicalDeviceProperties;
physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
physicalDeviceProperties.pNext = &driverProperties;
if(ffvkGetPhysicalDeviceProperties2 != NULL)
ffvkGetPhysicalDeviceProperties2(physicalDevices[i], &physicalDeviceProperties);
else
ffvkGetPhysicalDeviceProperties(physicalDevices[i], &physicalDeviceProperties.properties);
//If the device api version is higher than the current highest device api version, overwrite it
//In this case, also use the current device driver name as the shown driver name
FFVersion deviceAPIVersion = FF_VERSION_INIT;
applyVulkanVersion(physicalDeviceProperties.properties.apiVersion, &deviceAPIVersion);
if(ffVersionCompare(&deviceAPIVersion, &maxDeviceApiVersion) > 0)
{
maxDeviceApiVersion = deviceAPIVersion;
applyDriverName(&driverProperties, &result->driver);
}
//If the device conformance version is higher than the current highest device conformance version, overwrite it
FFVersion deviceConformanceVersion = FF_VERSION_INIT;
deviceConformanceVersion.major = driverProperties.conformanceVersion.major;
deviceConformanceVersion.minor = driverProperties.conformanceVersion.minor;
deviceConformanceVersion.patch = driverProperties.conformanceVersion.patch;
if(ffVersionCompare(&deviceConformanceVersion, &maxDeviceConformanceVersion) > 0)
maxDeviceConformanceVersion = deviceConformanceVersion;
//Add the device to the list of devices shown by the GPU module
//We don't want softare rasterizers to show up as physical gpu
if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
continue;
FFGPUResult* gpu = ffListAdd(&result->devices);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufAppendS(&gpu->name, physicalDeviceProperties.properties.deviceName);
}
//If the highest device version is lower than the instance version, use it as our vulkan version
//otherwise the instance version is the vulkan version
if(ffVersionCompare(&instanceVersion, &maxDeviceApiVersion) > 0)
ffVersionToPretty(&maxDeviceApiVersion, &result->apiVersion);
else
ffVersionToPretty(&instanceVersion, &result->apiVersion);
//Use the highest device conformace version as our conformance version
ffVersionToPretty(&maxDeviceConformanceVersion, &result->conformanceVersion);
free(physicalDevices);
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
}
#endif
const FFVulkanResult* ffDetectVulkan(const FFinstance* instance)
{
static FFVulkanResult result;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
ffStrbufInit(&result.driver);
ffStrbufInit(&result.apiVersion);
ffStrbufInit(&result.conformanceVersion);
ffListInit(&result.devices, sizeof(FFGPUResult));
#ifdef FF_HAVE_VULKAN
detectVulkan(instance, &result);
#endif
pthread_mutex_unlock(&mutex);
return &result;
}
+14
View File
@@ -343,6 +343,14 @@ static inline void printCommandHelp(const char* command)
"second with leading zero"
);
}
else if(strcasecmp(command, "vulkan-format") == 0)
{
constructAndPrintCommandHelpFormat("vulkan", "{} (driver), {} (api version)", 3,
"Driver name",
"API version",
"Conformance version"
);
}
else
fprintf(stderr, "No specific help for command %s provided\n", command);
}
@@ -964,6 +972,10 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
optionParseString(key, value, &instance->config.timeKey);
else if(strcasecmp(key, "--time-format") == 0)
optionParseString(key, value, &instance->config.timeFormat);
else if(strcasecmp(key, "--vulkan-key") == 0)
optionParseString(key, value, &instance->config.vulkanKey);
else if(strcasecmp(key, "--vulkan-format") == 0)
optionParseString(key, value, &instance->config.vulkanFormat);
///////////////////
//Library options//
@@ -1165,6 +1177,8 @@ static void parseStructureCommand(FFinstance* instance, FFdata* data, const char
ffPrintTime(instance);
else if(strcasecmp(line, "colors") == 0)
ffPrintColors(instance);
else if(strcasecmp(line, "vulkan") == 0)
ffPrintVulkan(instance);
else
ffPrintError(instance, line, 0, NULL, NULL, 0, "<no implementation provided>");
}
+32
View File
@@ -125,6 +125,8 @@ typedef struct FFconfig
FFstrbuf dateFormat;
FFstrbuf timeKey;
FFstrbuf timeFormat;
FFstrbuf vulkanKey;
FFstrbuf vulkanFormat;
FFstrbuf libPCI;
FFstrbuf libVulkan;
@@ -180,6 +182,14 @@ typedef struct FFinstance
FFstate state;
} FFinstance;
typedef struct FFVersion
{
uint32_t major;
uint32_t minor;
uint32_t patch;
} FFVersion;
#define FF_VERSION_INIT ((FFVersion) {0})
typedef struct FFTitleResult
{
FFstrbuf userName;
@@ -235,6 +245,21 @@ typedef struct FFTerminalShellResult
FFstrbuf userShellVersion;
} FFTerminalShellResult;
typedef struct FFGPUResult
{
FFstrbuf vendor;
FFstrbuf name;
FFstrbuf driver;
} FFGPUResult;
typedef struct FFVulkanResult
{
FFstrbuf driver;
FFstrbuf apiVersion;
FFstrbuf conformanceVersion;
FFlist devices; //List of FFGPUResult
} FFVulkanResult;
typedef struct FFResolutionResult
{
uint32_t width;
@@ -452,6 +477,9 @@ bool ffStrSet(const char* str);
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch);
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4);
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty);
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
//common/processing.c
void ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[]);
@@ -517,6 +545,9 @@ const FFMediaResult* ffDetectMedia(FFinstance* instance);
//detection/dateTime.c
const FFDateTimeResult* ffDetectDateTime(const FFinstance* instance);
//detection/vulkan.c
const FFVulkanResult* ffDetectVulkan(const FFinstance* instance);
//////////////////////
// Module functions //
//////////////////////
@@ -564,5 +595,6 @@ void ffPrintTime(FFinstance* instance);
void ffPrintLocalIp(FFinstance* instance);
void ffPrintPublicIp(FFinstance* instance);
void ffPrintColors(FFinstance* instance);
void ffPrintVulkan(FFinstance* instance);
#endif
+2
View File
@@ -4,6 +4,8 @@
#define FASTFETCH_PROJECT_NAME "@PROJECT_NAME@"
#define FASTFETCH_PROJECT_VERSION "@PROJECT_VERSION@"
#define FASTFETCH_PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define FASTFETCH_PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define FASTFETCH_PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define FASTFETCH_PROJECT_VERSION_TWEAK "@PROJECT_VERSION_TWEAK@"
#define FASTFETCH_TARGET_DIR_ROOT "@TARGET_DIR_ROOT@"
+119 -194
View File
@@ -5,181 +5,7 @@
#define FF_GPU_MODULE_NAME "GPU"
#define FF_GPU_NUM_FORMAT_ARGS 5
typedef struct GPUResult
{
FFstrbuf vendor;
FFstrbuf name;
FFstrbuf driver;
} GPUResult;
#ifdef FF_HAVE_VULKAN
#include <vulkan/vulkan.h>
static void vulkanFillGPUs(FFinstance* instance, FFlist* results)
{
FF_LIBRARY_LOAD(vulkan, instance->config.libVulkan, , "libvulkan.so", 2)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkCreateInstance,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkDestroyInstance,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkEnumeratePhysicalDevices,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkGetPhysicalDeviceProperties,)
//Some drivers (nvdc) print messages to stdout
//and thats the best way i found to disable that
ffSuppressIO(true);
const VkApplicationInfo applicationInfo = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = NULL,
.pApplicationName = FASTFETCH_PROJECT_NAME,
.applicationVersion = VK_MAKE_VERSION(FASTFETCH_PROJECT_VERSION_MAJOR, 0, 0),
.pEngineName = "vulkanPrintGPUs",
.engineVersion = VK_MAKE_VERSION(FASTFETCH_PROJECT_VERSION_MAJOR, 0, 0),
.apiVersion = VK_API_VERSION_1_0,
};
const VkInstanceCreateInfo instanceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = NULL,
.pApplicationInfo = &applicationInfo,
.enabledLayerCount = 0,
.ppEnabledLayerNames = NULL,
.enabledExtensionCount = 0,
.ppEnabledExtensionNames = NULL,
.flags = 0
};
VkInstance vkInstance;
if(ffvkCreateInstance(&instanceCreateInfo, NULL, &vkInstance) != VK_SUCCESS)
{
dlclose(vulkan);
ffSuppressIO(false);
return;
}
uint32_t physicalDeviceCount;
if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, NULL) != VK_SUCCESS)
{
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
VkPhysicalDevice* physicalDevices = malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, physicalDevices) != VK_SUCCESS)
{
free(physicalDevices);
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
for(uint32_t i = 0; i < physicalDeviceCount; i++)
{
VkPhysicalDeviceProperties physicalDeviceProperties;
ffvkGetPhysicalDeviceProperties(physicalDevices[i], &physicalDeviceProperties);
//We don't want softare rasterizers
if(physicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
continue;
GPUResult* result = ffListAdd(results);
ffStrbufInit(&result->vendor);
ffStrbufInit(&result->name);
ffStrbufInit(&result->driver);
ffStrbufAppendS(&result->name, physicalDeviceProperties.deviceName);
}
free(physicalDevices);
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
#endif
#ifdef FF_HAVE_LIBPCI
#include <pci/pci.h>
#include <unistd.h>
//see https://github.com/pciutils/pciutils/blob/5bdf63b6b1bc35b59c4b3f47f7ca83ca1868155b/ls-kernel.c#L220
static void pciGetDriver(struct pci_dev* dev, FFstrbuf* driver, char*(*ffpci_get_param)(struct pci_access*, char*))
{
if(dev->access->method != PCI_ACCESS_SYS_BUS_PCI)
return;
const char* base = ffpci_get_param(dev->access, "sysfs.path");
if(!ffStrSet(base))
return;
FFstrbuf path;
ffStrbufInitA(&path, 64);
ffStrbufAppendF(&path, "%s/devices/%04x:%02x:%02x.%d/driver", base, dev->domain, dev->bus, dev->dev, dev->func);
ffStrbufEnsureFree(driver, 1023);
ssize_t resultLength = readlink(path.chars, driver->chars, driver->allocated - 1); //-1 for null terminator
if(resultLength > 0)
{
driver->length = (uint32_t) resultLength;
driver->chars[resultLength] = '\0';
ffStrbufSubstrAfterLastC(driver, '/');
}
ffStrbufDestroy(&path);
}
static void pciFillGPUs(FFinstance* instance, FFlist* results)
{
FF_LIBRARY_LOAD(pci, instance->config.libPCI, , "libpci.so", 4)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_alloc,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_init,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_scan_bus,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_fill_info,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_lookup_name,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_get_param,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_cleanup,)
struct pci_access *pacc = ffpci_alloc();
ffpci_init(pacc);
ffpci_scan_bus(pacc);
struct pci_dev* dev;
for (dev=pacc->devices; dev; dev=dev->next)
{
ffpci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS);
char class[1024];
ffpci_lookup_name(pacc, class, sizeof(class), PCI_LOOKUP_CLASS, dev->device_class);
if(
strcasecmp("VGA compatible controller", class) == 0 ||
strcasecmp("3D controller", class) == 0 ||
strcasecmp("Display controller", class) == 0
) {
GPUResult* result = ffListAdd(results);
ffStrbufInitA(&result->vendor, 256);
ffpci_lookup_name(pacc, result->vendor.chars, (int) result->vendor.allocated -1, PCI_LOOKUP_VENDOR, dev->vendor_id, dev->device_id);
ffStrbufRecalculateLength(&result->vendor);
ffStrbufInitA(&result->name, 256);
ffpci_lookup_name(pacc, result->name.chars, (int) result->name.allocated - 1, PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
ffStrbufRecalculateLength(&result->name);
ffStrbufInit(&result->driver);
if(instance->config.gpuFormat.length > 0) //We only need it for the format string, so don't detect it if it isn't needed
pciGetDriver(dev, &result->driver, ffpci_get_param);
};
}
ffpci_cleanup(pacc);
dlclose(pci);
}
#endif
static void printGPUResult(FFinstance* instance, uint8_t index, FFcache* cache, GPUResult* result)
static void printGPUResult(FFinstance* instance, uint8_t index, FFcache* cache, FFGPUResult* result)
{
const char* vendorPretty;
if(ffStrbufIgnCaseCompS(&result->vendor, "Advanced Micro Devices, Inc. [AMD/ATI]") == 0)
@@ -222,32 +48,131 @@ static void printGPUResult(FFinstance* instance, uint8_t index, FFcache* cache,
ffStrbufDestroy(&namePretty);
}
static void printGPUList(FFinstance* instance, const FFlist* list)
{
FFcache cache;
ffCacheOpenWrite(instance, FF_GPU_MODULE_NAME, &cache);
for(uint8_t i = 0; i < (uint8_t) list->length; i++)
printGPUResult(instance, list->length == 1 ? 0 : (uint8_t) (i + 1), &cache, ffListGet(list, i));
ffCacheClose(&cache);
}
#ifdef FF_HAVE_LIBPCI
#include <pci/pci.h>
#include <unistd.h>
//see https://github.com/pciutils/pciutils/blob/5bdf63b6b1bc35b59c4b3f47f7ca83ca1868155b/ls-kernel.c#L220
static void pciGetDriver(struct pci_dev* dev, FFstrbuf* driver, char*(*ffpci_get_param)(struct pci_access*, char*))
{
if(dev->access->method != PCI_ACCESS_SYS_BUS_PCI)
return;
const char* base = ffpci_get_param(dev->access, "sysfs.path");
if(!ffStrSet(base))
return;
FFstrbuf path;
ffStrbufInitA(&path, 64);
ffStrbufAppendF(&path, "%s/devices/%04x:%02x:%02x.%d/driver", base, dev->domain, dev->bus, dev->dev, dev->func);
ffStrbufEnsureFree(driver, 1023);
ssize_t resultLength = readlink(path.chars, driver->chars, driver->allocated - 1); //-1 for null terminator
if(resultLength > 0)
{
driver->length = (uint32_t) resultLength;
driver->chars[resultLength] = '\0';
ffStrbufSubstrAfterLastC(driver, '/');
}
ffStrbufDestroy(&path);
}
static bool pciPrintGPUs(FFinstance* instance)
{
FF_LIBRARY_LOAD(pci, instance->config.libPCI, false, "libpci.so", 4)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_alloc, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_init, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_scan_bus, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_fill_info, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_lookup_name, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_get_param, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_cleanup, false)
FFlist results;
ffListInit(&results, sizeof(FFGPUResult));
struct pci_access *pacc = ffpci_alloc();
ffpci_init(pacc);
ffpci_scan_bus(pacc);
struct pci_dev* dev;
for (dev=pacc->devices; dev; dev=dev->next)
{
ffpci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS);
char class[1024];
ffpci_lookup_name(pacc, class, sizeof(class), PCI_LOOKUP_CLASS, dev->device_class);
if(
strcasecmp("VGA compatible controller", class) == 0 ||
strcasecmp("3D controller", class) == 0 ||
strcasecmp("Display controller", class) == 0
) {
FFGPUResult* result = ffListAdd(&results);
ffStrbufInitA(&result->vendor, 256);
ffpci_lookup_name(pacc, result->vendor.chars, (int) result->vendor.allocated -1, PCI_LOOKUP_VENDOR, dev->vendor_id, dev->device_id);
ffStrbufRecalculateLength(&result->vendor);
ffStrbufInitA(&result->name, 256);
ffpci_lookup_name(pacc, result->name.chars, (int) result->name.allocated - 1, PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
ffStrbufRecalculateLength(&result->name);
ffStrbufInit(&result->driver);
if(instance->config.gpuFormat.length > 0) //We only need it for the format string, so don't detect it if it isn't needed
pciGetDriver(dev, &result->driver, ffpci_get_param);
};
}
ffpci_cleanup(pacc);
dlclose(pci);
if(results.length == 0)
{
ffListDestroy(&results);
return false;
}
printGPUList(instance, &results);
ffListDestroy(&results);
return true;
}
#endif
static bool vulkanPrintGPUs(FFinstance* instance)
{
const FFVulkanResult* result = ffDetectVulkan(instance);
if(result->devices.length == 0)
return false;
printGPUList(instance, &result->devices);
return true;
}
void ffPrintGPU(FFinstance* instance)
{
if(ffPrintFromCache(instance, FF_GPU_MODULE_NAME, &instance->config.gpuKey, &instance->config.gpuFormat, FF_GPU_NUM_FORMAT_ARGS))
return;
FFlist gpus;
ffListInitA(&gpus, sizeof(GPUResult), 4);
FFcache cache;
ffCacheOpenWrite(instance, FF_GPU_MODULE_NAME, &cache);
#ifdef FF_HAVE_LIBPCI
pciFillGPUs(instance, &gpus);
if(pciPrintGPUs(instance))
return;
#endif
#ifdef FF_HAVE_VULKAN
if(gpus.length == 0)
vulkanFillGPUs(instance, &gpus);
#endif
if(vulkanPrintGPUs(instance))
return;
for(uint8_t i = 0; i < (uint8_t) gpus.length; i++)
printGPUResult(instance, gpus.length == 1 ? 0 : (uint8_t) (i + 1), &cache, ffListGet(&gpus, i));
if(gpus.length == 0)
ffPrintError(instance, FF_GPU_MODULE_NAME, 0, &instance->config.gpuKey, &instance->config.gpuFormat, FF_GPU_NUM_FORMAT_ARGS, "No GPUs found.");
ffCacheClose(&cache);
ffListDestroy(&gpus);
ffPrintError(instance, FF_GPU_MODULE_NAME, 0, &instance->config.gpuKey, &instance->config.gpuFormat, FF_GPU_NUM_FORMAT_ARGS, "No GPUs found.");
}
+41
View File
@@ -0,0 +1,41 @@
#include "fastfetch.h"
#define FF_VULKAN_MODULE_NAME "Vulkan"
#define FF_VULKAN_NUM_FORMAT_ARGS 3
void ffPrintVulkan(FFinstance* instance)
{
const FFVulkanResult* vulkan = ffDetectVulkan(instance);
if(vulkan->apiVersion.length == 0 && vulkan->driver.length == 0)
{
ffPrintError(instance, FF_VULKAN_MODULE_NAME, 0, &instance->config.vulkanKey, &instance->config.vulkanFormat, FF_VULKAN_NUM_FORMAT_ARGS, "Failed to detect vulkan");
return;
}
if(instance->config.vulkanFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_VULKAN_MODULE_NAME, 0, &instance->config.vulkanKey);
if(vulkan->driver.length > 0)
{
printf("%s (driver)", vulkan->driver.chars);
if(vulkan->apiVersion.length > 0)
fputs(", ", stdout);
}
if(vulkan->apiVersion.length > 0)
printf("%s (api version)", vulkan->apiVersion.chars);
putchar('\n');
}
else
{
ffPrintFormatString(instance, FF_VULKAN_MODULE_NAME, 0, &instance->config.vulkanKey, &instance->config.vulkanFormat, NULL, FF_VULKAN_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRBUF, &vulkan->driver},
{FF_FORMAT_ARG_TYPE_STRBUF, &vulkan->apiVersion},
{FF_FORMAT_ARG_TYPE_STRBUF, &vulkan->conformanceVersion}
});
}
}