2022-06-04 15:21:34 +02:00
#include "fastfetch.h"
2022-07-25 13:15:01 +02:00
#include "common/printing.h"
2022-07-25 13:59:19 +02:00
#include "common/parsing.h"
2022-06-04 15:21:34 +02:00
#include <string.h>
#define FF_OPENGL_MODULE_NAME "OpenGL"
2022-06-04 19:30:26 +02:00
#define FF_OPENGL_NUM_FORMAT_ARGS 4
2022-06-04 15:21:34 +02:00
2022-09-13 13:57:12 +08:00
#if defined(FF_HAVE_EGL) || defined(FF_HAVE_GLX) || defined(FF_HAVE_OSMESA) || defined(FF_HAVE_APPLECGL)
2022-06-04 19:30:26 +02:00
#define FF_HAVE_GL 1
2022-07-25 11:20:38 +02:00
#include "common/library.h"
2022-09-10 10:53:08 +08:00
#ifdef __APPLE__
#define GL_SILENCE_DEPRECATION
#include <OpenGL/gl.h>
#else
2022-06-04 15:21:34 +02:00
#include <GL/gl.h>
2022-09-10 10:53:08 +08:00
#endif
2022-06-04 15:21:34 +02:00
2022-06-04 19:30:26 +02:00
#define FF_OPENGL_BUFFER_WIDTH 1
#define FF_OPENGL_BUFFER_HEIGHT 1
2022-06-04 15:21:34 +02:00
typedef struct GLData
{
FF_LIBRARY_SYMBOL ( glGetString );
} GLData ;
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 );
2022-06-04 19:30:26 +02:00
const char * slv = ( const char * ) data -> ffglGetString ( GL_SHADING_LANGUAGE_VERSION );
2022-06-04 15:21:34 +02:00
2022-06-17 18:15:36 +02:00
if ( instance -> config . openGL . outputFormat . length == 0 )
2022-06-04 15:21:34 +02:00
{
2022-06-17 18:15:36 +02:00
ffPrintLogoAndKey ( instance , FF_OPENGL_MODULE_NAME , 0 , & instance -> config . openGL . key );
2022-06-04 15:21:34 +02:00
puts ( version );
}
else
{
2022-06-17 18:15:36 +02:00
ffPrintFormat ( instance , FF_OPENGL_MODULE_NAME , 0 , & instance -> config . openGL , FF_OPENGL_NUM_FORMAT_ARGS , ( FFformatarg []) {
2022-06-04 15:21:34 +02:00
{ FF_FORMAT_ARG_TYPE_STRING , version },
{ FF_FORMAT_ARG_TYPE_STRING , renderer },
2022-06-04 19:30:26 +02:00
{ FF_FORMAT_ARG_TYPE_STRING , vendor },
{ FF_FORMAT_ARG_TYPE_STRING , slv }
2022-06-04 15:21:34 +02:00
});
}
return NULL ;
}
#ifdef FF_HAVE_EGL
#include <EGL/egl.h>
typedef struct EGLData
{
2022-06-04 19:30:26 +02:00
GLData glData ;
2022-06-04 15:21:34 +02:00
2022-06-04 19:30:26 +02:00
FF_LIBRARY_SYMBOL ( eglGetProcAddress );
2022-06-04 15:21:34 +02:00
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" ;
2022-06-04 19:30:26 +02:00
return glHandlePrint ( instance , & data -> glData );
2022-06-04 15:21:34 +02:00
}
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 []){
2022-06-04 19:30:26 +02:00
EGL_WIDTH , FF_OPENGL_BUFFER_WIDTH ,
EGL_HEIGHT , FF_OPENGL_BUFFER_HEIGHT ,
2022-06-04 15:21:34 +02:00
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 )
{
2022-06-04 19:30:26 +02:00
data -> glData . ffglGetString = ( __typeof__ ( data -> glData . ffglGetString )) data -> ffeglGetProcAddress ( "glGetString" );
if ( ! data -> glData . ffglGetString )
return "eglGetProcAddress(glGetString) returned NULL" ;
2022-06-04 15:21:34 +02:00
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 ;
}
2022-06-04 19:30:26 +02:00
static const char * eglPrint ( FFinstance * instance )
2022-06-04 15:21:34 +02:00
{
EGLData eglData ;
FF_LIBRARY_LOAD ( egl , instance -> config . libEGL , "dlopen egl failed" , "libEGL.so" , 1 );
2022-09-10 13:36:15 +08:00
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 );
2022-06-04 15:21:34 +02:00
const char * error = eglHandleData ( instance , & eglData );
dlclose ( egl );
return error ;
}
#endif //FF_HAVE_EGL
#ifdef FF_HAVE_GLX
#include <GL/glx.h>
typedef struct GLXData
{
2022-06-04 19:30:26 +02:00
GLData glData ;
2022-06-04 15:21:34 +02:00
2022-06-04 19:30:26 +02:00
FF_LIBRARY_SYMBOL ( glXGetProcAddress );
2022-06-04 15:21:34 +02:00
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" ;
2022-06-04 19:30:26 +02:00
return glHandlePrint ( instance , & data -> glData );
2022-06-04 15:21:34 +02:00
}
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 )
{
2022-06-04 19:30:26 +02:00
data -> pixmap = data -> ffXCreatePixmap ( data -> display , DefaultRootWindow ( data -> display ), FF_OPENGL_BUFFER_WIDTH , FF_OPENGL_BUFFER_HEIGHT , ( unsigned int ) data -> visualInfo -> depth );
2022-06-04 15:21:34 +02:00
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 )
{
2022-06-04 19:30:26 +02:00
data -> glData . ffglGetString = ( __typeof__ ( data -> glData . ffglGetString )) data -> ffglXGetProcAddress (( const GLubyte * ) "glGetString" );
if ( data -> glData . ffglGetString == NULL )
return "glXGetProcAddress(glGetString) returned NULL" ;
2022-06-04 15:21:34 +02:00
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 ;
}
2022-06-04 19:30:26 +02:00
static const char * glxPrint ( FFinstance * instance )
2022-06-04 15:21:34 +02:00
{
GLXData data ;
FF_LIBRARY_LOAD ( glx , instance -> config . libGLX , "dlopen glx failed" , "libGLX.so" , 1 );
2022-09-10 13:36:15 +08:00
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 );
2022-06-04 15:21:34 +02:00
const char * error = glxHandleData ( instance , & data );
dlclose ( glx );
return error ;
}
#endif //FF_HAVE_GLX
2022-06-04 19:30:26 +02:00
#ifdef FF_HAVE_OSMESA
#include <GL/osmesa.h>
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 );
2022-09-10 13:36:15 +08:00
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 );
2022-06-04 19:30:26 +02:00
const char * error = osMesaHandleData ( instance , & data );
dlclose ( osmesa );
return error ;
}
#endif //FF_HAVE_OSMESA
2022-09-13 13:57:12 +08:00
#ifdef FF_HAVE_APPLECGL
#include <OpenGL/OpenGL.h>
static const char * appleCglPrint ( FFinstance * instance )
{
CGLPixelFormatAttribute attrs [] = {
kCGLPFAOpenGLProfile , ( CGLPixelFormatAttribute ) kCGLOGLPVersion_3_2_Core ,
kCGLPFAAccelerated ,
0
};
CGLPixelFormatObj pix ;
GLint num ;
if ( CGLChoosePixelFormat ( attrs , & pix , & num ) != kCGLNoError ) {
return "CGLChoosePixelFormat() failed" ;
}
CGLContextObj ctx ;
if ( CGLCreateContext ( pix , NULL , & ctx ) != kCGLNoError ) {
return "CGLCreateContext() failed" ;
}
if ( CGLSetCurrentContext ( ctx ) != kCGLNoError ) {
return "CGLSetCurrentContext() failed" ;
}
GLData glData = {
. ffglGetString = glGetString
};
const char * error = glHandlePrint ( instance , & glData );
CGLDestroyContext ( ctx );
CGLDestroyPixelFormat ( pix );
return error ;
}
#endif //FF_HAVE_APPLECGL
2022-06-04 19:30:26 +02:00
static const char * glPrint ( FFinstance * instance )
2022-06-04 15:21:34 +02:00
{
if ( instance -> config . glType == FF_GL_TYPE_GLX )
{
2022-06-04 19:30:26 +02:00
#ifdef FF_HAVE_GLX
return glxPrint ( instance );
2022-06-04 15:21:34 +02:00
#else
2022-06-04 19:30:26 +02:00
return "fastfetch was compiled without glx support" ;
2022-06-04 15:21:34 +02:00
#endif
}
if ( instance -> config . glType == FF_GL_TYPE_EGL )
{
#ifdef FF_HAVE_EGL
2022-06-04 19:30:26 +02:00
return eglPrint ( instance );
2022-06-04 15:21:34 +02:00
#else
return "fastfetch was compiled without egl support" ;
#endif
}
2022-06-04 19:30:26 +02:00
if ( instance -> config . glType == FF_GL_TYPE_OSMESA )
{
#ifdef FF_HAVE_OSMESA
return osMesaPrint ( instance );
#else
return "fastfetch was compiled without osmesa support" ;
#endif
}
2022-09-13 13:57:12 +08:00
if ( instance -> config . glType == FF_GL_TYPE_APPLECGL )
{
#ifdef FF_HAVE_APPLECGL
return appleCglPrint ( instance );
#else
return "fastfetch was compiled without apple-cgl support" ;
#endif
}
2022-06-04 15:21:34 +02:00
const char * error = "" ; // not NULL dummy value
#ifdef FF_HAVE_EGL
2022-06-04 19:30:26 +02:00
error = eglPrint ( instance );
2022-06-04 15:21:34 +02:00
#endif
#ifdef FF_HAVE_GLX
if ( error != NULL )
2022-06-04 19:30:26 +02:00
error = glxPrint ( instance );
2022-06-04 15:21:34 +02:00
#endif
2022-09-13 13:57:12 +08:00
#ifdef FF_HAVE_APPLECGL
if ( error != NULL )
error = appleCglPrint ( instance );
#endif
2022-06-04 19:30:26 +02:00
//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
2022-06-04 15:21:34 +02:00
return error ;
}
2022-06-04 19:30:26 +02:00
#endif // FF_HAVE_GL
2022-06-04 15:21:34 +02:00
void ffPrintOpenGL ( FFinstance * instance )
{
const char * error ;
#ifndef FF_HAVE_GL
error = "Fastfetch was built without gl support." ;
#else
2022-09-10 10:53:08 +08:00
error = glPrint ( instance );
2022-06-04 15:21:34 +02:00
#endif
if ( error != NULL )
2022-06-17 18:15:36 +02:00
ffPrintError ( instance , FF_OPENGL_MODULE_NAME , 0 , & instance -> config . openGL , error );
2022-06-04 15:21:34 +02:00
}