From b8e25bdc4e45c3e79817796826d9b23b94246cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 13 Feb 2025 10:43:11 +0800 Subject: [PATCH] GPU: support embedding amdgpu.ids into fastfetch --- CMakeLists.txt | 24 ++++++++++++++++++ scripts/gen-amdgpuids.py | 43 ++++++++++++++++++++++++++++++++ src/detection/gpu/gpu.h | 1 + src/detection/gpu/gpu_bsd.c | 7 +----- src/detection/gpu/gpu_general.c | 7 +----- src/detection/gpu/gpu_linux.c | 11 +-------- src/detection/gpu/gpu_pci.c | 44 +++++++++++++++++++++++++++++++++ src/detection/gpu/gpu_sunos.c | 7 +----- 8 files changed, 116 insertions(+), 28 deletions(-) create mode 100755 scripts/gen-amdgpuids.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 525285009..148582670 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by gith option(IS_MUSL "Build with musl libc" OFF) # Used by Github Actions option(INSTALL_LICENSE "Install license into /usr/share/licenses" ON) option(ENABLE_EMBEDDED_PCIIDS "Embed pci.ids into fastfetch, requires `python`" OFF) +option(ENABLE_EMBEDDED_AMDGPUIDS "Embed amdgpu.ids into fastfetch, requires `python`" OFF) set(BINARY_LINK_TYPE_OPTIONS dlopen dynamic static) set(BINARY_LINK_TYPE dlopen CACHE STRING "How to link fastfetch") @@ -289,6 +290,26 @@ if(ENABLE_EMBEDDED_PCIIDS AND NOT EXISTS "${PROJECT_BINARY_DIR}/fastfetch_pciids endif() endif() +if(ENABLE_EMBEDDED_AMDGPUIDS AND NOT EXISTS "${PROJECT_BINARY_DIR}/fastfetch_amdgpuids.c.inc") + if(Python_FOUND) + if(NOT EXISTS "${PROJECT_BINARY_DIR}/amdgpu.ids") + message(STATUS "'${PROJECT_BINARY_DIR}/amdgpu.ids' is missing, downloading...") + file(DOWNLOAD "https://gitlab.freedesktop.org/mesa/drm/-/raw/main/data/amdgpu.ids" "${PROJECT_BINARY_DIR}/amdgpu.ids") + endif() + message(STATUS "Generating 'fastfetch_amdgpuids.c.inc'") + execute_process(COMMAND ${Python_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/scripts/gen-amdgpuids.py" "${PROJECT_BINARY_DIR}/amdgpu.ids" + OUTPUT_FILE "${PROJECT_BINARY_DIR}/fastfetch_amdgpuids.c.inc" + RESULT_VARIABLE PYTHON_AMDGPUIDS_RETCODE) + if(NOT PYTHON_AMDGPUIDS_RETCODE EQUAL 0) + file(REMOVE "${PROJECT_BINARY_DIR}/fastfetch_amdgpuids.c.inc") + message(FATAL_ERROR "Failed to generate 'fastfetch_amdgpuids.c.inc'") + endif() + else() + message(WARNING "Python3 is not found, 'fastfetch_amdgpuids.c.inc' will not be generated") + set(ENABLE_EMBEDDED_AMDGPUIDS OFF) + endif() +endif() + if(Python_FOUND) message(STATUS "Generating 'fastfetch.1'") execute_process(COMMAND ${Python_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/scripts/gen-man.py" @@ -1517,6 +1538,9 @@ endif() if(ENABLE_EMBEDDED_PCIIDS) target_compile_definitions(libfastfetch PRIVATE FF_HAVE_EMBEDDED_PCIIDS=1) endif() +if(ENABLE_EMBEDDED_AMDGPUIDS) + target_compile_definitions(libfastfetch PRIVATE FF_HAVE_EMBEDDED_AMDGPUIDS=1) +endif() if(LINUX) target_link_libraries(libfastfetch diff --git a/scripts/gen-amdgpuids.py b/scripts/gen-amdgpuids.py new file mode 100755 index 000000000..253c3a370 --- /dev/null +++ b/scripts/gen-amdgpuids.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +import sys + +def main(amdgpu_ids_path: str): + with open(amdgpu_ids_path, 'r') as f: + full_text = f.read() + + products = [] + for line in full_text.split('\n'): + if not line or line[0] == '#' or not ',\t' in line: + continue + device, revision, name = line.split(',\t', maxsplit=2) + products.append((device, revision, name)) + + code = """\ +// SPDX-License-Identifier: MIT +// https://opensource.org/license/mit +// Generated from https://gitlab.freedesktop.org/mesa/drm/-/raw/main/data/amdgpu.ids + +#include +#include + +typedef struct FFArmGpuProduct +{ + const uint32_t id; // device << 8 | revision + const char* name; +} FFArmGpuProduct; + +const FFArmGpuProduct ffAmdGpuProducts[] = { +""" + + for device, revision, name in products: + code += f" {{ 0x{device} << 8 | 0x{revision}, \"{name.replace('"', '\\"')}\" }},\n" + + code += "};\n" + + print(code) + +if __name__ == '__main__': + len(sys.argv) == 2 or sys.exit('Usage: gen-amdgpuids.py ') + + main(sys.argv[1]) diff --git a/src/detection/gpu/gpu.h b/src/detection/gpu/gpu.h index 7ed37910f..bef90b6d5 100644 --- a/src/detection/gpu/gpu.h +++ b/src/detection/gpu/gpu.h @@ -50,4 +50,5 @@ 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 diff --git a/src/detection/gpu/gpu_bsd.c b/src/detection/gpu/gpu_bsd.c index 40821c9b8..1525e9e0e 100644 --- a/src/detection/gpu/gpu_bsd.c +++ b/src/detection/gpu/gpu_bsd.c @@ -1,7 +1,6 @@ #include "gpu_driver_specific.h" #include "common/io/io.h" -#include "common/properties.h" #include #include @@ -76,11 +75,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) if (gpu->name.length == 0) { if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) - { - char query[32]; - snprintf(query, ARRAY_SIZE(query), "%X,\t%X,", (unsigned) pc->pc_device, (unsigned) pc->pc_revid); - ffParsePropFileData("libdrm/amdgpu.ids", query, &gpu->name); - } + ffGPUQueryAmdGpuName(pc->pc_device, pc->pc_revid, gpu); if (gpu->name.length == 0) ffGPUFillVendorAndName(pc->pc_subclass, pc->pc_vendor, pc->pc_device, gpu); } diff --git a/src/detection/gpu/gpu_general.c b/src/detection/gpu/gpu_general.c index 464cccbef..fdffcdd90 100644 --- a/src/detection/gpu/gpu_general.c +++ b/src/detection/gpu/gpu_general.c @@ -2,7 +2,6 @@ #ifdef FF_HAVE_PCIACCESS -#include "common/properties.h" #include "common/io/io.h" #include "common/library.h" @@ -43,11 +42,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpu->frequency = FF_GPU_FREQUENCY_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) - { - char query[32]; - snprintf(query, sizeof(query), "%X,\t%X,", (unsigned) dev->device_id, (unsigned) dev->revision); - ffParsePropFileData("libdrm/amdgpu.ids", query, &gpu->name); - } + ffGPUQueryAmdGpuName(dev->device_id, dev->revision, gpu); if (gpu->name.length == 0) { diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index cc655e31e..f2563917b 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -4,7 +4,6 @@ #include "detection/gpu/gpu_driver_specific.h" #include "common/io/io.h" #include "common/library.h" -#include "common/properties.h" #include "util/stringUtils.h" #include "util/mallocHelper.h" @@ -491,15 +490,7 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf char* pend; uint64_t revision = strtoul(buffer->chars, &pend, 16); if (pend != buffer->chars) - { - char query[32]; - snprintf(query, ARRAY_SIZE(query), "%X,\t%X,", (unsigned) deviceId, (unsigned) revision); - #ifdef FF_CUSTOM_AMDGPU_IDS_PATH - ffParsePropFile(FF_STR(FF_CUSTOM_AMDGPU_IDS_PATH), query, &gpu->name); - #else - ffParsePropFileData("libdrm/amdgpu.ids", query, &gpu->name); - #endif - } + ffGPUQueryAmdGpuName((uint16_t) deviceId, (uint8_t) revision, gpu); } ffStrbufSubstrBefore(deviceDir, drmDirPathLength); } diff --git a/src/detection/gpu/gpu_pci.c b/src/detection/gpu/gpu_pci.c index dfc35558d..11fd3ab10 100644 --- a/src/detection/gpu/gpu_pci.c +++ b/src/detection/gpu/gpu_pci.c @@ -1,5 +1,6 @@ #include "gpu.h" #include "common/io/io.h" +#include "common/properties.h" #include #ifdef __FreeBSD__ @@ -16,6 +17,9 @@ #if FF_HAVE_EMBEDDED_PCIIDS #include "fastfetch_pciids.c.inc" #endif +#if FF_HAVE_EMBEDDED_AMDGPUIDS +#include "fastfetch_amdgpuids.c.inc" +#endif #define FF_STR_INDIR(x) #x #define FF_STR(x) FF_STR_INDIR(x) @@ -191,3 +195,43 @@ void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, #endif return parsePciIdsFile(loadPciIds(), subclass, vendor, device, gpu); } + +#if FF_HAVE_EMBEDDED_AMDGPUIDS +static inline int amdGpuCmp(const uint32_t* key, const FFArmGpuProduct* element) +{ + // Maximum value of *key is 0x00FFFFFF. `(int) *key` should never overflow + return (int) *key - (int) element->id; +} + +static bool loadAmdGpuIdsInc(uint16_t deviceId, uint8_t revision, FFGPUResult* gpu) +{ + uint32_t key = (deviceId << 8u) | revision; + FFArmGpuProduct* product = bsearch(&key, ffAmdGpuProducts, ARRAY_SIZE(ffAmdGpuProducts), sizeof(*ffAmdGpuProducts), (void*) amdGpuCmp); + if (product) + { + ffStrbufSetS(&gpu->name, product->name); + return true; + } + return false; +} +#endif + +static void parseAmdGpuIdsFile(uint16_t deviceId, uint8_t revision, FFGPUResult* gpu) +{ + char query[32]; + snprintf(query, ARRAY_SIZE(query), "%X,\t%X,", (unsigned) deviceId, (unsigned) revision); + #ifdef FF_CUSTOM_AMDGPU_IDS_PATH + ffParsePropFile(FF_STR(FF_CUSTOM_AMDGPU_IDS_PATH), query, &gpu->name); + #else + ffParsePropFileData("libdrm/amdgpu.ids", query, &gpu->name); + #endif +} + +void ffGPUQueryAmdGpuName(uint16_t deviceId, uint8_t revisionId, FFGPUResult* gpu) +{ + #if FF_HAVE_EMBEDDED_AMDGPUIDS + bool ok = loadAmdGpuIdsInc(deviceId, revisionId, gpu); + if (ok) return; + #endif + return parseAmdGpuIdsFile(deviceId, revisionId, gpu); +} diff --git a/src/detection/gpu/gpu_sunos.c b/src/detection/gpu/gpu_sunos.c index d79f430e2..8c59f7dc6 100644 --- a/src/detection/gpu/gpu_sunos.c +++ b/src/detection/gpu/gpu_sunos.c @@ -1,5 +1,4 @@ #include "gpu.h" -#include "common/properties.h" #include "common/io/io.h" #include "common/processing.h" @@ -65,11 +64,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpu->frequency = FF_GPU_FREQUENCY_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) - { - char query[32]; - snprintf(query, ARRAY_SIZE(query), "%X,\t%X,", (unsigned) deviceId, (unsigned) revision); - ffParsePropFileData("libdrm/amdgpu.ids", query, &gpu->name); - } + ffGPUQueryAmdGpuName((uint16_t) deviceId, (uint8_t) revision, gpu); if (gpu->name.length == 0) {