diff options
| author | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
|---|---|---|
| committer | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
| commit | 76424950e373d3b04ac3dd13019151bfba3e8423 (patch) | |
| tree | 4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/opengl | |
Add the files
Diffstat (limited to 'src/detection/opengl')
| -rw-r--r-- | src/detection/opengl/opengl.h | 17 | ||||
| -rw-r--r-- | src/detection/opengl/opengl_apple.c | 66 | ||||
| -rw-r--r-- | src/detection/opengl/opengl_haiku.cpp | 38 | ||||
| -rw-r--r-- | src/detection/opengl/opengl_linux.c | 200 | ||||
| -rw-r--r-- | src/detection/opengl/opengl_shared.c | 214 | ||||
| -rw-r--r-- | src/detection/opengl/opengl_windows.c | 120 |
6 files changed, 655 insertions, 0 deletions
diff --git a/src/detection/opengl/opengl.h b/src/detection/opengl/opengl.h new file mode 100644 index 0000000..f7ff9d5 --- /dev/null +++ b/src/detection/opengl/opengl.h @@ -0,0 +1,17 @@ +#pragma once + +#include "fastfetch.h" +#include "modules/opengl/option.h" + +typedef struct FFOpenGLResult { + FFstrbuf version; + FFstrbuf renderer; + FFstrbuf vendor; + FFstrbuf slv; + FFstrbuf library; +} FFOpenGLResult; + +#define FF_OPENGL_BUFFER_WIDTH 1 +#define FF_OPENGL_BUFFER_HEIGHT 1 + +const char* ffDetectOpenGL(FFOpenGLOptions* options, FFOpenGLResult* result); diff --git a/src/detection/opengl/opengl_apple.c b/src/detection/opengl/opengl_apple.c new file mode 100644 index 0000000..9128593 --- /dev/null +++ b/src/detection/opengl/opengl_apple.c @@ -0,0 +1,66 @@ + +#include "fastfetch.h" +#include "opengl.h" + +#define GL_SILENCE_DEPRECATION +#include <OpenGL/gl.h> +#include <OpenGL/OpenGL.h> // This brings in CGL, not GL + +void ffOpenGLHandleResult(FFOpenGLResult* result, __typeof__(&glGetString) ffglGetString); + +static const char* cglHandleContext(FFOpenGLResult* result, CGLContextObj context) { + if (CGLSetCurrentContext(context) != kCGLNoError) { + return "CGLSetCurrentContext() failed"; + } + + ffOpenGLHandleResult(result, &glGetString); + + GLint major, minor; + CGLGetVersion(&major, &minor); + ffStrbufSetF(&result->library, "CGL %d.%d", major, minor); + + return NULL; +} + +static const char* cglHandlePixelFormat(FFOpenGLResult* result, CGLPixelFormatObj pixelFormat) { + CGLContextObj context; + + if (CGLCreateContext(pixelFormat, NULL, &context) != kCGLNoError) { + return "CGLCreateContext() failed"; + } + + const char* error = cglHandleContext(result, context); + CGLDestroyContext(context); + return error; +} + +const char* cglDetectOpenGL(FFOpenGLResult* result) { + CGLPixelFormatObj pixelFormat; + CGLPixelFormatAttribute attrs[] = { + kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, kCGLPFAAccelerated, 0 + }; + + GLint num; + if (CGLChoosePixelFormat(attrs, &pixelFormat, &num) != kCGLNoError) { + return "CGLChoosePixelFormat() failed"; + } + + const char* error = cglHandlePixelFormat(result, pixelFormat); + CGLDestroyPixelFormat(pixelFormat); + return error; +} + +const char* ffDetectOpenGL(FFOpenGLOptions* options, FFOpenGLResult* result) { + if (options->library == FF_OPENGL_LIBRARY_AUTO) { + return cglDetectOpenGL(result); + } else if (options->library == FF_OPENGL_LIBRARY_EGL) { +#if __has_include(<EGL/egl.h>) + const char* ffOpenGLDetectByEGL(FFOpenGLResult * result); + return ffOpenGLDetectByEGL(result); +#else + return "fastfetch was compiled without egl support"; +#endif + } else { + return "Unsupported OpenGL library"; + } +} diff --git a/src/detection/opengl/opengl_haiku.cpp b/src/detection/opengl/opengl_haiku.cpp new file mode 100644 index 0000000..64a21a0 --- /dev/null +++ b/src/detection/opengl/opengl_haiku.cpp @@ -0,0 +1,38 @@ +#include <OpenGLKit.h> + +extern "C" { +#include "opengl.h" +#include "common/io.h" +#if FF_HAVE_EGL +const char* ffOpenGLDetectByEGL(FFOpenGLResult* result); +#endif +void ffOpenGLHandleResult(FFOpenGLResult* result, __typeof__(&glGetString) ffglGetString); +} + +static const char* oglDetectOpenGL(FFOpenGLResult* result) { + BApplication app("application/x-vnd.fastfetch-cli-fastfetch"); + FF_SUPPRESS_IO(); + + BGLView glView(BRect(), "ff_ogl_view", B_FOLLOW_NONE, B_WILL_DRAW, BGL_RGB); + auto ffglGetString = (decltype(&glGetString)) glView.GetGLProcAddress("glGetString"); + if (!ffglGetString) { + return "glView.GetGLProcAddress() failed"; + } + ffOpenGLHandleResult(result, ffglGetString); + ffStrbufSetStatic(&result->library, "OpenGLKit"); + return NULL; +} + +const char* ffDetectOpenGL(FFOpenGLOptions* options, FFOpenGLResult* result) { + if (options->library == FF_OPENGL_LIBRARY_AUTO) { + return oglDetectOpenGL(result); + } else if (options->library == FF_OPENGL_LIBRARY_EGL) { +#if FF_HAVE_EGL + return ffOpenGLDetectByEGL(result); +#else + return "fastfetch was compiled without egl support"; +#endif + } else { + return "Unsupported OpenGL library"; + } +} diff --git a/src/detection/opengl/opengl_linux.c b/src/detection/opengl/opengl_linux.c new file mode 100644 index 0000000..5f88b7e --- /dev/null +++ b/src/detection/opengl/opengl_linux.c @@ -0,0 +1,200 @@ +#include "fastfetch.h" +#include "opengl.h" +#include "common/io.h" + +#include <string.h> + +#if __ANDROID__ && !defined(FF_HAVE_EGL) + // On Android, installing OpenGL headers is enough (mesa-dev) + #if __has_include(<EGL/egl.h>) + #define FF_HAVE_EGL 1 + #endif +#endif + +#if defined(FF_HAVE_EGL) || defined(FF_HAVE_GLX) + #define FF_HAVE_GL 1 + + #include "common/library.h" + + #include <GL/gl.h> + +void ffOpenGLHandleResult(FFOpenGLResult* result, __typeof__(&glGetString) ffglGetString); + +#endif // FF_HAVE_GL + +#ifdef FF_HAVE_GLX + #include <GL/glx.h> + +typedef struct GLXData { + FF_LIBRARY_SYMBOL(glGetString) + FF_LIBRARY_SYMBOL(glXGetProcAddress) + FF_LIBRARY_SYMBOL(glXQueryVersion) + FF_LIBRARY_SYMBOL(XOpenDisplay) + FF_LIBRARY_SYMBOL(glXChooseVisual) + FF_LIBRARY_SYMBOL(XCreatePixmap) + FF_LIBRARY_SYMBOL(glXCreateGLXPixmap) + FF_LIBRARY_SYMBOL(glXCreateContext) + FF_LIBRARY_SYMBOL(glXMakeCurrent) + FF_LIBRARY_SYMBOL(glXDestroyContext) + FF_LIBRARY_SYMBOL(glXDestroyGLXPixmap) + FF_LIBRARY_SYMBOL(XFreePixmap) + FF_LIBRARY_SYMBOL(XCloseDisplay) + FF_LIBRARY_SYMBOL(XFree) + + Display* display; + XVisualInfo* visualInfo; + Pixmap pixmap; + GLXPixmap glxPixmap; + GLXContext context; +} GLXData; + +static const char* glxHandleContext(FFOpenGLResult* result, GLXData* data) { + if (data->ffglXMakeCurrent(data->display, data->glxPixmap, data->context) != True) { + return "glXMakeCurrent returned False"; + } + ffOpenGLHandleResult(result, data->ffglGetString); + + int major, minor; + if (data->ffglXQueryVersion(data->display, &major, &minor)) { + ffStrbufSetF(&result->library, "GLX %d.%d", major, minor); + } else { + ffStrbufSetStatic(&result->library, "GLX"); + } + + return NULL; +} + +static const char* glxHandleGLXPixmap(FFOpenGLResult* result, GLXData* data) { + data->context = data->ffglXCreateContext(data->display, data->visualInfo, NULL, True); + if (data->context == NULL) { + return "glXCreateContext returned NULL"; + } + + const char* error = glxHandleContext(result, data); + data->ffglXDestroyContext(data->display, data->context); + return error; +} + +static const char* glxHandlePixmap(FFOpenGLResult* result, GLXData* data) { + data->glxPixmap = data->ffglXCreateGLXPixmap(data->display, data->visualInfo, data->pixmap); + if (data->glxPixmap == None) { + return "glXCreateGLXPixmap returned None"; + } + + const char* error = glxHandleGLXPixmap(result, data); + data->ffglXDestroyGLXPixmap(data->display, data->glxPixmap); + return error; +} + +static const char* glxHandleVisualInfo(FFOpenGLResult* result, GLXData* data) { + data->pixmap = data->ffXCreatePixmap(data->display, DefaultRootWindow(data->display), FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT, (unsigned int) data->visualInfo->depth); + if (data->pixmap == None) { + return "XCreatePixmap returned None"; + } + + const char* error = glxHandlePixmap(result, data); + data->ffXFreePixmap(data->display, data->pixmap); + return error; +} + +static const char* glxHandleDisplay(FFOpenGLResult* result, GLXData* data) { + data->visualInfo = data->ffglXChooseVisual(data->display, DefaultScreen(data->display), (int[]) { None }); + if (data->visualInfo == NULL) { + return "glXChooseVisual returned NULL"; + } + + const char* error = glxHandleVisualInfo(result, data); + data->ffXFree(data->visualInfo); + return error; +} + +static const char* glxHandleData(FFOpenGLResult* result, GLXData* data) { + data->ffglGetString = (__typeof__(data->ffglGetString)) data->ffglXGetProcAddress((const GLubyte*) "glGetString"); + if (data->ffglGetString == NULL) { + return "glXGetProcAddress(glGetString) returned NULL"; + } + + data->display = data->ffXOpenDisplay(NULL); + if (data->display == NULL) { + return "XOpenDisplay returned NULL"; + } + + const char* error = glxHandleDisplay(result, data); + data->ffXCloseDisplay(data->display); + return error; +} + +static const char* detectByGlx(FFOpenGLResult* result) { + GLXData data; + + FF_LIBRARY_LOAD_MESSAGE(glx, + #if !__OpenBSD__ && !__NetBSD__ + "libGLX" + #else + "libGL" + #endif + FF_LIBRARY_EXTENSION, + 1); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, glXGetProcAddress); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, glXQueryVersion); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, XOpenDisplay); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, glXChooseVisual); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, XCreatePixmap); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, glXCreateGLXPixmap); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, glXCreateContext); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, glXMakeCurrent); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, glXDestroyContext); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, glXDestroyGLXPixmap); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, XFreePixmap); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, XCloseDisplay); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, XFree); + + FF_SUPPRESS_IO(); + + return glxHandleData(result, &data); +} + +#endif // FF_HAVE_GLX + +const char* ffDetectOpenGL(FFOpenGLOptions* options, FFOpenGLResult* result) { +#if FF_HAVE_GL + + if (options->library == FF_OPENGL_LIBRARY_GLX) { + #ifdef FF_HAVE_GLX + return detectByGlx(result); + #else + return "fastfetch was compiled without glx support"; + #endif + } + + if (options->library == FF_OPENGL_LIBRARY_EGL) { + #ifdef FF_HAVE_EGL + const char* ffOpenGLDetectByEGL(FFOpenGLResult * result); + return ffOpenGLDetectByEGL(result); + #else + return "fastfetch was compiled without egl support"; + #endif + } + + const char* error = ""; // not NULL dummy value + + #ifdef FF_HAVE_EGL + const char* ffOpenGLDetectByEGL(FFOpenGLResult * result); + error = ffOpenGLDetectByEGL(result); + #endif + + #ifdef FF_HAVE_GLX + if (error != NULL) { + error = detectByGlx(result); + } + #endif + + return error; + +#else + + FF_UNUSED(options, result); + return "Fastfetch was built without gl support."; + +#endif // FF_HAVE_GL +} diff --git a/src/detection/opengl/opengl_shared.c b/src/detection/opengl/opengl_shared.c new file mode 100644 index 0000000..307e71d --- /dev/null +++ b/src/detection/opengl/opengl_shared.c @@ -0,0 +1,214 @@ +#include "opengl.h" +#include "common/debug.h" +#include "common/library.h" + +#if __has_include(<GL/gl.h>) + #include <GL/gl.h> +#elif __APPLE__ + #define GL_SILENCE_DEPRECATION 1 + #include <OpenGL/gl.h> +#else + #define FF_HAVE_NO_GL 1 +#endif + +#ifndef FF_HAVE_NO_GL + + #ifndef GL_SHADING_LANGUAGE_VERSION // For WGL + #define GL_SHADING_LANGUAGE_VERSION 0x8B8C + #endif + +void ffOpenGLHandleResult(FFOpenGLResult* result, __typeof__(&glGetString) ffglGetString) { + ffStrbufAppendS(&result->version, (const char*) ffglGetString(GL_VERSION)); + ffStrbufAppendS(&result->renderer, (const char*) ffglGetString(GL_RENDERER)); + ffStrbufAppendS(&result->vendor, (const char*) ffglGetString(GL_VENDOR)); + ffStrbufAppendS(&result->slv, (const char*) ffglGetString(GL_SHADING_LANGUAGE_VERSION)); +} + + #if defined(FF_HAVE_EGL) || __has_include(<EGL/egl.h>) + #include "common/io.h" + + #define EGL_EGL_PROTOTYPES 1 + #define EGL_EGLEXT_PROTOTYPES 1 + #include <EGL/egl.h> + #include <EGL/eglext.h> + +typedef struct EGLData { + FF_LIBRARY_SYMBOL(glGetString) + FF_LIBRARY_SYMBOL(eglGetProcAddress) + FF_LIBRARY_SYMBOL(eglGetDisplay) + FF_LIBRARY_SYMBOL(eglQueryString) + FF_LIBRARY_SYMBOL(eglInitialize) + FF_LIBRARY_SYMBOL(eglBindAPI) + FF_LIBRARY_SYMBOL(eglGetConfigs) + FF_LIBRARY_SYMBOL(eglCreatePbufferSurface) + FF_LIBRARY_SYMBOL(eglCreateContext) + FF_LIBRARY_SYMBOL(eglMakeCurrent) + FF_LIBRARY_SYMBOL(eglDestroyContext) + FF_LIBRARY_SYMBOL(eglDestroySurface) + FF_LIBRARY_SYMBOL(eglTerminate) + + EGLDisplay display; + EGLConfig config; + EGLSurface surface; + EGLContext context; +} 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("Releasing current EGL context"); + data->ffeglMakeCurrent(data->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + FF_DEBUG("Destroying EGL context"); + data->ffeglDestroyContext(data->display, data->context); + return error; +} + +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, EGL_NONE }); + + 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; +} + +const char* ffOpenGLDetectByEGL(FFOpenGLResult* result) { + FF_DEBUG("Starting OpenGL detection via EGL"); + EGLData eglData; + + FF_LIBRARY_LOAD_MESSAGE(egl, "libEGL" FF_LIBRARY_EXTENSION, 1); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglGetProcAddress); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglGetDisplay); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglQueryString); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglInitialize); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglBindAPI); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglGetConfigs); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglCreatePbufferSurface); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglCreateContext); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglMakeCurrent); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglDestroyContext); + 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(); + 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 + +#endif // FF_HAVE_NO_GL diff --git a/src/detection/opengl/opengl_windows.c b/src/detection/opengl/opengl_windows.c new file mode 100644 index 0000000..01bd986 --- /dev/null +++ b/src/detection/opengl/opengl_windows.c @@ -0,0 +1,120 @@ +#include "opengl.h" +#include "common/library.h" +#include "common/printing.h" +#include "common/windows/nt.h" + +#include <windows.h> +#include <GL/gl.h> + +typedef struct WGLData { + FF_LIBRARY_SYMBOL(glGetString) + FF_LIBRARY_SYMBOL(wglMakeCurrent) + FF_LIBRARY_SYMBOL(wglCreateContext) + FF_LIBRARY_SYMBOL(wglDeleteContext) +} WGLData; + +void ffOpenGLHandleResult(FFOpenGLResult* result, __typeof__(&glGetString) ffglGetString); + +static const char* wglHandleContext(WGLData* wglData, FFOpenGLResult* result, HDC hdc, HGLRC context) { + if (wglData->ffwglMakeCurrent(hdc, context) == FALSE) { + return "wglMakeCurrent() failed"; + } + ffOpenGLHandleResult(result, wglData->ffglGetString); + ffStrbufSetStatic(&result->library, "WGL 1.0"); + if (wglData->ffwglMakeCurrent(NULL, NULL) == FALSE) { + return "wglMakeCurrent(NULL, NULL) failed"; + } + return NULL; +} + +static const char* wglHandlePixelFormat(WGLData* wglData, FFOpenGLResult* result, HWND hWnd) { + HDC hdc = GetDC(hWnd); + + if (hdc == NULL) { + return "GetDC() failed"; + } + + PIXELFORMATDESCRIPTOR pfd = { + .nSize = sizeof(PIXELFORMATDESCRIPTOR), + .nVersion = 1, + .dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + .iPixelType = PFD_TYPE_RGBA, + .cColorBits = 32, + .cDepthBits = 24, + .iLayerType = PFD_MAIN_PLANE + }; + int pixelFormat = ChoosePixelFormat(hdc, &pfd); + if (pixelFormat == 0) { + ReleaseDC(hWnd, hdc); + return "ChoosePixelFormat() failed"; + } + + if (SetPixelFormat(hdc, pixelFormat, &pfd) == FALSE) { + ReleaseDC(hWnd, hdc); + return "SetPixelFormat() failed"; + } + + HGLRC context = wglData->ffwglCreateContext(hdc); + if (context == NULL) { + ReleaseDC(hWnd, hdc); + return "wglCreateContext() failed"; + } + + const char* error = wglHandleContext(wglData, result, hdc, context); + wglData->ffwglDeleteContext(context); + + ReleaseDC(hWnd, hdc); + + return error; +} + +static const char* wglDetectOpenGL(FFOpenGLResult* result) { + FF_LIBRARY_LOAD_MESSAGE(opengl32, "opengl32" FF_LIBRARY_EXTENSION, 1); + + WGLData data = {}; + + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, wglMakeCurrent); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, wglCreateContext); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, wglDeleteContext); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, glGetString); + + HINSTANCE hInstance = ffGetPeb()->ImageBaseAddress; + + WNDCLASSW wc = { + .lpfnWndProc = DefWindowProcW, + .hInstance = hInstance, + .hbrBackground = (HBRUSH) COLOR_BACKGROUND, + .lpszClassName = L"ogl_version_check", + .style = CS_OWNDC, + }; + if (!RegisterClassW(&wc)) { + return "RegisterClassW() failed"; + } + + HWND hWnd = CreateWindowW(wc.lpszClassName, L"ogl_version_check", 0, 0, 0, FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT, NULL, NULL, hInstance, NULL); + if (!hWnd) { + return "CreateWindowW() failed"; + } + + const char* error = wglHandlePixelFormat(&data, result, hWnd); + + DestroyWindow(hWnd); + UnregisterClassW(wc.lpszClassName, hInstance); + + return error; +} + +const char* ffDetectOpenGL(FFOpenGLOptions* options, FFOpenGLResult* result) { + if (options->library == FF_OPENGL_LIBRARY_AUTO) { + return wglDetectOpenGL(result); + } else if (options->library == FF_OPENGL_LIBRARY_EGL) { +#if __has_include(<EGL/egl.h>) + const char* ffOpenGLDetectByEGL(FFOpenGLResult * result); + return ffOpenGLDetectByEGL(result); +#else + return "fastfetch was compiled without egl support"; +#endif + } else { + return "Unsupported OpenGL library"; + } +} |