mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:14:37 +02:00
Vulkan module
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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: {}"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -31,5 +31,6 @@ Theme
|
||||
Time
|
||||
Title
|
||||
Uptime
|
||||
Vulkan
|
||||
WM
|
||||
WMTheme
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user