diff --git a/CMakeLists.txt b/CMakeLists.txt index 26e64e4ef..5ab4dbaeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -529,6 +529,7 @@ if(LINUX) src/detection/displayserver/linux/xlib.c src/detection/font/font_linux.c src/detection/gpu/gpu_linux.c + src/detection/gpu/gpu_drm.c src/detection/gpu/gpu_pci.c src/detection/gtk_qt/gtk.c src/detection/host/host_linux.c @@ -676,6 +677,7 @@ elseif(FreeBSD) src/detection/displayserver/linux/xlib.c src/detection/font/font_linux.c src/detection/gpu/gpu_bsd.c + src/detection/gpu/gpu_drm.c src/detection/gpu/gpu_pci.c src/detection/gtk_qt/gtk.c src/detection/host/host_bsd.c diff --git a/src/detection/gpu/gpu.h b/src/detection/gpu/gpu.h index a81dd11f1..60d9e1ba6 100644 --- a/src/detection/gpu/gpu.h +++ b/src/detection/gpu/gpu.h @@ -52,4 +52,21 @@ const char* ffGPUGetVendorString(unsigned vendorId); #if defined(__linux__) || defined(__FreeBSD__) || defined(__sun) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu); void ffGPUQueryAmdGpuName(uint16_t deviceId, uint8_t revisionId, FFGPUResult* gpu); -#endif + +#if FF_HAVE_DRM +const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath); +const char* ffDrmDetectI915(FFGPUResult* gpu, int fd); +const char* ffDrmDetectXe(FFGPUResult* gpu, int fd); +const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd); +#endif // FF_HAVE_DRM + +typedef struct FFGpuDriverPciBusId +{ + uint32_t domain; + uint32_t bus; + uint32_t device; + uint32_t func; +} FFGpuDriverPciBusId; +const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId); + +#endif // defined(XXX) diff --git a/src/detection/gpu/gpu_bsd.c b/src/detection/gpu/gpu_bsd.c index 1eac8c930..5057fe05b 100644 --- a/src/detection/gpu/gpu_bsd.c +++ b/src/detection/gpu/gpu_bsd.c @@ -11,17 +11,6 @@ #include // DragonFly #endif -#include "common/library.h" -#include "util/stringUtils.h" -#include -#include - -#ifdef FF_HAVE_DRM_AMDGPU -#include -#include -#include -#endif - static void fillGPUTypeGeneric(FFGPUResult* gpu) { if (gpu->type == FF_GPU_TYPE_UNKNOWN) @@ -47,137 +36,10 @@ static void fillGPUTypeGeneric(FFGPUResult* gpu) } #if FF_HAVE_DRM -static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath) -{ -#if FF_HAVE_DRM_AMDGPU - FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize) +#include "common/library.h" +#include "util/stringUtils.h" - FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY); - if (fd < 0) return "Failed to open DRM device"; - - amdgpu_device_handle handle; - uint32_t majorVersion, minorVersion; - if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0) - return "Failed to initialize AMDGPU device"; - - ffStrbufAppendF(&gpu->driver, " %u.%u", (unsigned) majorVersion, (unsigned) minorVersion); - - uint32_t value; - - if (options->temp) - { - if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0) - gpu->temperature = value / 1000.; - } - - ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle)); - - struct amdgpu_gpu_info gpuInfo; - if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0) - { - gpu->coreCount = (int32_t) gpuInfo.cu_active_number; - gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u); - gpu->index = FF_GPU_INDEX_UNSET; - gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; -#define FF_VRAM_CASE(name, value) case value /* AMDGPU_VRAM_TYPE_ ## name */: ffStrbufSetStatic(&gpu->memoryType, #name); break - switch (gpuInfo.vram_type) - { - FF_VRAM_CASE(UNKNOWN, 0); - FF_VRAM_CASE(GDDR1, 1); - FF_VRAM_CASE(DDR2, 2); - FF_VRAM_CASE(GDDR3, 3); - FF_VRAM_CASE(GDDR4, 4); - FF_VRAM_CASE(GDDR5, 5); - FF_VRAM_CASE(HBM, 6); - FF_VRAM_CASE(DDR3, 7); - FF_VRAM_CASE(DDR4, 8); - FF_VRAM_CASE(GDDR6, 9); - FF_VRAM_CASE(DDR5, 10); - FF_VRAM_CASE(LPDDR4, 11); - FF_VRAM_CASE(LPDDR5, 12); - default: - ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type); - break; - } - - struct amdgpu_heap_info heapInfo; - if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0) - { - if (gpu->type == FF_GPU_TYPE_DISCRETE) - { - gpu->dedicated.total = heapInfo.heap_size; - gpu->dedicated.used = heapInfo.heap_usage; - } - else - { - gpu->shared.total = heapInfo.heap_size; - gpu->shared.used = heapInfo.heap_usage; - } - } - } - - if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0) - gpu->coreUsage = value; - - ffamdgpu_device_deinitialize(handle); - - return NULL; -#else - FF_UNUSED(options, gpu, drmKey, buffer); - return "Fastfetch is compiled without libdrm support"; -#endif -} - -static const char* drmDetectIntelSpecific(FFGPUResult* gpu, int fd) -{ - { - int value; - drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value }; - if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0) - gpu->coreCount = value; - } - { - struct drm_i915_query_item queryItem = { - .query_id = DRM_I915_QUERY_MEMORY_REGIONS, - }; - struct drm_i915_query query = { - .items_ptr = (uintptr_t) &queryItem, - .num_items = 1, - }; - if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 ) - { - FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length); - queryItem.data_ptr = (uintptr_t) buffer; - if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0) - { - gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0; - struct drm_i915_query_memory_regions* regionInfo = (void*) buffer; - for (uint32_t i = 0; i < regionInfo->num_regions; i++) - { - struct drm_i915_memory_region_info* region = regionInfo->regions + i; - switch (region->region.memory_class) - { - case I915_MEMORY_CLASS_SYSTEM: - gpu->shared.total += region->probed_size; - gpu->shared.used += region->probed_size - region->unallocated_size; - break; - case I915_MEMORY_CLASS_DEVICE: - gpu->dedicated.total += region->probed_size; - gpu->dedicated.used += region->probed_size - region->unallocated_size; - break; - } - } - } - } - } - return NULL; -} +#include static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus) { @@ -235,43 +97,30 @@ static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus) if (fd < 0) continue; char driverName[64]; - char driverDesc[64]; + driverName[0] = '\0'; struct drm_version ver = { .name = driverName, .name_len = ARRAY_SIZE(driverName), - .desc = driverDesc, - .desc_len = ARRAY_SIZE(driverDesc), }; if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0) ffStrbufSetF(&gpu->driver, "%*s %d.%d.%d", (int) ver.name_len, ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel); - if (dev->bustype != DRM_BUS_PCI) - continue; - - if (ffStrEquals(ver.name, "i915")) - drmDetectIntelSpecific(gpu, fd); - else if (ffStrEquals(ver.name, "amdgpu")) - drmDetectAmdSpecific(options, gpu, dev->nodes[DRM_NODE_RENDER]); - else if (ffStrEquals(ver.name, "nvidia-drm") && (options->temp || options->driverSpecific)) + if (ffStrStartsWith(driverName, "i915")) + ffDrmDetectI915(gpu, fd); + else if (ffStrStartsWith(driverName, "amdgpu")) + ffDrmDetectAmdgpu(options, gpu, dev->nodes[DRM_NODE_RENDER]); + else if (ffStrStartsWith(driverName, "xe")) + ffDrmDetectXe(gpu, fd); + else if (ffStrStartsWith(driverName, "asahi")) + ffDrmDetectAsahi(gpu, fd); + else if (dev->bustype == DRM_BUS_PCI) { - ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) { - .type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID, - .pciBusId = { - .domain = (uint32_t) dev->businfo.pci->domain, - .bus = dev->businfo.pci->bus, - .device = dev->businfo.pci->dev, - .func = dev->businfo.pci->func, - }, - }, (FFGpuDriverResult) { - .index = &gpu->index, - .temp = options->temp ? &gpu->temperature : NULL, - .memory = options->driverSpecific ? &gpu->dedicated : NULL, - .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL, - .type = &gpu->type, - .frequency = &gpu->frequency, - .coreUsage = &gpu->coreUsage, - .name = &gpu->name, - }, "libnvidia-ml.so"); + ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) { + .domain = (uint32_t) dev->businfo.pci->domain, + .bus = dev->businfo.pci->bus, + .device = dev->businfo.pci->dev, + .func = dev->businfo.pci->func, + }); } if (gpu->name.length == 0) @@ -333,27 +182,12 @@ static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) gpu->deviceId = (pc->pc_sel.pc_domain * 100000ull) + (pc->pc_sel.pc_bus * 1000ull) + (pc->pc_sel.pc_dev * 10ull) + pc->pc_sel.pc_func; gpu->frequency = FF_GPU_FREQUENCY_UNSET; - if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific)) - { - ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) { - .type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID, - .pciBusId = { - .domain = (uint32_t) pc->pc_sel.pc_domain, - .bus = pc->pc_sel.pc_bus, - .device = pc->pc_sel.pc_dev, - .func = pc->pc_sel.pc_func, - }, - }, (FFGpuDriverResult) { - .index = &gpu->index, - .temp = options->temp ? &gpu->temperature : NULL, - .memory = options->driverSpecific ? &gpu->dedicated : NULL, - .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL, - .type = &gpu->type, - .frequency = &gpu->frequency, - .coreUsage = &gpu->coreUsage, - .name = &gpu->name, - }, "libnvidia-ml.so"); - } + ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) { + .domain = (uint32_t) pc->pc_sel.pc_domain, + .bus = pc->pc_sel.pc_bus, + .device = pc->pc_sel.pc_dev, + .func = pc->pc_sel.pc_func, + }); if (gpu->name.length == 0) { diff --git a/src/detection/gpu/gpu_driver_specific.h b/src/detection/gpu/gpu_driver_specific.h index 82db3f66b..37b4a6728 100644 --- a/src/detection/gpu/gpu_driver_specific.h +++ b/src/detection/gpu/gpu_driver_specific.h @@ -10,14 +10,6 @@ typedef enum __attribute__((__packed__)) FFGpuDriverConditionType FF_GPU_DRIVER_CONDITION_TYPE_FORCE_UNSIGNED = UINT8_MAX, } FFGpuDriverConditionType; -typedef struct FFGpuDriverPciBusId -{ - uint32_t domain; - uint32_t bus; - uint32_t device; - uint32_t func; -} FFGpuDriverPciBusId; - typedef struct FFGpuDriverPciDeviceId { uint32_t deviceId; diff --git a/src/detection/gpu/gpu_drm.c b/src/detection/gpu/gpu_drm.c new file mode 100644 index 000000000..35c10737f --- /dev/null +++ b/src/detection/gpu/gpu_drm.c @@ -0,0 +1,317 @@ +#include "gpu.h" + +#if FF_HAVE_DRM +#include +#include +#include + +#include "common/io/io.h" +#include "common/library.h" +#include "util/mallocHelper.h" +#include "util/stringUtils.h" + +#include "intel_drm.h" +#include "asahi_drm.h" + +#ifdef FF_HAVE_DRM_AMDGPU +#include +#include + +const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath) +{ +#if FF_HAVE_DRM_AMDGPU + FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize) + + FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY); + if (fd < 0) return "Failed to open DRM render device"; + + amdgpu_device_handle handle; + uint32_t majorVersion, minorVersion; + if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0) + return "Failed to initialize AMDGPU device"; + + uint32_t value; + + if (options->temp) + { + if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0) + gpu->temperature = value / 1000.; + } + + ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle)); + + struct amdgpu_gpu_info gpuInfo; + if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0) + { + gpu->coreCount = (int32_t) gpuInfo.cu_active_number; + gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u); + gpu->index = FF_GPU_INDEX_UNSET; + gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; +#define FF_VRAM_CASE(name, value) case value /* AMDGPU_VRAM_TYPE_ ## name */: ffStrbufSetStatic(&gpu->memoryType, #name); break + switch (gpuInfo.vram_type) + { + FF_VRAM_CASE(UNKNOWN, 0); + FF_VRAM_CASE(GDDR1, 1); + FF_VRAM_CASE(DDR2, 2); + FF_VRAM_CASE(GDDR3, 3); + FF_VRAM_CASE(GDDR4, 4); + FF_VRAM_CASE(GDDR5, 5); + FF_VRAM_CASE(HBM, 6); + FF_VRAM_CASE(DDR3, 7); + FF_VRAM_CASE(DDR4, 8); + FF_VRAM_CASE(GDDR6, 9); + FF_VRAM_CASE(DDR5, 10); + FF_VRAM_CASE(LPDDR4, 11); + FF_VRAM_CASE(LPDDR5, 12); + default: + ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type); + break; + } + + struct amdgpu_heap_info heapInfo; + if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0) + { + if (gpu->type == FF_GPU_TYPE_DISCRETE) + { + gpu->dedicated.total = heapInfo.heap_size; + gpu->dedicated.used = heapInfo.heap_usage; + } + else + { + gpu->shared.total = heapInfo.heap_size; + gpu->shared.used = heapInfo.heap_usage; + } + } + } + + if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0) + gpu->coreUsage = value; + + ffamdgpu_device_deinitialize(handle); + + return NULL; +#else + FF_UNUSED(gpu, renderPath); + return "Fastfetch is compiled without libdrm support"; +#endif +} +#endif + +const char* ffDrmDetectI915(FFGPUResult* gpu, int fd) +{ + { + int value; + drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value }; + if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0) + gpu->coreCount = value; + } + { + struct drm_i915_query_item queryItem = { + .query_id = DRM_I915_QUERY_MEMORY_REGIONS, + }; + struct drm_i915_query query = { + .items_ptr = (uintptr_t) &queryItem, + .num_items = 1, + }; + if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 ) + { + FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length); + queryItem.data_ptr = (uintptr_t) buffer; + if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0) + { + gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0; + struct drm_i915_query_memory_regions* regionInfo = (void*) buffer; + for (uint32_t i = 0; i < regionInfo->num_regions; i++) + { + struct drm_i915_memory_region_info* region = regionInfo->regions + i; + switch (region->region.memory_class) + { + case I915_MEMORY_CLASS_SYSTEM: + gpu->shared.total += region->probed_size; + gpu->shared.used += region->probed_size - region->unallocated_size; + break; + case I915_MEMORY_CLASS_DEVICE: + gpu->dedicated.total += region->probed_size; + gpu->dedicated.used += region->probed_size - region->unallocated_size; + break; + } + } + } + } + } + return NULL; +} + +static inline int popcountBytes(uint8_t* bytes, uint32_t length) +{ + int count = 0; + while (length >= 8) + { + count += __builtin_popcountll(*(uint64_t*) bytes); + bytes += 8; + length -= 8; + } + if (length >= 4) + { + count += __builtin_popcountl(*(uint32_t*) bytes); + bytes += 4; + length -= 4; + } + if (length >= 2) + { + count += __builtin_popcountl(*(uint16_t*) bytes); + bytes += 2; + length -= 2; + } + if (length) + { + count += __builtin_popcountl(*(uint8_t*) bytes); + } + return count; +} + +const char* ffDrmDetectXe(FFGPUResult* gpu, int fd) +{ + bool flag = false; + { + struct drm_xe_device_query query = { + .query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY, + }; + if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) + { + FF_AUTO_FREE uint8_t* buffer = malloc(query.size); + query.data = (uintptr_t) buffer; + if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) + { + int dssCount = 0, euPerDssCount = 0; + for (struct drm_xe_query_topology_mask* topo = (void*) buffer; + (uint8_t*) topo < buffer + query.size; + topo = (void*) (topo->mask + topo->num_bytes) + ) { + switch (topo->type) + { + case DRM_XE_TOPO_DSS_COMPUTE: + case DRM_XE_TOPO_DSS_GEOMETRY: + dssCount += popcountBytes(topo->mask, topo->num_bytes); + break; + case DRM_XE_TOPO_EU_PER_DSS: + euPerDssCount += popcountBytes(topo->mask, topo->num_bytes); + break; + } + } + gpu->coreCount = dssCount * euPerDssCount; + flag = true; + } + } + } + + { + struct drm_xe_device_query query = { + .query = DRM_XE_DEVICE_QUERY_MEM_REGIONS, + }; + if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) + { + FF_AUTO_FREE uint8_t* buffer = malloc(query.size); + query.data = (uintptr_t) buffer; + if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) + { + gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0; + struct drm_xe_query_mem_regions* regionInfo = (void*) buffer; + for (uint32_t i = 0; i < regionInfo->num_mem_regions; i++) + { + struct drm_xe_mem_region* region = regionInfo->mem_regions + i; + switch (region->mem_class) + { + case DRM_XE_MEM_REGION_CLASS_SYSMEM: + gpu->shared.total += region->total_size; + gpu->shared.used += region->used; + break; + case DRM_XE_MEM_REGION_CLASS_VRAM: + gpu->dedicated.total += region->total_size; + gpu->dedicated.used += region->used; + break; + } + } + flag = true; + } + } + } + return flag ? NULL : "Failed to query Xe GPU information"; +} + +const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd) +{ + struct drm_asahi_params_global paramsGlobal = {}; + if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) { + .param_group = DRM_ASAHI_GET_PARAMS, + .pointer = (uint64_t) ¶msGlobal, + .size = sizeof(paramsGlobal), + }) >= 0) + { + // They removed `unstable_uabi_version` from the struct. Hopefully they won't introduce new ABI changes. + gpu->coreCount = (int32_t) (paramsGlobal.num_clusters_total * paramsGlobal.num_cores_per_cluster); + gpu->frequency = paramsGlobal.max_frequency_khz / 1000; + gpu->deviceId = paramsGlobal.chip_id; + + if (!gpu->name.length) + { + const char* variant = " Unknown"; + switch (paramsGlobal.gpu_variant) { + case 'G': + variant = ""; + break; + case 'S': + variant = " Pro"; + break; + case 'C': + variant = " Max"; + break; + case 'D': + variant = " Ultra"; + break; + } + ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)", + paramsGlobal.gpu_generation - 12, variant, + paramsGlobal.gpu_generation, paramsGlobal.gpu_variant, + paramsGlobal.gpu_revision + 0xA0); + } + + return NULL; + } + + return "Failed to query Asahi GPU information"; +} + +#endif // FF_HAVE_DRM + +#include "gpu_driver_specific.h" + +const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId) +{ + __typeof__(&ffDetectNvidiaGpuInfo) detectFn; + const char* soName; + if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific)) + { + return detectFn(&(FFGpuDriverCondition) { + .type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID, + .pciBusId = pciBusId, + }, (FFGpuDriverResult) { + .index = &gpu->index, + .temp = options->temp ? &gpu->temperature : NULL, + .memory = options->driverSpecific ? &gpu->dedicated : NULL, + .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL, + .coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL, + .type = &gpu->type, + .frequency = options->driverSpecific ? &gpu->frequency : NULL, + .name = &gpu->name, + }, soName); + } + + return "No driver-specific detection function found for the GPU vendor"; +} diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index 681845f1f..48ffe46a3 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -105,94 +105,14 @@ FF_MAYBE_UNUSED static const char* drmFindRenderFromCard(const char* drmCardKey, static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer) { - #if FF_HAVE_DRM_AMDGPU - - FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize) - - { - const char* error = drmFindRenderFromCard(drmKey, buffer); - if (error) return error; - } - FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY); - if (fd < 0) return "Failed to open DRM device"; - - amdgpu_device_handle handle; - uint32_t majorVersion, minorVersion; - if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0) - return "Failed to initialize AMDGPU device"; - - ffStrbufAppendF(&gpu->driver, " %u.%u", (unsigned) majorVersion, (unsigned) minorVersion); - - uint32_t value; - - if (options->temp) - { - if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0) - gpu->temperature = value / 1000.; - } - - ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle)); - - struct amdgpu_gpu_info gpuInfo; - if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0) - { - gpu->coreCount = (int32_t) gpuInfo.cu_active_number; - gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u); - gpu->index = FF_GPU_INDEX_UNSET; - gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; - #define FF_VRAM_CASE(name, value) case value /* AMDGPU_VRAM_TYPE_ ## name */: ffStrbufSetStatic(&gpu->memoryType, #name); break - switch (gpuInfo.vram_type) - { - FF_VRAM_CASE(UNKNOWN, 0); - FF_VRAM_CASE(GDDR1, 1); - FF_VRAM_CASE(DDR2, 2); - FF_VRAM_CASE(GDDR3, 3); - FF_VRAM_CASE(GDDR4, 4); - FF_VRAM_CASE(GDDR5, 5); - FF_VRAM_CASE(HBM, 6); - FF_VRAM_CASE(DDR3, 7); - FF_VRAM_CASE(DDR4, 8); - FF_VRAM_CASE(GDDR6, 9); - FF_VRAM_CASE(DDR5, 10); - FF_VRAM_CASE(LPDDR4, 11); - FF_VRAM_CASE(LPDDR5, 12); - default: - ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type); - break; - } - - struct amdgpu_heap_info heapInfo; - if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0) - { - if (gpu->type == FF_GPU_TYPE_DISCRETE) - { - gpu->dedicated.total = heapInfo.heap_size; - gpu->dedicated.used = heapInfo.heap_usage; - } - else - { - gpu->shared.total = heapInfo.heap_size; - gpu->shared.used = heapInfo.heap_usage; - } - } - } - - if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0) - gpu->coreUsage = value; - - ffamdgpu_device_deinitialize(handle); - - return NULL; +#if FF_HAVE_DRM_AMDGPU + const char* error = drmFindRenderFromCard(drmKey, buffer); + if (error) return error; + return ffDrmDetectAmdgpu(options, gpu, buffer->chars); #else FF_UNUSED(options, gpu, drmKey, buffer); - return "Fastfetch is compiled without libdrm support"; - #endif + return "Fastfetch is not compiled with libdrm_amdgpu support"; +#endif } static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer) @@ -311,34 +231,6 @@ static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu } } -static inline int popcountBytes(uint8_t* bytes, uint32_t length) -{ - int count = 0; - while (length >= 8) - { - count += __builtin_popcountll(*(uint64_t*) bytes); - bytes += 8; - length -= 8; - } - if (length >= 4) - { - count += __builtin_popcountl(*(uint32_t*) bytes); - bytes += 4; - length -= 4; - } - if (length >= 2) - { - count += __builtin_popcountl(*(uint16_t*) bytes); - bytes += 2; - length -= 2; - } - if (length) - { - count += __builtin_popcountl(*(uint8_t*) bytes); - } - return count; -} - static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer) { #if FF_HAVE_DRM @@ -348,113 +240,10 @@ static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, if (fd < 0) return "Failed to open drm device"; if (ffStrbufEqualS(&gpu->driver, "xe")) - { - { - struct drm_xe_device_query query = { - .query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY, - }; - if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) - { - FF_AUTO_FREE uint8_t* buffer = malloc(query.size); - query.data = (uintptr_t) buffer; - if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) - { - int dssCount = 0, euPerDssCount = 0; - for (struct drm_xe_query_topology_mask* topo = (void*) buffer; - (uint8_t*) topo < buffer + query.size; - topo = (void*) (topo->mask + topo->num_bytes) - ) { - switch (topo->type) - { - case DRM_XE_TOPO_DSS_COMPUTE: - case DRM_XE_TOPO_DSS_GEOMETRY: - dssCount += popcountBytes(topo->mask, topo->num_bytes); - break; - case DRM_XE_TOPO_EU_PER_DSS: - euPerDssCount += popcountBytes(topo->mask, topo->num_bytes); - break; - } - } - gpu->coreCount = dssCount * euPerDssCount; - } - } - } - - { - struct drm_xe_device_query query = { - .query = DRM_XE_DEVICE_QUERY_MEM_REGIONS, - }; - if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) - { - FF_AUTO_FREE uint8_t* buffer = malloc(query.size); - query.data = (uintptr_t) buffer; - if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) - { - gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0; - struct drm_xe_query_mem_regions* regionInfo = (void*) buffer; - for (uint32_t i = 0; i < regionInfo->num_mem_regions; i++) - { - struct drm_xe_mem_region* region = regionInfo->mem_regions + i; - switch (region->mem_class) - { - case DRM_XE_MEM_REGION_CLASS_SYSMEM: - gpu->shared.total += region->total_size; - gpu->shared.used += region->used; - break; - case DRM_XE_MEM_REGION_CLASS_VRAM: - gpu->dedicated.total += region->total_size; - gpu->dedicated.used += region->used; - break; - } - } - } - } - } - } + return ffDrmDetectXe(gpu, fd); else if (ffStrbufEqualS(&gpu->driver, "i915")) - { - { - int value; - drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value }; - if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0) - gpu->coreCount = value; - } - { - struct drm_i915_query_item queryItem = { - .query_id = DRM_I915_QUERY_MEMORY_REGIONS, - }; - struct drm_i915_query query = { - .items_ptr = (uintptr_t) &queryItem, - .num_items = 1, - }; - if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 ) - { - FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length); - queryItem.data_ptr = (uintptr_t) buffer; - if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0) - { - gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0; - struct drm_i915_query_memory_regions* regionInfo = (void*) buffer; - for (uint32_t i = 0; i < regionInfo->num_regions; i++) - { - struct drm_i915_memory_region_info* region = regionInfo->regions + i; - switch (region->region.memory_class) - { - case I915_MEMORY_CLASS_SYSTEM: - gpu->shared.total += region->probed_size; - gpu->shared.used += region->probed_size - region->unallocated_size; - break; - case I915_MEMORY_CLASS_DEVICE: - gpu->dedicated.total += region->probed_size; - gpu->dedicated.used += region->probed_size - region->unallocated_size; - break; - } - } - } - } - } - } - return NULL; + return ffDrmDetectI915(gpu, fd); + return "Unknown Intel GPU driver"; #else FF_UNUSED(gpu, drmKey, buffer); return "Fastfetch is not compiled with drm support"; @@ -569,29 +358,12 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf } else { - __typeof__(&ffDetectNvidiaGpuInfo) detectFn; - const char* soName; - if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific)) - { - detectFn(&(FFGpuDriverCondition) { - .type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID, - .pciBusId = { - .domain = pciDomain, - .bus = pciBus, - .device = pciDevice, - .func = pciFunc, - }, - }, (FFGpuDriverResult) { - .index = &gpu->index, - .temp = options->temp ? &gpu->temperature : NULL, - .memory = options->driverSpecific ? &gpu->dedicated : NULL, - .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL, - .coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL, - .type = &gpu->type, - .frequency = options->driverSpecific ? &gpu->frequency : NULL, - .name = &gpu->name, - }, soName); - } + ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) { + .domain = pciDomain, + .bus = pciBus, + .device = pciDevice, + .func = pciFunc, + }); } if (gpu->name.length == 0) @@ -629,43 +401,7 @@ FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, cons ffStrbufAppendS(buffer, drmKey); FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY); if (fd >= 0) - { - struct drm_asahi_params_global paramsGlobal = {}; - if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) { - .param_group = DRM_ASAHI_GET_PARAMS, - .pointer = (uint64_t) ¶msGlobal, - .size = sizeof(paramsGlobal), - }) >= 0) - { - // They removed `unstable_uabi_version` from the struct. Hopefully they won't introduce new ABI changes. - gpu->coreCount = (int32_t) (paramsGlobal.num_clusters_total * paramsGlobal.num_cores_per_cluster); - gpu->frequency = paramsGlobal.max_frequency_khz / 1000; - gpu->deviceId = paramsGlobal.chip_id; - - if (!gpu->name.length) - { - const char* variant = " Unknown"; - switch (paramsGlobal.gpu_variant) { - case 'G': - variant = ""; - break; - case 'S': - variant = " Pro"; - break; - case 'C': - variant = " Max"; - break; - case 'D': - variant = " Ultra"; - break; - } - ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)", - paramsGlobal.gpu_generation - 12, variant, - paramsGlobal.gpu_generation, paramsGlobal.gpu_variant, - paramsGlobal.gpu_revision + 0xA0); - } - } - } + return ffDrmDetectAsahi(gpu, fd); #endif return NULL;