diff --git a/CMakeLists.txt b/CMakeLists.txt index d1c3e80b9..f3e390365 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,7 @@ add_library(libfastfetch STATIC src/detection/plasma.c src/detection/gtk.c src/detection/terminalShell.c + src/detection/vulkan.c src/detection/media.c src/detection/datetime.c src/detection/displayserver/displayServer.c @@ -158,6 +159,7 @@ add_library(libfastfetch STATIC src/modules/disk.c src/modules/battery.c src/modules/locale.c + src/modules/vulkan.c src/modules/localip.c src/modules/publicip.c src/modules/player.c diff --git a/README.md b/README.md index 73398608f..a2d32b23e 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ All categories not listed here should work without needing a specific implementa ##### Available Modules ``` -Title, Separator, OS, Host, Kernel, Uptime, Processes, Packages, Shell, Resolution, DE, WM, WMTheme, Theme, Icons, Font, Cursor, Terminal, Terminal Font, CPU, CPUUsage, GPU, Memory, Disk, Battery, Player, Song, LocalIP, PublicIP, DateTime, Date, Time, Locale, Colors, Break, Custom +Title, Separator, OS, Host, Kernel, Uptime, Processes, Packages, Shell, Resolution, DE, WM, WMTheme, Theme, Icons, Font, Cursor, Terminal, Terminal Font, CPU, CPUUsage, GPU, Memory, Disk, Battery, Player, Song, Vulkan, LocalIP, PublicIP, DateTime, Date, Time, Locale, Colors, Break, Custom ``` ##### Logos diff --git a/presets/all b/presets/all index ecc086397..08094c54d 100644 --- a/presets/all +++ b/presets/all @@ -1 +1 @@ ---structure Title:Separator:OS:Host:Kernel:Uptime:Processes:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:Player:Song:PublicIP:LocalIP:DateTime:Locale:Break:Colors +--structure Title:Separator:OS:Host:Kernel:Uptime:Processes:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:Player:Song:PublicIP:LocalIP:DateTime:Locale:Vulkan:Break:Colors diff --git a/presets/verbose b/presets/verbose index 9f65e6159..d402c011c 100644 --- a/presets/verbose +++ b/presets/verbose @@ -26,3 +26,4 @@ --player-format "Name: {}" --song-format "Song: {}; Artist: {}; Album: {}" --datetime-format "year: {}; yearShort: {}; month: {}; monthPretty: {}; monthName: {}; monthNameShort: {}; weekNumber: {}; weekday: {}; weekdayShort: {}; dayInYear: {}; dayInMonth: {}; dayInWeek: {}; hour: {}; hourPretty: {}; hour12: {}; hour12Pretty: {}; minute: {}; minutePretty: {}; second: {}; secondPretty: {}" +--vulkan-format "driver: {}; Api Version: {}; Conformance Version: {}" diff --git a/src/common/init.c b/src/common/init.c index 10f9bd5ba..0fbf4570b 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -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); diff --git a/src/common/parsing.c b/src/common/parsing.c index 416d80cc9..2ea8b30ed 100644 --- a/src/common/parsing.c +++ b/src/common/parsing.c @@ -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) diff --git a/src/data/config.txt b/src/data/config.txt index 48ae0e8f5..5f2759128 100644 --- a/src/data/config.txt +++ b/src/data/config.txt @@ -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. diff --git a/src/data/help.txt b/src/data/help.txt index 240783588..10a986515 100644 --- a/src/data/help.txt +++ b/src/data/help.txt @@ -76,6 +76,7 @@ Format options: Provide the format string for custom output. Use fastfetch --hel --datetime-format --time-format --date-format + --vulkan-format Key options: Provide a custom key for an output --os-key @@ -109,6 +110,7 @@ Key options: Provide a custom key for an output --datetime-key --time-key --date-key + --vulkan-key Library options: Set the path of a library to load --lib-PCI diff --git a/src/data/modules.txt b/src/data/modules.txt index 25416f7cc..f2dcdcbb0 100644 --- a/src/data/modules.txt +++ b/src/data/modules.txt @@ -31,5 +31,6 @@ Theme Time Title Uptime +Vulkan WM WMTheme diff --git a/src/detection/vulkan.c b/src/detection/vulkan.c new file mode 100644 index 000000000..2c985d801 --- /dev/null +++ b/src/detection/vulkan.c @@ -0,0 +1,223 @@ +#include "fastfetch.h" + +#include + +#ifdef FF_HAVE_VULKAN +#include + +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; +} diff --git a/src/fastfetch.c b/src/fastfetch.c index 0937bbbb0..0d4dd0830 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -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, ""); } diff --git a/src/fastfetch.h b/src/fastfetch.h index ff6b4e503..886bed4c1 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -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 diff --git a/src/fastfetch_config.h.in b/src/fastfetch_config.h.in index debfe63f1..d7bbf7fcf 100644 --- a/src/fastfetch_config.h.in +++ b/src/fastfetch_config.h.in @@ -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@" diff --git a/src/modules/gpu.c b/src/modules/gpu.c index a0e30811b..05506109b 100644 --- a/src/modules/gpu.c +++ b/src/modules/gpu.c @@ -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 - -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 -#include - -//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 +#include + +//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."); } diff --git a/src/modules/vulkan.c b/src/modules/vulkan.c new file mode 100644 index 000000000..974c0007d --- /dev/null +++ b/src/modules/vulkan.c @@ -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} + }); + } +}