From 4038ed265627e177909e72ab1a1fab0aacc39754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 12 Feb 2026 18:30:02 +0800 Subject: [PATCH] GPU: adds debug logs Thanks Github Copilot --- src/detection/gpu/gpu.c | 52 +++++++++++++++++++- src/detection/opengl/opengl_shared.c | 73 +++++++++++++++++++++++++++- src/detection/vulkan/vulkan.c | 71 +++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 3 deletions(-) diff --git a/src/detection/gpu/gpu.c b/src/detection/gpu/gpu.c index c66d780e6..b2130d56d 100644 --- a/src/detection/gpu/gpu.c +++ b/src/detection/gpu/gpu.c @@ -1,4 +1,5 @@ #include "gpu.h" +#include "common/debug.h" #include "detection/vulkan/vulkan.h" #include "detection/opencl/opencl.h" #include "detection/opengl/opengl.h" @@ -50,6 +51,8 @@ const char* ffGPUGetVendorString(unsigned vendorId) const char* detectByOpenGL(FFlist* gpus) { + FF_DEBUG("Starting OpenGL GPU detection fallback"); + FFOpenGLResult result; ffStrbufInit(&result.version); ffStrbufInit(&result.renderer); @@ -60,6 +63,7 @@ const char* detectByOpenGL(FFlist* gpus) __attribute__((__cleanup__(ffDestroyOpenGLOptions))) FFOpenGLOptions options; ffInitOpenGLOptions(&options); const char* error = ffDetectOpenGL(&options, &result); + FF_DEBUG("OpenGL detection returns: %s", error ?: "success"); if (!error) { @@ -78,6 +82,11 @@ const char* detectByOpenGL(FFlist* gpus) gpu->dedicated = gpu->shared = (FFGPUMemory){0, 0}; gpu->deviceId = 0; + FF_DEBUG("OpenGL reported renderer='%s', vendor='%s', version='%s'", + gpu->name.chars, + gpu->vendor.chars, + result.version.chars); + if (ffStrbufContainS(&gpu->name, "Apple")) { ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE); @@ -92,6 +101,11 @@ const char* detectByOpenGL(FFlist* gpus) else if (ffStrbufContainS(&gpu->name, "MTT")) ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_MTHREADS); + FF_DEBUG("OpenGL fallback produced GPU: name='%s', vendor='%s', type=%u", + gpu->name.chars, + gpu->vendor.chars, + gpu->type); + } ffStrbufDestroy(&result.version); @@ -104,43 +118,77 @@ const char* detectByOpenGL(FFlist* gpus) const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result) { + FF_DEBUG("Starting GPU detection with method=%d", (int) options->detectionMethod); + if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_PCI) { + FF_DEBUG("Trying PCI/native GPU detection"); const char* error = ffDetectGPUImpl(options, result); - if (!error && result->length > 0) return NULL; + if (!error && result->length > 0) + { + FF_DEBUG("PCI/native GPU detection succeeded with %u GPU(s)", result->length); + return NULL; + } + + FF_DEBUG("PCI/native GPU detection did not produce results (error=%s, gpuCount=%u)", + error ?: "none", + result->length); } if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_VULKAN) { + FF_DEBUG("Trying Vulkan GPU detection fallback"); FFVulkanResult* vulkan = ffDetectVulkan(); if (!vulkan->error && vulkan->gpus.length > 0) { + FF_DEBUG("Vulkan detection succeeded with %u GPU(s)", vulkan->gpus.length); ffListDestroy(result); ffListInitMove(result, &vulkan->gpus); #ifdef __ANDROID__ double ffGPUDetectTempFromTZ(void); if (options->temp && result->length == 1) + { + FF_DEBUG("Applying Android thermal-zone temperature to single Vulkan GPU"); FF_LIST_GET(FFGPUResult, *result, 0)->temperature = ffGPUDetectTempFromTZ(); + } #endif return NULL; } + + FF_DEBUG("Vulkan detection did not produce results (error=%s, gpuCount=%u)", + vulkan->error ?: "none", + vulkan->gpus.length); } if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_OPENCL) { + FF_DEBUG("Trying OpenCL GPU detection fallback"); FFOpenCLResult* opencl = ffDetectOpenCL(); if (!opencl->error && opencl->gpus.length > 0) { + FF_DEBUG("OpenCL detection succeeded with %u GPU(s)", opencl->gpus.length); ffListDestroy(result); ffListInitMove(result, &opencl->gpus); return NULL; } + + FF_DEBUG("OpenCL detection did not produce results (error=%s, gpuCount=%u)", + opencl->error ?: "none", + opencl->gpus.length); } if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_OPENGL) { - if (detectByOpenGL(result) == NULL) + FF_DEBUG("Trying OpenGL GPU detection fallback"); + const char* error = detectByOpenGL(result); + if (error == NULL) + { + FF_DEBUG("OpenGL fallback succeeded with %u GPU(s)", result->length); return NULL; + } + + FF_DEBUG("OpenGL fallback failed: %s", error); } + FF_DEBUG("GPU detection failed in all enabled backends"); return "GPU detection failed"; } diff --git a/src/detection/opengl/opengl_shared.c b/src/detection/opengl/opengl_shared.c index db72fb80d..fa70abf74 100644 --- a/src/detection/opengl/opengl_shared.c +++ b/src/detection/opengl/opengl_shared.c @@ -1,4 +1,5 @@ #include "opengl.h" +#include "common/debug.h" #include "common/library.h" #if __has_include() @@ -56,26 +57,48 @@ typedef struct EGLData static const char* eglHandleContext(FFOpenGLResult* result, EGLData* data) { + FF_DEBUG("Making EGL context current"); if(data->ffeglMakeCurrent(data->display, data->surface, data->surface, data->context) != EGL_TRUE) + { + FF_DEBUG("eglMakeCurrent() returned EGL_FALSE"); return "eglMakeCurrent returned EGL_FALSE"; + } ffOpenGLHandleResult(result, data->ffglGetString); ffStrbufSetF(&result->library, "EGL %s", data->ffeglQueryString(data->display, EGL_VERSION)); + FF_DEBUG("OpenGL via EGL detected: version='%s', renderer='%s', vendor='%s', slv='%s', library='%s'", + result->version.chars, + result->renderer.chars, + result->vendor.chars, + result->slv.chars, + result->library.chars); return NULL; } static const char* eglHandleSurface(FFOpenGLResult* result, EGLData* data, bool gles) { + FF_DEBUG("Creating EGL context (preferred API=%s, client version=%d)", gles ? "OpenGL ES" : "OpenGL", gles ? 2 : 1); data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){ EGL_CONTEXT_CLIENT_VERSION, gles ? 2 : 1, // Try GLES 2.0+ first EGL_NONE }); if(data->context == EGL_NO_CONTEXT && gles) // Some ANGLE builds support GLES 1.1 only + { + FF_DEBUG("EGL context creation with GLES 2.x failed, retrying with default attributes (GLES 1.1 fallback)"); data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){EGL_NONE}); + } if(data->context == EGL_NO_CONTEXT) + { + FF_DEBUG("eglCreateContext() returned EGL_NO_CONTEXT"); return "eglCreateContext returned EGL_NO_CONTEXT"; + } + + FF_DEBUG("EGL context created successfully"); const char* error = eglHandleContext(result, data); + FF_DEBUG("eglHandleContext() returns: %s", error ?: "success"); + + FF_DEBUG("Destroying EGL context"); data->ffeglDestroyContext(data->display, data->context); return error; } @@ -84,13 +107,21 @@ static const char* eglHandleDisplay(FFOpenGLResult* result, EGLData* data) { // try use OpenGL API. If failed, use the default API (usually OpenGL ES) bool gles = !data->ffeglBindAPI(EGL_OPENGL_API); + FF_DEBUG("eglBindAPI(EGL_OPENGL_API) %s, effective API=%s", + gles ? "failed" : "succeeded", + gles ? "default (usually OpenGL ES)" : "OpenGL"); EGLint eglConfigCount; data->ffeglGetConfigs(data->display, &data->config, 1, &eglConfigCount); + FF_DEBUG("eglGetConfigs() returned %d config(s)", eglConfigCount); if(eglConfigCount == 0) + { + FF_DEBUG("No EGL config is available"); return "eglGetConfigs returned 0 configs"; + } + FF_DEBUG("Creating EGL pbuffer surface (%dx%d)", FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT); data->surface = data->ffeglCreatePbufferSurface(data->display, data->config, (EGLint[]){ EGL_WIDTH, FF_OPENGL_BUFFER_WIDTH, EGL_HEIGHT, FF_OPENGL_BUFFER_HEIGHT, @@ -98,39 +129,71 @@ static const char* eglHandleDisplay(FFOpenGLResult* result, EGLData* data) }); if(data->surface == EGL_NO_SURFACE) + { + FF_DEBUG("eglCreatePbufferSurface() returned EGL_NO_SURFACE"); return "eglCreatePbufferSurface returned EGL_NO_SURFACE"; + } + + FF_DEBUG("EGL pbuffer surface created successfully"); const char* error = eglHandleSurface(result, data, gles); + FF_DEBUG("eglHandleSurface() returns: %s", error ?: "success"); + + FF_DEBUG("Destroying EGL surface"); data->ffeglDestroySurface(data->display, data->surface); return error; } static const char* eglHandleData(FFOpenGLResult* result, EGLData* data) { + FF_DEBUG("Resolving glGetString via eglGetProcAddress()"); data->ffglGetString = (__typeof__(&glGetString)) data->ffeglGetProcAddress("glGetString"); if(!data->ffglGetString) + { + FF_DEBUG("eglGetProcAddress('glGetString') returned NULL"); return "eglGetProcAddress(glGetString) returned NULL"; + } #if EGL_VERSION_1_5 PFNEGLGETPLATFORMDISPLAYEXTPROC ffeglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC) data->ffeglGetProcAddress("eglGetPlatformDisplay"); if (ffeglGetPlatformDisplay) + { + FF_DEBUG("Trying eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA)"); data->display = ffeglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA, NULL, NULL); + FF_DEBUG("eglGetPlatformDisplay() %s", data->display == EGL_NO_DISPLAY ? "failed" : "succeeded"); + } + else + FF_DEBUG("eglGetPlatformDisplay is unavailable, falling back to eglGetDisplay"); if(!ffeglGetPlatformDisplay || data->display == EGL_NO_DISPLAY) #endif { + FF_DEBUG("Trying eglGetDisplay(EGL_DEFAULT_DISPLAY)"); data->display = data->ffeglGetDisplay(EGL_DEFAULT_DISPLAY); if(data->display == EGL_NO_DISPLAY) + { + FF_DEBUG("eglGetDisplay() returned EGL_NO_DISPLAY"); return "eglGetDisplay returned EGL_NO_DISPLAY"; + } + + FF_DEBUG("eglGetDisplay() succeeded"); } EGLint major, minor; if(data->ffeglInitialize(data->display, &major, &minor) == EGL_FALSE) + { + FF_DEBUG("eglInitialize() returned EGL_FALSE"); return "eglInitialize returned EGL_FALSE"; + } + + FF_DEBUG("EGL initialized successfully: %d.%d", major, minor); const char* error = eglHandleDisplay(result, data); + FF_DEBUG("eglHandleDisplay() returns: %s", error ?: "success"); + + FF_DEBUG("Terminating EGL display connection"); data->ffeglTerminate(data->display); return error; } @@ -138,6 +201,7 @@ static const char* eglHandleData(FFOpenGLResult* result, EGLData* data) const char* ffOpenGLDetectByEGL(FFOpenGLResult* result) { + FF_DEBUG("Starting OpenGL detection via EGL"); EGLData eglData; FF_LIBRARY_LOAD_MESSAGE(egl, "libEGL" FF_LIBRARY_EXTENSION, 1); @@ -154,8 +218,15 @@ const char* ffOpenGLDetectByEGL(FFOpenGLResult* result) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglDestroySurface); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglTerminate); + FF_DEBUG("Loaded EGL library and required symbols"); + FF_SUPPRESS_IO(); - return eglHandleData(result, &eglData); + FF_DEBUG("Suppressed stdout/stderr during EGL probing"); + + const char* error = eglHandleData(result, &eglData); + FF_DEBUG("OpenGL detection via EGL returns: %s", error ?: "success"); + + return error; } #endif //FF_HAVE_EGL diff --git a/src/detection/vulkan/vulkan.c b/src/detection/vulkan/vulkan.c index 085c7cb64..4dc2b775f 100644 --- a/src/detection/vulkan/vulkan.c +++ b/src/detection/vulkan/vulkan.c @@ -1,4 +1,5 @@ #include "fastfetch.h" +#include "common/debug.h" #include "detection/gpu/gpu.h" #include "detection/vulkan/vulkan.h" @@ -39,6 +40,8 @@ static void applyDriverName(VkPhysicalDeviceDriverPropertiesKHR* properties, FFs static const char* detectVulkan(FFVulkanResult* result) { + FF_DEBUG("Starting Vulkan detection"); + FF_LIBRARY_LOAD_MESSAGE(vulkan, #if __APPLE__ "libMoltenVK" FF_LIBRARY_EXTENSION, -1 @@ -56,6 +59,7 @@ static const char* detectVulkan(FFVulkanResult* result) //Some drivers (nvdc) print messages to stdout //and that is the best way I found to disable that FF_SUPPRESS_IO(); + FF_DEBUG("Suppressed stdout/stderr during Vulkan probing to avoid noisy drivers"); FFVersion instanceVersion = FF_VERSION_INIT; @@ -66,8 +70,15 @@ static const char* detectVulkan(FFVulkanResult* result) { uint32_t version; if(ffvkEnumerateInstanceVersion(&version) == VK_SUCCESS) + { applyVulkanVersion(version, &instanceVersion); + FF_DEBUG("Detected Vulkan instance version: %u.%u.%u", instanceVersion.major, instanceVersion.minor, instanceVersion.patch); + } + else + FF_DEBUG("vkEnumerateInstanceVersion() is available but returned a non-success status"); } + else + FF_DEBUG("vkEnumerateInstanceVersion() is unavailable (likely Vulkan 1.0 runtime)"); const uint32_t projectVersion = VK_MAKE_VERSION( FASTFETCH_PROJECT_VERSION_MAJOR, @@ -76,6 +87,7 @@ static const char* detectVulkan(FFVulkanResult* result) ); VkInstance vkInstance; + FF_DEBUG("Creating Vulkan instance with requested API version %s", instanceVersion.minor >= 1 ? "1.1" : "1.0"); VkResult res = ffvkCreateInstance(&(VkInstanceCreateInfo) { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = NULL, @@ -98,6 +110,7 @@ static const char* detectVulkan(FFVulkanResult* result) }, NULL, &vkInstance); if(res != VK_SUCCESS) { + FF_DEBUG("ffvkCreateInstance() failed with VkResult=%d", res); switch (res) { case VK_ERROR_OUT_OF_HOST_MEMORY: @@ -116,17 +129,22 @@ static const char* detectVulkan(FFVulkanResult* result) return "ffvkCreateInstance() failed: unknown error"; } } + FF_DEBUG("Vulkan instance created successfully"); //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; + FF_DEBUG("Falling back to Vulkan instance version 1.0 due to unavailable enumerate call"); + } VkPhysicalDevice physicalDevices[128]; uint32_t physicalDeviceCount = (uint32_t) ARRAY_SIZE(physicalDevices); res = ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, physicalDevices); if(res != VK_SUCCESS) { + FF_DEBUG("ffvkEnumeratePhysicalDevices() failed with VkResult=%d", res); ffvkDestroyInstance(vkInstance, NULL); switch (res) { @@ -142,13 +160,22 @@ static const char* detectVulkan(FFVulkanResult* result) return "ffvkEnumeratePhysicalDevices() failed"; } } + FF_DEBUG("Enumerated %u Vulkan physical device(s)", physicalDeviceCount); PFN_vkGetPhysicalDeviceProperties ffvkGetPhysicalDeviceProperties = NULL; PFN_vkGetPhysicalDeviceProperties2 ffvkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties2"); // 1.1 if(!ffvkGetPhysicalDeviceProperties2) ffvkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties"); + FF_DEBUG("Using %s for querying physical device properties", ffvkGetPhysicalDeviceProperties2 ? "vkGetPhysicalDeviceProperties2" : "vkGetPhysicalDeviceProperties"); + PFN_vkGetPhysicalDeviceMemoryProperties ffvkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceMemoryProperties"); + if(!ffvkGetPhysicalDeviceMemoryProperties) + { + FF_DEBUG("vkGetPhysicalDeviceMemoryProperties is unavailable"); + ffvkDestroyInstance(vkInstance, NULL); + return "vkGetPhysicalDeviceMemoryProperties is not available"; + } FFVersion maxDeviceApiVersion = FF_VERSION_INIT; FFVersion maxDeviceConformanceVersion = FF_VERSION_INIT; @@ -172,10 +199,19 @@ static const char* detectVulkan(FFVulkanResult* result) else ffvkGetPhysicalDeviceProperties(physicalDevices[i], &physicalDeviceProperties.properties); + FF_DEBUG("Processing Vulkan device #%u: name='%s', vendorId=0x%04X, deviceId=0x%04X, type=%u", i, + physicalDeviceProperties.properties.deviceName, + physicalDeviceProperties.properties.vendorID, + physicalDeviceProperties.properties.deviceID, + physicalDeviceProperties.properties.deviceType); + //We don't want software rasterizers to show up as physical gpu if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) + { + FF_DEBUG("Skipping CPU Vulkan device '%s'", physicalDeviceProperties.properties.deviceName); continue; + } //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 @@ -186,6 +222,11 @@ static const char* detectVulkan(FFVulkanResult* result) { maxDeviceApiVersion = deviceAPIVersion; applyDriverName(&driverProperties, &result->driver); + FF_DEBUG("Updated max Vulkan device API version to %u.%u.%u (driver='%s')", + maxDeviceApiVersion.major, + maxDeviceApiVersion.minor, + maxDeviceApiVersion.patch, + result->driver.chars); } //If the device conformance version is higher than the current highest device conformance version, overwrite it @@ -198,7 +239,13 @@ static const char* detectVulkan(FFVulkanResult* result) }; if(ffVersionCompare(&deviceConformanceVersion, &maxDeviceConformanceVersion) > 0) + { maxDeviceConformanceVersion = deviceConformanceVersion; + FF_DEBUG("Updated max Vulkan conformance version to %u.%u.%u", + maxDeviceConformanceVersion.major, + maxDeviceConformanceVersion.minor, + maxDeviceConformanceVersion.patch); + } } //Add the device to the list of devices shown by the GPU module @@ -207,7 +254,10 @@ static const char* detectVulkan(FFVulkanResult* result) FF_LIST_FOR_EACH(FFGPUResult, gpu, result->gpus) { if (gpu->deviceId == physicalDeviceProperties.properties.deviceID) + { + FF_DEBUG("Skipping duplicate Vulkan GPU entry for deviceId=0x%04X", physicalDeviceProperties.properties.deviceID); goto next; + } } FFGPUResult* gpu = ffListAdd(&result->gpus); @@ -221,6 +271,10 @@ static const char* detectVulkan(FFVulkanResult* result) ffStrbufInitS(&gpu->vendor, ffGPUGetVendorString(physicalDeviceProperties.properties.vendorID)); ffStrbufInitS(&gpu->driver, driverProperties.driverInfo); ffStrbufInit(&gpu->memoryType); + FF_DEBUG("Added Vulkan GPU '%s' (vendor='%s', type=%s)", + gpu->name.chars, + gpu->vendor.chars, + gpu->type == FF_GPU_TYPE_DISCRETE ? "discrete" : "integrated"); VkPhysicalDeviceMemoryProperties memoryProperties = {}; ffvkGetPhysicalDeviceMemoryProperties(physicalDevices[i], &memoryProperties); @@ -233,6 +287,10 @@ static const char* detectVulkan(FFVulkanResult* result) FFGPUMemory* vmem = gpu->type == FF_GPU_TYPE_DISCRETE && (heap->flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) ? &gpu->dedicated : &gpu->shared; vmem->total += heap->size; } + FF_DEBUG("Computed memory for '%s': dedicatedTotal=%llu, sharedTotal=%llu", + gpu->name.chars, + (unsigned long long) gpu->dedicated.total, + (unsigned long long) gpu->shared.total); //No way to detect those using vulkan gpu->index = FF_GPU_INDEX_UNSET; @@ -249,7 +307,14 @@ static const char* detectVulkan(FFVulkanResult* result) ffVersionToPretty(&maxDeviceApiVersion, &result->apiVersion); ffVersionToPretty(&maxDeviceConformanceVersion, &result->conformanceVersion); + FF_DEBUG("Vulkan detection finished: instanceVersion=%s, apiVersion=%s, conformanceVersion=%s, gpuCount=%u", + result->instanceVersion.chars, + result->apiVersion.chars, + result->conformanceVersion.chars, + result->gpus.length); + ffvkDestroyInstance(vkInstance, NULL); + FF_DEBUG("Destroyed Vulkan instance"); return NULL; } @@ -261,6 +326,7 @@ FFVulkanResult* ffDetectVulkan(void) if (result.gpus.elementSize == 0) { + FF_DEBUG("Initializing Vulkan detection cache"); ffStrbufInit(&result.driver); ffStrbufInit(&result.apiVersion); ffStrbufInit(&result.conformanceVersion); @@ -269,10 +335,15 @@ FFVulkanResult* ffDetectVulkan(void) #ifdef FF_HAVE_VULKAN result.error = detectVulkan(&result); + if (result.error) + FF_DEBUG("Vulkan detection returned error: %s", result.error); #else result.error = "fastfetch was compiled without vulkan support"; + FF_DEBUG("Vulkan support is disabled at compile time"); #endif } + else + FF_DEBUG("Reusing cached Vulkan detection result"); return &result; }