From 8ea2014baf32480ce2073e90725021dd8c5c0795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 5 Oct 2022 23:51:59 +0800 Subject: [PATCH] OpenGL: add support for Windows --- CMakeLists.txt | 6 + src/detection/opengl/opengl.h | 18 + src/detection/opengl/opengl_apple.c | 56 ++++ src/detection/opengl/opengl_linux.c | 369 +++++++++++++++++++++ src/detection/opengl/opengl_windows.c | 108 ++++++ src/modules/opengl.c | 459 ++------------------------ 6 files changed, 579 insertions(+), 437 deletions(-) create mode 100644 src/detection/opengl/opengl.h create mode 100644 src/detection/opengl/opengl_apple.c create mode 100644 src/detection/opengl/opengl_linux.c create mode 100644 src/detection/opengl/opengl_windows.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 495d2794..6a5122e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -302,6 +302,7 @@ if(LINUX OR BSD) src/detection/media/media_linux.c src/detection/wmtheme/wmtheme_linux.c src/detection/font/font_linux.c + src/detection/opengl/opengl_linux.c ) endif() @@ -318,6 +319,7 @@ if(WIN_MSYS) src/detection/media/media_linux.c src/detection/wmtheme/wmtheme_linux.c src/detection/font/font_linux.c + src/detection/opengl/opengl_windows.c src/util/windows/wmi.cpp ) endif() @@ -343,6 +345,7 @@ if(APPLE) src/detection/wmtheme/wmtheme_apple.m src/detection/temps/temps_apple.c src/detection/font/font_apple.m + src/detection/opengl/opengl_apple.c ) endif() @@ -366,6 +369,7 @@ if(ANDROID) src/detection/media/media_android.c src/detection/wmtheme/wmtheme_android.c src/detection/font/font_android.c + src/detection/opengl/opengl_linux.c ) endif() @@ -449,6 +453,8 @@ elseif(WIN_MSYS) PRIVATE "-lole32" PRIVATE "-loleaut32" PRIVATE "-ldwmapi" + PRIVATE "-lopengl32" + PRIVATE "-lgdi32" ) endif() diff --git a/src/detection/opengl/opengl.h b/src/detection/opengl/opengl.h new file mode 100644 index 00000000..20634718 --- /dev/null +++ b/src/detection/opengl/opengl.h @@ -0,0 +1,18 @@ +#pragma once + +#ifndef FF_INCLUDED_detection_opengl_opengl +#define FF_INCLUDED_detection_opengl_opengl + +#include "fastfetch.h" + +typedef struct FFOpenGLResult +{ + FFstrbuf version; + FFstrbuf renderer; + FFstrbuf vendor; + FFstrbuf slv; +} FFOpenGLResult; + +const char* ffDetectOpenGL(FFinstance* instance, FFOpenGLResult* result); + +#endif diff --git a/src/detection/opengl/opengl_apple.c b/src/detection/opengl/opengl_apple.c new file mode 100644 index 00000000..4ccbb5fe --- /dev/null +++ b/src/detection/opengl/opengl_apple.c @@ -0,0 +1,56 @@ + +#include "fastfetch.h" +#include "opengl.h" + +#define GL_SILENCE_DEPRECATION +#include +#include // This brings in CGL, not GL + +static const char* glHandleResult(FFOpenGLResult* result) +{ + ffStrbufAppendS(&result->version, (const char*) glGetString(GL_VERSION)); + ffStrbufAppendS(&result->renderer, (const char*) glGetString(GL_RENDERER)); + ffStrbufAppendS(&result->vendor, (const char*) glGetString(GL_VENDOR)); + ffStrbufAppendS(&result->slv, (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); + return NULL; +} + +static const char* cglHandleContext(FFOpenGLResult* result, CGLContextObj context) +{ + if(CGLSetCurrentContext(context) != kCGLNoError) + return "CGLSetCurrentContext() failed"; + + return glHandleResult(result); +} + +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* ffDetectOpenGL(FFinstance* instance, FFOpenGLResult* result) +{ + FF_UNUSED(instance); + + 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; +} diff --git a/src/detection/opengl/opengl_linux.c b/src/detection/opengl/opengl_linux.c new file mode 100644 index 00000000..6e5b8d50 --- /dev/null +++ b/src/detection/opengl/opengl_linux.c @@ -0,0 +1,369 @@ +#include "fastfetch.h" +#include "opengl.h" + +#include + +#if defined(FF_HAVE_EGL) || defined(FF_HAVE_GLX) || defined(FF_HAVE_OSMESA) +#define FF_HAVE_GL 1 + +#include "common/library.h" + +#include + +#define FF_OPENGL_BUFFER_WIDTH 1 +#define FF_OPENGL_BUFFER_HEIGHT 1 + +typedef struct GLData +{ + FF_LIBRARY_SYMBOL(glGetString) +} GLData; + +static const char* glHandleResult(FFOpenGLResult* result, const GLData* data) +{ + ffStrbufAppendS(&result->version, (const char*) data->ffglGetString(GL_VERSION)); + ffStrbufAppendS(&result->renderer, (const char*) data->ffglGetString(GL_RENDERER)); + ffStrbufAppendS(&result->vendor, (const char*) data->ffglGetString(GL_VENDOR)); + ffStrbufAppendS(&result->slv, (const char*) data->ffglGetString(GL_SHADING_LANGUAGE_VERSION)); + return NULL; +} + +#endif // FF_HAVE_GL + +#ifdef FF_HAVE_EGL +#include + +typedef struct EGLData +{ + GLData glData; + + FF_LIBRARY_SYMBOL(eglGetProcAddress) + FF_LIBRARY_SYMBOL(eglGetDisplay) + 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) +{ + if(data->ffeglMakeCurrent(data->display, data->surface, data->surface, data->context) != EGL_TRUE) + return "eglMakeCurrent returned EGL_FALSE"; + + return glHandleResult(result, &data->glData); +} + +static const char* eglHandleSurface(FFOpenGLResult* result, EGLData* data) +{ + data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){EGL_NONE}); + if(data->context == EGL_NO_CONTEXT) + return "eglCreateContext returned EGL_NO_CONTEXT"; + + const char* error = eglHandleContext(result, data); + data->ffeglDestroyContext(data->display, data->context); + return error; +} + +static const char* eglHandleDisplay(FFOpenGLResult* result, EGLData* data) +{ + if(data->ffeglBindAPI(EGL_OPENGL_API) != EGL_TRUE) + return "eglBindAPI returned EGL_FALSE"; + + EGLint eglConfigCount; + data->ffeglGetConfigs(data->display, &data->config, 1, &eglConfigCount); + if(eglConfigCount == 0) + return "eglGetConfigs returned 0 configs"; + + 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) + return "eglCreatePbufferSurface returned EGL_NO_SURFACE"; + + const char* error = eglHandleSurface(result, data); + data->ffeglDestroySurface(data->display, data->surface); + return error; +} + +static const char* eglHandleData(FFOpenGLResult* result, EGLData* data) +{ + data->glData.ffglGetString = (__typeof__(data->glData.ffglGetString)) data->ffeglGetProcAddress("glGetString"); + if(!data->glData.ffglGetString) + return "eglGetProcAddress(glGetString) returned NULL"; + + data->display = data->ffeglGetDisplay(EGL_DEFAULT_DISPLAY); + if(data->display == EGL_NO_DISPLAY) + return "eglGetDisplay returned EGL_NO_DISPLAY"; + + EGLint major, minor; + if(data->ffeglInitialize(data->display, &major, &minor) == EGL_FALSE) + return "eglInitialize returned EGL_FALSE"; + + const char* error = eglHandleDisplay(result, data); + data->ffeglTerminate(data->display); + return error; +} + +static const char* eglPrint(FFinstance* instance, FFOpenGLResult* result) +{ + EGLData eglData; + + FF_LIBRARY_LOAD(egl, &instance->config.libEGL, "dlopen egl failed", "libEGL.so", 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, 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); + + const char* error = eglHandleData(result, &eglData); + dlclose(egl); + return error; +} + +#endif //FF_HAVE_EGL + +#ifdef FF_HAVE_GLX +#include + +typedef struct GLXData +{ + GLData glData; + + FF_LIBRARY_SYMBOL(glXGetProcAddress) + 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) + + 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"; + + return glHandleResult(result, &data->glData); +} + +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"; + + return glxHandleVisualInfo(result, data); +} + +static const char* glxHandleData(FFOpenGLResult* result, GLXData* data) +{ + data->glData.ffglGetString = (__typeof__(data->glData.ffglGetString)) data->ffglXGetProcAddress((const GLubyte*) "glGetString"); + if(data->glData.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* glxPrint(FFinstance* instance, FFOpenGLResult* result) +{ + GLXData data; + + FF_LIBRARY_LOAD(glx, &instance->config.libGLX, "dlopen glx failed", "libGLX.so", 1); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, glXGetProcAddress); + 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); + + const char* error = glxHandleData(result, &data); + dlclose(glx); + return error; +} + +#endif //FF_HAVE_GLX + +#ifdef FF_HAVE_OSMESA +#include + +typedef struct OSMesaData +{ + GLData glData; + + FF_LIBRARY_SYMBOL(OSMesaGetProcAddress) + FF_LIBRARY_SYMBOL(OSMesaCreateContext) + FF_LIBRARY_SYMBOL(OSMesaMakeCurrent) + FF_LIBRARY_SYMBOL(OSMesaDestroyContext) + + OSMesaContext context; +} OSMesaData; + +static const char* osMesaHandleContext(FFOpenGLResult* result, OSMesaData* data) +{ + unsigned char buffer[FF_OPENGL_BUFFER_WIDTH * FF_OPENGL_BUFFER_HEIGHT * sizeof(uint32_t)]; // 4 bytes per pixel (RGBA) + + if(data->ffOSMesaMakeCurrent(data->context, buffer, GL_UNSIGNED_BYTE, FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT) != GL_TRUE) + return "OSMesaMakeCurrent returned GL_FALSE"; + + return glHandleResult(result, &data->glData); +} + +static const char* osMesaHandleData(FFOpenGLResult* result, OSMesaData* data) +{ + //The case to void* is required here, because OSMESAproc can't be cast to (__typeof__(data->glData.ffglGetString)) without a warning, even though it is the actual type. + data->glData.ffglGetString = (__typeof__(data->glData.ffglGetString)) (void*) data->ffOSMesaGetProcAddress("glGetString"); + if(data->glData.ffglGetString == NULL) + return "OSMesaGetProcAddress(glGetString) returned NULL"; + + data->context = data->ffOSMesaCreateContext(OSMESA_RGBA, NULL); + if(data->context == NULL) + return "OSMesaCreateContext returned NULL"; + + const char* error = osMesaHandleContext(result, data); + data->ffOSMesaDestroyContext(data->context); + return error; +} + +static const char* osMesaPrint(FFinstance* instance, FFOpenGLResult* result) +{ + OSMesaData data; + + FF_LIBRARY_LOAD(osmesa, &instance->config.libOSMesa, "dlopen osmesa failed", "libOSMesa.so", 8); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(osmesa, data, OSMesaGetProcAddress); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(osmesa, data, OSMesaCreateContext); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(osmesa, data, OSMesaMakeCurrent); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(osmesa, data, OSMesaDestroyContext); + + const char* error = osMesaHandleData(result, &data); + dlclose(osmesa); + return error; +} + +#endif //FF_HAVE_OSMESA + +const char* ffDetectOpenGL(FFinstance* instance, FFOpenGLResult* result) +{ + #if FF_HAVE_GL + + if(instance->config.glType == FF_GL_TYPE_GLX) + { + #ifdef FF_HAVE_GLX + return glxPrint(instance, result); + #else + return "fastfetch was compiled without glx support"; + #endif + } + + if(instance->config.glType == FF_GL_TYPE_EGL) + { + #ifdef FF_HAVE_EGL + return eglPrint(instance, result); + #else + return "fastfetch was compiled without egl support"; + #endif + } + + if(instance->config.glType == FF_GL_TYPE_OSMESA) + { + #ifdef FF_HAVE_OSMESA + return osMesaPrint(instance, result); + #else + return "fastfetch was compiled without osmesa support"; + #endif + } + + const char* error = ""; // not NULL dummy value + + #ifdef FF_HAVE_EGL + error = eglPrint(instance, result); + #endif + + #ifdef FF_HAVE_GLX + if(error != NULL) + error = glxPrint(instance, result); + #endif + + //We don't use osmesa in auto mode here, because it is a software implementation, + //that doesn't reflect the opengl supported by the hardware + + return error; + + #else + + FF_UNUSED(instance, result); + return "Fastfetch was built without gl support."; + + #endif //FF_HAVE_GL +} diff --git a/src/detection/opengl/opengl_windows.c b/src/detection/opengl/opengl_windows.c new file mode 100644 index 00000000..92e56b97 --- /dev/null +++ b/src/detection/opengl/opengl_windows.c @@ -0,0 +1,108 @@ +#include "fastfetch.h" +#include "common/printing.h" +#include "opengl.h" + +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#ifndef GL_SHADING_LANGUAGE_VERSION // For WGL + #define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#endif + +static const char* glHandleResult(FFOpenGLResult* result) +{ + ffStrbufAppendS(&result->version, (const char*) glGetString(GL_VERSION)); + ffStrbufAppendS(&result->renderer, (const char*) glGetString(GL_RENDERER)); + ffStrbufAppendS(&result->vendor, (const char*) glGetString(GL_VENDOR)); + ffStrbufAppendS(&result->slv, (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); + return NULL; +} + +const char* wglHandleContext(FFOpenGLResult* result, HDC hdc, HGLRC context) +{ + if(wglMakeCurrent(hdc, context) == FALSE) + return "wglMakeCurrent() failed"; + return glHandleResult(result); +} + +const char* wglHandlePixelFormat(FFOpenGLResult* result, HWND hWnd) +{ + PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags + PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. + 32, // Colordepth of the framebuffer. + 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, 0, + 24, // Number of bits for the depthbuffer + 8, // Number of bits for the stencilbuffer + 0, // Number of Aux buffers in the framebuffer. + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + + HDC hdc = GetDC(hWnd); + + if(SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd) == FALSE) + return "SetPixelFormat() failed"; + + HGLRC context = wglCreateContext(hdc); + if(context == NULL) + return "wglCreateContext() failed"; + + const char* error = wglHandleContext(result, hdc, context); + wglDeleteContext(context); + + return error; +} + +typedef struct WGLData +{ + FFOpenGLResult* result; + const char* error; +} WGLData; + +LRESULT CALLBACK wglHandleWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_CREATE: { + WGLData* wglData = (WGLData*)((CREATESTRUCT*)lParam)->lpCreateParams; + wglData->error = wglHandlePixelFormat(wglData->result, hWnd); + PostQuitMessage(0); + return 0; + } + default: + return DefWindowProcW(hWnd, message, wParam, lParam); + } +} + +const char* ffDetectOpenGL(FFinstance* instance, FFOpenGLResult* result) +{ + FF_UNUSED(instance); + + MSG msg = {0}; + WNDCLASSW wc = { + .lpfnWndProc = wglHandleWndProc, + .hInstance = NULL, + .hbrBackground = (HBRUSH)COLOR_BACKGROUND, + .lpszClassName = L"ogl_version_check", + .style = CS_OWNDC, + }; + if(!RegisterClassW(&wc)) + return "RegisterClassW() failed"; + + WGLData data = { .result = result }; + HWND hWnd = CreateWindowW(wc.lpszClassName, L"ogl_version_check", 0, 0, 0, 1, 1, NULL, NULL, NULL, &data); + + while(GetMessageW(&msg, hWnd, 0, 0) > 0) + DispatchMessage(&msg); + + return data.error; +} diff --git a/src/modules/opengl.c b/src/modules/opengl.c index 78d0b484..61e78451 100644 --- a/src/modules/opengl.c +++ b/src/modules/opengl.c @@ -1,457 +1,42 @@ #include "fastfetch.h" #include "common/printing.h" -#include "common/parsing.h" - -#include +#include "detection/opengl/opengl.h" #define FF_OPENGL_MODULE_NAME "OpenGL" #define FF_OPENGL_NUM_FORMAT_ARGS 4 -#if defined(FF_HAVE_EGL) || defined(FF_HAVE_GLX) || defined(FF_HAVE_OSMESA) || defined(__APPLE__) -#define FF_HAVE_GL 1 - -#include "common/library.h" - -#ifdef __APPLE__ - #define GL_SILENCE_DEPRECATION - #include -#else - #include -#endif - -#define FF_OPENGL_BUFFER_WIDTH 1 -#define FF_OPENGL_BUFFER_HEIGHT 1 - -typedef struct GLData +void ffPrintOpenGL(FFinstance* instance) { - FF_LIBRARY_SYMBOL(glGetString) -} GLData; + FFOpenGLResult result; + ffStrbufInit(&result.version); + ffStrbufInit(&result.renderer); + ffStrbufInit(&result.vendor); + ffStrbufInit(&result.slv); -static const char* glHandlePrint(FFinstance* instance, const GLData* data) -{ - const char* version = (const char*) data->ffglGetString(GL_VERSION); - if(!ffStrSet(version)) - return "glGetString(GL_VERSION) returned NULL"; - - const char* renderer = (const char*) data->ffglGetString(GL_RENDERER); - const char* vendor = (const char*) data->ffglGetString(GL_VENDOR); - const char* slv = (const char*) data->ffglGetString(GL_SHADING_LANGUAGE_VERSION); + const char* error = ffDetectOpenGL(instance, &result); + if(error) + { + ffPrintError(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGL, "%s", error); + return; + } if(instance->config.openGL.outputFormat.length == 0) { ffPrintLogoAndKey(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGL.key); - puts(version); + puts(result.version.chars); } else { ffPrintFormat(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGL, FF_OPENGL_NUM_FORMAT_ARGS, (FFformatarg[]) { - {FF_FORMAT_ARG_TYPE_STRING, version}, - {FF_FORMAT_ARG_TYPE_STRING, renderer}, - {FF_FORMAT_ARG_TYPE_STRING, vendor}, - {FF_FORMAT_ARG_TYPE_STRING, slv} + {FF_FORMAT_ARG_TYPE_STRBUF, &result.version}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result.renderer}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result.vendor}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result.slv} }); } - return NULL; -} - -#endif // FF_HAVE_GL - -#ifdef FF_HAVE_EGL -#include - -typedef struct EGLData -{ - GLData glData; - - FF_LIBRARY_SYMBOL(eglGetProcAddress) - FF_LIBRARY_SYMBOL(eglGetDisplay) - 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(FFinstance* instance, EGLData* data) -{ - if(data->ffeglMakeCurrent(data->display, data->surface, data->surface, data->context) != EGL_TRUE) - return "eglMakeCurrent returned EGL_FALSE"; - - return glHandlePrint(instance, &data->glData); -} - -static const char* eglHandleSurface(FFinstance* instance, EGLData* data) -{ - data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){EGL_NONE}); - if(data->context == EGL_NO_CONTEXT) - return "eglCreateContext returned EGL_NO_CONTEXT"; - - const char* error = eglHandleContext(instance, data); - data->ffeglDestroyContext(data->display, data->context); - return error; -} - -static const char* eglHandleDisplay(FFinstance* instance, EGLData* data) -{ - if(data->ffeglBindAPI(EGL_OPENGL_API) != EGL_TRUE) - return "eglBindAPI returned EGL_FALSE"; - - EGLint eglConfigCount; - data->ffeglGetConfigs(data->display, &data->config, 1, &eglConfigCount); - if(eglConfigCount == 0) - return "eglGetConfigs returned 0 configs"; - - 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) - return "eglCreatePbufferSurface returned EGL_NO_SURFACE"; - - const char* error = eglHandleSurface(instance, data); - data->ffeglDestroySurface(data->display, data->surface); - return error; -} - -static const char* eglHandleData(FFinstance* instance, EGLData* data) -{ - data->glData.ffglGetString = (__typeof__(data->glData.ffglGetString)) data->ffeglGetProcAddress("glGetString"); - if(!data->glData.ffglGetString) - return "eglGetProcAddress(glGetString) returned NULL"; - - data->display = data->ffeglGetDisplay(EGL_DEFAULT_DISPLAY); - if(data->display == EGL_NO_DISPLAY) - return "eglGetDisplay returned EGL_NO_DISPLAY"; - - EGLint major, minor; - if(data->ffeglInitialize(data->display, &major, &minor) == EGL_FALSE) - return "eglInitialize returned EGL_FALSE"; - - const char* error = eglHandleDisplay(instance, data); - data->ffeglTerminate(data->display); - return error; -} - -static const char* eglPrint(FFinstance* instance) -{ - EGLData eglData; - - FF_LIBRARY_LOAD(egl, &instance->config.libEGL, "dlopen egl failed", "libEGL.so", 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, 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); - - const char* error = eglHandleData(instance, &eglData); - dlclose(egl); - return error; -} - -#endif //FF_HAVE_EGL - -#ifdef FF_HAVE_GLX -#include - -typedef struct GLXData -{ - GLData glData; - - FF_LIBRARY_SYMBOL(glXGetProcAddress) - 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) - - Display* display; - XVisualInfo* visualInfo; - Pixmap pixmap; - GLXPixmap glxPixmap; - GLXContext context; -} GLXData; - -static const char* glxHandleContext(FFinstance* instance, GLXData* data) -{ - if(data->ffglXMakeCurrent(data->display, data->glxPixmap, data->context) != True) - return "glXMakeCurrent returned False"; - - return glHandlePrint(instance, &data->glData); -} - -static const char* glxHandleGLXPixmap(FFinstance* instance, GLXData* data) -{ - data->context = data->ffglXCreateContext(data->display, data->visualInfo, NULL, True); - if(data->context == NULL) - return "glXCreateContext returned NULL"; - - const char* error = glxHandleContext(instance, data); - data->ffglXDestroyContext(data->display, data->context); - return error; -} - -static const char* glxHandlePixmap(FFinstance* instance, GLXData* data) -{ - data->glxPixmap = data->ffglXCreateGLXPixmap(data->display, data->visualInfo, data->pixmap); - if(data->glxPixmap == None) - return "glXCreateGLXPixmap returned None"; - - const char* error = glxHandleGLXPixmap(instance, data); - data->ffglXDestroyGLXPixmap(data->display, data->glxPixmap); - return error; -} - -static const char* glxHandleVisualInfo(FFinstance* instance, 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(instance, data); - data->ffXFreePixmap(data->display, data->pixmap); - return error; -} - -static const char* glxHandleDisplay(FFinstance* instance, GLXData* data) -{ - data->visualInfo = data->ffglXChooseVisual(data->display, DefaultScreen(data->display), (int[]){None}); - if(data->visualInfo == NULL) - return "glXChooseVisual returned NULL"; - - return glxHandleVisualInfo(instance, data); -} - -static const char* glxHandleData(FFinstance* instance, GLXData* data) -{ - data->glData.ffglGetString = (__typeof__(data->glData.ffglGetString)) data->ffglXGetProcAddress((const GLubyte*) "glGetString"); - if(data->glData.ffglGetString == NULL) - return "glXGetProcAddress(glGetString) returned NULL"; - - data->display = data->ffXOpenDisplay(NULL); - if(data->display == NULL) - return "XOpenDisplay returned NULL"; - - const char* error = glxHandleDisplay(instance, data); - data->ffXCloseDisplay(data->display); - return error; -} - -static const char* glxPrint(FFinstance* instance) -{ - GLXData data; - - FF_LIBRARY_LOAD(glx, &instance->config.libGLX, "dlopen glx failed", "libGLX.so", 1); - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, glXGetProcAddress); - 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); - - const char* error = glxHandleData(instance, &data); - dlclose(glx); - return error; -} - -#endif //FF_HAVE_GLX - -#ifdef FF_HAVE_OSMESA -#include - -typedef struct OSMesaData -{ - GLData glData; - - FF_LIBRARY_SYMBOL(OSMesaGetProcAddress) - FF_LIBRARY_SYMBOL(OSMesaCreateContext) - FF_LIBRARY_SYMBOL(OSMesaMakeCurrent) - FF_LIBRARY_SYMBOL(OSMesaDestroyContext) - - OSMesaContext context; -} OSMesaData; - -static const char* osMesaHandleContext(FFinstance* instance, OSMesaData* data) -{ - unsigned char buffer[FF_OPENGL_BUFFER_WIDTH * FF_OPENGL_BUFFER_HEIGHT * sizeof(uint32_t)]; // 4 bytes per pixel (RGBA) - - if(data->ffOSMesaMakeCurrent(data->context, buffer, GL_UNSIGNED_BYTE, FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT) != GL_TRUE) - return "OSMesaMakeCurrent returned GL_FALSE"; - - return glHandlePrint(instance, &data->glData); -} - -static const char* osMesaHandleData(FFinstance* instance, OSMesaData* data) -{ - //The case to void* is required here, because OSMESAproc can't be cast to (__typeof__(data->glData.ffglGetString)) without a warning, even though it is the actual type. - data->glData.ffglGetString = (__typeof__(data->glData.ffglGetString)) (void*) data->ffOSMesaGetProcAddress("glGetString"); - if(data->glData.ffglGetString == NULL) - return "OSMesaGetProcAddress(glGetString) returned NULL"; - - data->context = data->ffOSMesaCreateContext(OSMESA_RGBA, NULL); - if(data->context == NULL) - return "OSMesaCreateContext returned NULL"; - - const char* error = osMesaHandleContext(instance, data); - data->ffOSMesaDestroyContext(data->context); - return error; -} - -static const char* osMesaPrint(FFinstance* instance) -{ - OSMesaData data; - - FF_LIBRARY_LOAD(osmesa, &instance->config.libOSMesa, "dlopen osmesa failed", "libOSMesa.so", 8); - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(osmesa, data, OSMesaGetProcAddress); - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(osmesa, data, OSMesaCreateContext); - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(osmesa, data, OSMesaMakeCurrent); - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(osmesa, data, OSMesaDestroyContext); - - const char* error = osMesaHandleData(instance, &data); - dlclose(osmesa); - return error; -} - -#endif //FF_HAVE_OSMESA - -#ifdef __APPLE__ -#include // This brings in CGL, not GL - -typedef struct CGLData -{ - CGLPixelFormatObj pixelFormat; - CGLContextObj context; -} CGLData; - -static const char* cglHandleContext(FFinstance* instance, CGLData* data) -{ - if(CGLSetCurrentContext(data->context) != kCGLNoError) - return "CGLSetCurrentContext() failed"; - - GLData glData; - glData.ffglGetString = glGetString; - - return glHandlePrint(instance, &glData); -} - -static const char* cglHandlePixelFormat(FFinstance* instance, CGLData* data) -{ - if(CGLCreateContext(data->pixelFormat, NULL, &data->context) != kCGLNoError) - return "CGLCreateContext() failed"; - - const char* error = cglHandleContext(instance, data); - CGLDestroyContext(data->context); - return error; -} - -static const char* cglPrint(FFinstance* instance) -{ - CGLData data; - - CGLPixelFormatAttribute attrs[] = { - kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, - kCGLPFAAccelerated, - 0 - }; - - GLint num; - if (CGLChoosePixelFormat(attrs, &data.pixelFormat, &num) != kCGLNoError) - return "CGLChoosePixelFormat() failed"; - - const char* error = cglHandlePixelFormat(instance, &data); - CGLDestroyPixelFormat(data.pixelFormat); - return error; -} - -#elif FF_HAVE_GL - -static const char* glPrint(FFinstance* instance) -{ - if(instance->config.glType == FF_GL_TYPE_GLX) - { - #ifdef FF_HAVE_GLX - return glxPrint(instance); - #else - return "fastfetch was compiled without glx support"; - #endif - } - - if(instance->config.glType == FF_GL_TYPE_EGL) - { - #ifdef FF_HAVE_EGL - return eglPrint(instance); - #else - return "fastfetch was compiled without egl support"; - #endif - } - - if(instance->config.glType == FF_GL_TYPE_OSMESA) - { - #ifdef FF_HAVE_OSMESA - return osMesaPrint(instance); - #else - return "fastfetch was compiled without osmesa support"; - #endif - } - - const char* error = ""; // not NULL dummy value - - #ifdef FF_HAVE_EGL - error = eglPrint(instance); - #endif - - #ifdef FF_HAVE_GLX - if(error != NULL) - error = glxPrint(instance); - #endif - - //We don't use osmesa in auto mode here, because it is a software implementation, - //that doesn't reflect the opengl supported by the hardware - - return error; -} - -#endif // !__APPLE__ && FF_HAVE_GL - -void ffPrintOpenGL(FFinstance* instance) -{ - const char* error; - - #ifndef FF_HAVE_GL - error = "Fastfetch was built without gl support."; - #elif __APPLE__ - error = cglPrint(instance); - #else - error = glPrint(instance); - #endif - - if(error != NULL) - ffPrintError(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGL, "%s", error); + ffStrbufDestroy(&result.version); + ffStrbufDestroy(&result.renderer); + ffStrbufDestroy(&result.vendor); + ffStrbufDestroy(&result.slv); }