11#include "gpu_driver_specific.h"
22
33#include "common/io/io.h"
4+ #include "util/mallocHelper.h"
45
56#include <sys/pciio.h>
67#include <fcntl.h>
1011 #include <bus/pci/pcireg.h> // DragonFly
1112#endif
1213
13- const char * ffDetectGPUImpl (const FFGPUOptions * options , FFlist * gpus )
14+ #include "common/library.h"
15+ #include "util/stringUtils.h"
16+ #include <xf86drm.h>
17+ #include <i915_drm.h>
18+
19+ #ifdef FF_HAVE_DRM_AMDGPU
20+ #include <amdgpu.h>
21+ #include <amdgpu_drm.h>
22+ #include <fcntl.h>
23+ #endif
24+
25+ static void fillGPUTypeGeneric (FFGPUResult * gpu )
26+ {
27+ if (gpu -> type == FF_GPU_TYPE_UNKNOWN )
28+ {
29+ if (gpu -> vendor .chars == FF_GPU_VENDOR_NAME_NVIDIA )
30+ {
31+ if (ffStrbufStartsWithIgnCaseS (& gpu -> name , "GeForce" ) ||
32+ ffStrbufStartsWithIgnCaseS (& gpu -> name , "Quadro" ) ||
33+ ffStrbufStartsWithIgnCaseS (& gpu -> name , "Tesla" ))
34+ gpu -> type = FF_GPU_TYPE_DISCRETE ;
35+ }
36+ else if (gpu -> vendor .chars == FF_GPU_VENDOR_NAME_MTHREADS )
37+ {
38+ if (ffStrbufStartsWithIgnCaseS (& gpu -> name , "MTT " ))
39+ gpu -> type = FF_GPU_TYPE_DISCRETE ;
40+ }
41+ else if (gpu -> vendor .chars == FF_GPU_VENDOR_NAME_INTEL )
42+ {
43+ // 0000:00:02.0 is reserved for Intel integrated graphics
44+ gpu -> type = gpu -> deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE ;
45+ }
46+ }
47+ }
48+
49+ #if FF_HAVE_DRM
50+ static const char * drmDetectAmdSpecific (const FFGPUOptions * options , FFGPUResult * gpu , const char * renderPath )
51+ {
52+ #if FF_HAVE_DRM_AMDGPU
53+ FF_LIBRARY_LOAD (libdrm , "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed" , "libdrm_amdgpu" FF_LIBRARY_EXTENSION , 1 )
54+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE (libdrm , amdgpu_device_initialize )
55+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE (libdrm , amdgpu_get_marketing_name )
56+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE (libdrm , amdgpu_query_gpu_info )
57+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE (libdrm , amdgpu_query_sensor_info )
58+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE (libdrm , amdgpu_query_heap_info )
59+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE (libdrm , amdgpu_device_deinitialize )
60+
61+ FF_AUTO_CLOSE_FD int fd = open (renderPath , O_RDONLY );
62+ if (fd < 0 ) return "Failed to open DRM device" ;
63+
64+ amdgpu_device_handle handle ;
65+ uint32_t majorVersion , minorVersion ;
66+ if (ffamdgpu_device_initialize (fd , & majorVersion , & minorVersion , & handle ) < 0 )
67+ return "Failed to initialize AMDGPU device" ;
68+
69+ ffStrbufAppendF (& gpu -> driver , " %u.%u" , (unsigned ) majorVersion , (unsigned ) minorVersion );
70+
71+ uint32_t value ;
72+
73+ if (options -> temp )
74+ {
75+ if (ffamdgpu_query_sensor_info (handle , AMDGPU_INFO_SENSOR_GPU_TEMP , sizeof (value ), & value ) >= 0 )
76+ gpu -> temperature = value / 1000. ;
77+ }
78+
79+ ffStrbufSetS (& gpu -> name , ffamdgpu_get_marketing_name (handle ));
80+
81+ struct amdgpu_gpu_info gpuInfo ;
82+ if (ffamdgpu_query_gpu_info (handle , & gpuInfo ) >= 0 )
83+ {
84+ gpu -> coreCount = (int32_t ) gpuInfo .cu_active_number ;
85+ gpu -> frequency = (uint32_t ) (gpuInfo .max_engine_clk / 1000u );
86+ gpu -> index = FF_GPU_INDEX_UNSET ;
87+ gpu -> type = gpuInfo .ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE ;
88+ #define FF_VRAM_CASE (name , value ) case value /* AMDGPU_VRAM_TYPE_ ## name */ : ffStrbufSetStatic (& gpu ->memoryType, #name); break
89+ switch (gpuInfo .vram_type )
90+ {
91+ FF_VRAM_CASE (UNKNOWN , 0 );
92+ FF_VRAM_CASE (GDDR1 , 1 );
93+ FF_VRAM_CASE (DDR2 , 2 );
94+ FF_VRAM_CASE (GDDR3 , 3 );
95+ FF_VRAM_CASE (GDDR4 , 4 );
96+ FF_VRAM_CASE (GDDR5 , 5 );
97+ FF_VRAM_CASE (HBM , 6 );
98+ FF_VRAM_CASE (DDR3 , 7 );
99+ FF_VRAM_CASE (DDR4 , 8 );
100+ FF_VRAM_CASE (GDDR6 , 9 );
101+ FF_VRAM_CASE (DDR5 , 10 );
102+ FF_VRAM_CASE (LPDDR4 , 11 );
103+ FF_VRAM_CASE (LPDDR5 , 12 );
104+ default :
105+ ffStrbufAppendF (& gpu -> memoryType , "Unknown (%u)" , gpuInfo .vram_type );
106+ break ;
107+ }
108+
109+ struct amdgpu_heap_info heapInfo ;
110+ if (ffamdgpu_query_heap_info (handle , AMDGPU_GEM_DOMAIN_VRAM , 0 , & heapInfo ) >= 0 )
111+ {
112+ if (gpu -> type == FF_GPU_TYPE_DISCRETE )
113+ {
114+ gpu -> dedicated .total = heapInfo .heap_size ;
115+ gpu -> dedicated .used = heapInfo .heap_usage ;
116+ }
117+ else
118+ {
119+ gpu -> shared .total = heapInfo .heap_size ;
120+ gpu -> shared .used = heapInfo .heap_usage ;
121+ }
122+ }
123+ }
124+
125+ if (ffamdgpu_query_sensor_info (handle , AMDGPU_INFO_SENSOR_GPU_LOAD , sizeof (value ), & value ) >= 0 )
126+ gpu -> coreUsage = value ;
127+
128+ ffamdgpu_device_deinitialize (handle );
129+
130+ return NULL ;
131+ #else
132+ FF_UNUSED (options , gpu , drmKey , buffer );
133+ return "Fastfetch is compiled without libdrm support" ;
134+ #endif
135+ }
136+
137+ static const char * drmDetectIntelSpecific (FFGPUResult * gpu , int fd )
138+ {
139+ {
140+ int value ;
141+ drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL , .value = & value };
142+ if (ioctl (fd , DRM_IOCTL_I915_GETPARAM , & getparam ) >= 0 )
143+ gpu -> coreCount = value ;
144+ }
145+ {
146+ struct drm_i915_query_item queryItem = {
147+ .query_id = DRM_I915_QUERY_MEMORY_REGIONS ,
148+ };
149+ struct drm_i915_query query = {
150+ .items_ptr = (uintptr_t ) & queryItem ,
151+ .num_items = 1 ,
152+ };
153+ if (ioctl (fd , DRM_IOCTL_I915_QUERY , & query ) >= 0 )
154+ {
155+ FF_AUTO_FREE uint8_t * buffer = calloc (1 , (size_t ) queryItem .length );
156+ queryItem .data_ptr = (uintptr_t ) buffer ;
157+ if (ioctl (fd , DRM_IOCTL_I915_QUERY , & query ) >= 0 )
158+ {
159+ gpu -> dedicated .total = gpu -> shared .total = gpu -> dedicated .used = gpu -> shared .used = 0 ;
160+ struct drm_i915_query_memory_regions * regionInfo = (void * ) buffer ;
161+ for (uint32_t i = 0 ; i < regionInfo -> num_regions ; i ++ )
162+ {
163+ struct drm_i915_memory_region_info * region = regionInfo -> regions + i ;
164+ switch (region -> region .memory_class )
165+ {
166+ case I915_MEMORY_CLASS_SYSTEM :
167+ gpu -> shared .total += region -> probed_size ;
168+ gpu -> shared .used += region -> probed_size - region -> unallocated_size ;
169+ break ;
170+ case I915_MEMORY_CLASS_DEVICE :
171+ gpu -> dedicated .total += region -> probed_size ;
172+ gpu -> dedicated .used += region -> probed_size - region -> unallocated_size ;
173+ break ;
174+ }
175+ }
176+ }
177+ }
178+ }
179+ return NULL ;
180+ }
181+
182+ static const char * detectByDrm (const FFGPUOptions * options , FFlist * gpus )
183+ {
184+ FF_LIBRARY_LOAD (libdrm , "dlopen libdrm" FF_LIBRARY_EXTENSION " failed" , "libdrm" FF_LIBRARY_EXTENSION , 2 )
185+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE (libdrm , drmGetDevices )
186+
187+ drmDevicePtr devices [64 ];
188+ int nDevices = ffdrmGetDevices (devices , ARRAY_SIZE (devices ));
189+
190+ for (int iDev = 0 ; iDev < nDevices ; ++ iDev )
191+ {
192+ drmDevice * dev = devices [iDev ];
193+
194+ if (!(dev -> available_nodes & (1 << DRM_NODE_PRIMARY )))
195+ continue ;
196+
197+ const char * path = dev -> nodes [DRM_NODE_PRIMARY ];
198+
199+ FFGPUResult * gpu = (FFGPUResult * )ffListAdd (gpus );
200+ ffStrbufInit (& gpu -> vendor );
201+ ffStrbufInit (& gpu -> name );
202+ ffStrbufInit (& gpu -> driver );
203+ ffStrbufInitS (& gpu -> platformApi , path );
204+ ffStrbufInit (& gpu -> memoryType );
205+ gpu -> index = FF_GPU_INDEX_UNSET ;
206+ gpu -> temperature = FF_GPU_TEMP_UNSET ;
207+ gpu -> coreCount = FF_GPU_CORE_COUNT_UNSET ;
208+ gpu -> coreUsage = FF_GPU_CORE_USAGE_UNSET ;
209+ gpu -> type = FF_GPU_TYPE_UNKNOWN ;
210+ gpu -> dedicated .total = gpu -> dedicated .used = gpu -> shared .total = gpu -> shared .used = FF_GPU_VMEM_SIZE_UNSET ;
211+ gpu -> deviceId = 0 ;
212+ gpu -> frequency = FF_GPU_FREQUENCY_UNSET ;
213+
214+ switch (dev -> bustype )
215+ {
216+ case DRM_BUS_PCI :
217+ ffStrbufInitStatic (& gpu -> vendor , ffGPUGetVendorString (dev -> deviceinfo .pci -> vendor_id ));
218+ gpu -> deviceId = (dev -> businfo .pci -> domain * 100000ull ) + (dev -> businfo .pci -> bus * 1000ull ) + (dev -> businfo .pci -> dev * 10ull ) + dev -> businfo .pci -> func ;
219+ break ;
220+ case DRM_BUS_HOST1X :
221+ ffStrbufSetS (& gpu -> name , dev -> deviceinfo .host1x -> compatible [0 ]);
222+ gpu -> type = FF_GPU_TYPE_INTEGRATED ;
223+ break ;
224+ case DRM_BUS_PLATFORM :
225+ ffStrbufSetS (& gpu -> name , dev -> deviceinfo .platform -> compatible [0 ]);
226+ gpu -> type = FF_GPU_TYPE_INTEGRATED ;
227+ break ;
228+ case DRM_BUS_USB :
229+ ffStrbufSetF (& gpu -> name , "USB Device (%u-%u)" , dev -> deviceinfo .usb -> vendor , dev -> deviceinfo .usb -> product );
230+ gpu -> type = FF_GPU_TYPE_DISCRETE ;
231+ break ;
232+ }
233+
234+ FF_AUTO_CLOSE_FD int fd = open (path , O_RDONLY );
235+ if (fd < 0 ) continue ;
236+
237+ char driverName [64 ];
238+ char driverDesc [64 ];
239+ struct drm_version ver = {
240+ .name = driverName ,
241+ .name_len = ARRAY_SIZE (driverName ),
242+ .desc = driverDesc ,
243+ .desc_len = ARRAY_SIZE (driverDesc ),
244+ };
245+ if (ioctl (fd , DRM_IOCTL_VERSION , & ver ) == 0 )
246+ ffStrbufSetF (& gpu -> driver , "%*s %d.%d.%d" , (int ) ver .name_len , ver .name , ver .version_major , ver .version_minor , ver .version_patchlevel );
247+
248+ if (dev -> bustype != DRM_BUS_PCI )
249+ continue ;
250+
251+ if (ffStrEquals (ver .name , "i915" ))
252+ drmDetectIntelSpecific (gpu , fd );
253+ else if (ffStrEquals (ver .name , "amdgpu" ))
254+ drmDetectAmdSpecific (options , gpu , dev -> nodes [DRM_NODE_RENDER ]);
255+ else if (ffStrEquals (ver .name , "nvidia-drm" ) && (options -> temp || options -> driverSpecific ))
256+ {
257+ ffDetectNvidiaGpuInfo (& (FFGpuDriverCondition ) {
258+ .type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID ,
259+ .pciBusId = {
260+ .domain = (uint32_t ) dev -> businfo .pci -> domain ,
261+ .bus = dev -> businfo .pci -> bus ,
262+ .device = dev -> businfo .pci -> dev ,
263+ .func = dev -> businfo .pci -> func ,
264+ },
265+ }, (FFGpuDriverResult ) {
266+ .index = & gpu -> index ,
267+ .temp = options -> temp ? & gpu -> temperature : NULL ,
268+ .memory = options -> driverSpecific ? & gpu -> dedicated : NULL ,
269+ .coreCount = options -> driverSpecific ? (uint32_t * ) & gpu -> coreCount : NULL ,
270+ .type = & gpu -> type ,
271+ .frequency = & gpu -> frequency ,
272+ .coreUsage = & gpu -> coreUsage ,
273+ .name = & gpu -> name ,
274+ }, "libnvidia-ml.so" );
275+ }
276+
277+ if (gpu -> name .length == 0 )
278+ {
279+ if (gpu -> vendor .chars == FF_GPU_VENDOR_NAME_AMD )
280+ ffGPUQueryAmdGpuName (dev -> deviceinfo .pci -> device_id , dev -> deviceinfo .pci -> revision_id , gpu );
281+ if (gpu -> name .length == 0 )
282+ ffGPUFillVendorAndName (0 , dev -> deviceinfo .pci -> vendor_id , dev -> deviceinfo .pci -> device_id , gpu );
283+ }
284+
285+ fillGPUTypeGeneric (gpu );
286+ }
287+
288+ return NULL ;
289+ }
290+ #endif
291+
292+ static const char * detectByPci (const FFGPUOptions * options , FFlist * gpus )
14293{
15294 FF_AUTO_CLOSE_FD int fd = open ("/dev/pci" , O_RDONLY , 0 );
16295 if (fd < 0 )
@@ -57,23 +336,23 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
57336 if (gpu -> vendor .chars == FF_GPU_VENDOR_NAME_NVIDIA && (options -> temp || options -> driverSpecific ))
58337 {
59338 ffDetectNvidiaGpuInfo (& (FFGpuDriverCondition ) {
60- .type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID ,
61- .pciBusId = {
62- .domain = (uint32_t ) pc -> pc_sel .pc_domain ,
63- .bus = pc -> pc_sel .pc_bus ,
64- .device = pc -> pc_sel .pc_dev ,
65- .func = pc -> pc_sel .pc_func ,
66- },
67- }, (FFGpuDriverResult ) {
68- .index = & gpu -> index ,
69- .temp = options -> temp ? & gpu -> temperature : NULL ,
70- .memory = options -> driverSpecific ? & gpu -> dedicated : NULL ,
71- .coreCount = options -> driverSpecific ? (uint32_t * ) & gpu -> coreCount : NULL ,
72- .type = & gpu -> type ,
73- .frequency = & gpu -> frequency ,
74- .coreUsage = & gpu -> coreUsage ,
75- .name = & gpu -> name ,
76- }, "libnvidia-ml.so" );
339+ .type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID ,
340+ .pciBusId = {
341+ .domain = (uint32_t ) pc -> pc_sel .pc_domain ,
342+ .bus = pc -> pc_sel .pc_bus ,
343+ .device = pc -> pc_sel .pc_dev ,
344+ .func = pc -> pc_sel .pc_func ,
345+ },
346+ }, (FFGpuDriverResult ) {
347+ .index = & gpu -> index ,
348+ .temp = options -> temp ? & gpu -> temperature : NULL ,
349+ .memory = options -> driverSpecific ? & gpu -> dedicated : NULL ,
350+ .coreCount = options -> driverSpecific ? (uint32_t * ) & gpu -> coreCount : NULL ,
351+ .type = & gpu -> type ,
352+ .frequency = & gpu -> frequency ,
353+ .coreUsage = & gpu -> coreUsage ,
354+ .name = & gpu -> name ,
355+ }, "libnvidia-ml.so" );
77356 }
78357
79358 if (gpu -> name .length == 0 )
@@ -84,27 +363,19 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
84363 ffGPUFillVendorAndName (pc -> pc_subclass , pc -> pc_vendor , pc -> pc_device , gpu );
85364 }
86365
87- if (gpu -> type == FF_GPU_TYPE_UNKNOWN )
88- {
89- if (gpu -> vendor .chars == FF_GPU_VENDOR_NAME_NVIDIA )
90- {
91- if (ffStrbufStartsWithIgnCaseS (& gpu -> name , "GeForce" ) ||
92- ffStrbufStartsWithIgnCaseS (& gpu -> name , "Quadro" ) ||
93- ffStrbufStartsWithIgnCaseS (& gpu -> name , "Tesla" ))
94- gpu -> type = FF_GPU_TYPE_DISCRETE ;
95- }
96- else if (gpu -> vendor .chars == FF_GPU_VENDOR_NAME_MTHREADS )
97- {
98- if (ffStrbufStartsWithIgnCaseS (& gpu -> name , "MTT " ))
99- gpu -> type = FF_GPU_TYPE_DISCRETE ;
100- }
101- else if (gpu -> vendor .chars == FF_GPU_VENDOR_NAME_INTEL )
102- {
103- // 0000:00:02.0 is reserved for Intel integrated graphics
104- gpu -> type = gpu -> deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE ;
105- }
106- }
366+ fillGPUTypeGeneric (gpu );
107367 }
108368
109369 return NULL ;
110370}
371+
372+ const char * ffDetectGPUImpl (const FFGPUOptions * options , FFlist * gpus )
373+ {
374+ if (options -> detectionMethod == FF_GPU_DETECTION_METHOD_AUTO )
375+ {
376+ detectByDrm (options , gpus );
377+ if (gpus -> length > 0 ) return NULL ;
378+ }
379+
380+ return detectByPci (options , gpus );
381+ }
0 commit comments