View Issue Details

IDProjectCategoryView StatusLast Update
0004820The Dark ModCodingpublic16.05.2019 16:05
Reporterstgatilov Assigned Tostgatilov  
PrioritylowSeveritytweakReproducibilityN/A
Status resolvedResolutionfixed 
Product VersionTDM 2.06 
Target VersionTDM 2.08Fixed in VersionTDM 2.08 
Summary0004820: Remove M4 from Linux build | GL linking system
DescriptionFor some incomprehensible reason Linux build uses ugly M4 macros for generating some OpenGL stubs. The M4 macro-generator is AWFUL, and it is much less usable that ordinary Python code which can be written directly in Scons script.

I'd like to remove this dependency on M4, rewrite corresponding code generating with Python.

P.S. I recall having some problems with these M4 scripts when duzenko changed the set of OpenGL functions. So this work is even useful =)
Additional InformationGradually, this task turned into revising GL linking system (GL loader, qgl, glimp).
TagsNo tags attached.
Attached Files
gl_desc.txt (9,349 bytes)   
renderer\qgl.h:
    #include <gl/gl.h>
    #include "glext.h"
    GLExtension_t GLimp_ExtensionPointer( const char *name );

    extensions declarations:
        // ARB_vertex_buffer_object
        extern PFNGLBINDBUFFERARBPROC qglBindBuffer;
        extern PFNGLDELETEBUFFERSARBPROC qglDeleteBuffers;
        ...
        // GL fence sync
        extern PFNGLFENCESYNCPROC				qglFenceSync;
        ...

    // non-windows systems will just redefine qgl* to gl*
    #if defined( ID_GL_HARDLINK )
        #include "qgl_linked.h"
    #else
        // windows systems use a function pointer for each call so we can do our log file intercepts
        extern  void ( APIENTRY * qglAccum )(GLenum op, GLfloat value);
        extern  void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref);
        ...
        #if defined( _WIN32 )
            extern  int   ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *);
            extern  int   ( WINAPI * qwglDescribePixelFormat) (HDC, int, UINT, LPPIXELFORMATDESCRIPTOR);
            ...
        #endif
        #if defined( __linux__ )
            extern XVisualInfo * (*qglXChooseVisual)( Display *dpy, int screen, int *attribList );
            extern GLXContext (*qglXCreateContext)( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct );
            ...
        #endif
    #endif


renderer\qgl_linked.h:
    for every GL function:
        #define qglBegin glBegin

    #ifdef GLX_VERSION_1_1 // catch all for any GLX-aware situation
    #define qglXChooseVisual glXChooseVisual
    #define qglXCreateContext glXCreateContext
    #define qglXDestroyContext glXDestroyContext
    #define qglXMakeCurrent glXMakeCurrent
    #define qglXSwapBuffers glXSwapBuffers
    #define qglXGetProcAddressARB glXGetProcAddressARB
    #endif


//===================================================================================


win32\gl_logfuncs.cpp:
    for every GL function:
        static void APIENTRY logAlphaFunc(GLenum func, GLclampf ref) {
        	fprintf( tr.logFile, "glAlphaFunc %s %g\n", EnumString(func), ref );
        	dllAlphaFunc(func, ref);
        }
    linux-only:
        logChooseVisual(Display *dpy, int screen, int *attribList) {...}
        logCreateContext(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct) {...}
        logDestroyContext(Display *dpy, GLXContext ctx) {...}
        logMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx) {...}
        logSwapBuffers(Display *dpy, GLXDrawable drawable) {...}


win32\win_glimp.cpp:
    wgl extensions
    gamma settings
    create window + setup GL on it
    frontend/backend threads
    swap buffers, GLimp_ExtensionPointer

    bool GLimp_Init( glimpParms_t parms ) {
        ...
        driverName = r_glDriver.GetString()[0] ? r_glDriver.GetString() : "opengl32";
    	if ( !QGL_Init( driverName ) ) {
        ...
        GLimp_EnableLogging( ( r_logFile.GetInteger() != 0 ) );
    }
    void GLimp_Shutdown( void ) {
        ...
        QGL_Shutdown();
    }


win32\win_qgl.cpp:
    for every WGL function:
        int   ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *);
    for every GL function:
        void ( APIENTRY * qglBegin )(GLenum mode);
        static void ( APIENTRY * dllBegin )(GLenum mode);
    GL enums:
        typedef struct {
        	GLenum	e;
        	const char *name;
        } glEnumName_t;
        #define	DEF(x) { x, #x },
        glEnumName_t	glEnumNames[] = {
            DEF(GL_FALSE)
            DEF(GL_TRUE)
        	{ GL_BYTE, "GL_BYTE" },
        	{ GL_UNSIGNED_BYTE, "GL_UNSIGNED_BYTE" },
            ...
        static const char *EnumString( GLenum t );
    
    #include "gl_logfuncs.cpp"

    void QGL_Shutdown( void ) {
        //for every GL function:
        qglAccum                     = NULL;
        //for every WGL function:
        qwglCopyContext              = NULL;
    }
    bool QGL_Init( const char *dllname ) {
        ...
        if ( ( win32.hinstOpenGL = LoadLibrary( dllname ) ) == 0 )
        ...
        //for every GL function:
    	qglAccum                     = dllAccum = glAccum;
        //for every WGL function:
        qwglChoosePixelFormat        = ChoosePixelFormat;
    }
    void GLimp_EnableLogging( bool enable ) {
        if ( enable ) {
            ...
        	tr.logFile = fopen( ospath, "wt" );
            ...
            //for every GL function:
           	qglAccum                     = logAccum;
        }
        else {
            //for every GL function:
        	qglAccum                     = dllAccum;
        }

    }


//===================================================================================


linux\glimp.cpp:
    gamma settings
    create window + setup GL on it
    frontend/backend threads
    GLimp_SwapBuffers

    #ifdef ID_GL_HARDLINK
    void GLimp_EnableLogging(bool log) {
    	static bool logging;
    	if (log != logging)
    	{
    		common->DPrintf("GLimp_EnableLogging - disabled at compile time (ID_GL_HARDLINK)\n");
    		logging = log;
    	}
    }
    #endif
    
    void GLimp_Shutdown() {
        ...
        #if !defined( ID_GL_HARDLINK )
    		GLimp_dlclose();
        #endif
        ...
    }
		
    bool GLimp_Init( glimpParms_t a ) {
        ...
        #ifndef ID_GL_HARDLINK
        	if ( !GLimp_dlopen() ) {
        		return false;
        	}
        #endif
        ...
    }


linux\glimp_glenum.h:
    DEF(GL_FALSE)
    DEF(GL_TRUE)
    DEF(GL_BYTE)
    DEF(GL_UNSIGNED_BYTE)
    ...
    DEF(GL_TEXTURE_CUBE_MAP_EXT)
    DEF(GL_TEXTURE_3D)
    DEF(GL_TEXTURE_2D)
    DEF(GL_BLEND)
    ...
    

[generated]\linux\glimp_dlopen.cpp:
    for every GL function:
        void ( APIENTRY * qglAccum )(GLenum op, GLfloat value);
        void ( * dllAccum )(GLenum op, GLfloat value);
    for every GLX function (6 items):
        XVisualInfo * ( * qglXChooseVisual )(Display *dpy, int screen, int *attribList);
        XVisualInfo * ( * dllChooseVisual )(Display *dpy, int screen, int *attribList);

    void GLimp_BindNative() {
        //for every GL function:
        qglAccum = dllAccum;
        //for every GLX function:
        qglXChooseVisual = dllChooseVisual;
    }

    bool GLimp_dlopen() {
    	const char *driverName = r_glDriver.GetString()[0] ? r_glDriver.GetString() : "libGL.so.1";
    	if ( !( glHandle = dlopen( driverName, RTLD_NOW | RTLD_GLOBAL ) ) ) {
        ...
        //for every GL function:
        dllAccum = ( void ( APIENTRY *)(GLenum op, GLfloat value) ) dlsym( glHandle, "glAccum" );
        if (!dllAccum) { GLimp_dlsym_failed("glAccum"); return false; }
        //for every GLX function:
        dllChooseVisual = ( XVisualInfo * ( APIENTRY *)(Display *dpy, int screen, int *attribList) ) dlsym( glHandle, "glXChooseVisual" );
        if (!dllChooseVisual) { GLimp_dlsym_failed("glXChooseVisual"); return false; }
        ...
        // make the initial binding
    	GLimp_BindNative();
    }

    void GLimp_dlclose() {
        if (glHandle)
    		dlclose( glHandle );
        ...
        //for every GL function:
        qglAccum = NULL;
        //for every GLX function:
        qglXChooseVisual = NULL;
    }


[generated]\linux\glimp_logfuncs.cpp:
    empty with some ifdefs...


[generated]\linux\glimp_logging.cpp:
    GL enums:
        typedef struct {
        	GLenum	e;
        	const char *name;
        } glEnumName_t;
        #define	DEF(x) { x, #x },
        glEnumName_t	glEnumNames[] = {
            #include "sys/linux/glimp_glenum.h"
        	{ 0, NULL }
        };
        static const char *EnumString( GLenum t )
    
    #include "glimp_logfuncs.cpp"

    void GLimp_BindLogging() {/*empty*/}
    
    void GLimp_EnableLogging(bool enable) {
        ...
        if ( enable ) {
            ...
    		tr.logFile = fopen( ospath, "wt" );
        	GLimp_BindLogging();
    	} else {
    		GLimp_BindNative();
    	}
    }


[generated]\linux\glimp_stub.cpp:
    //for every GL function:
        void glAccum(GLenum op, GLfloat value){}
    //for every GLX function:
        XVisualInfo * glXChooseVisual(Display *dpy, int screen, int *attribList){}

    GLenum glGetError(void){return 0;}
    GLuint glGenLists(GLsizei range){return 0;}
    void glGetIntegerv(GLenum pname, GLint *params){ ... }

    const GLubyte * glGetString(GLenum name){
	    switch( name ) {
    		case GL_EXTENSIONS: return (GLubyte *)"GL_ARB_multitexture GL_ARB_texture_env_combine GL_ARB_texture_cube_map GL_ARB_texture_env_dot3";
    	}
    	return (const GLubyte *)"";
    }


[generated]\gllog\gl_extensions.cpp:
    GLExtension_t GLimp_ExtensionPointer( const char *name ) {
        if ( strstr( name, "wgl" ) == name ) {
    		common->DPrintf( "WARNING: GLimp_ExtensionPointer for '%s'\n", name );
    	}
        #ifdef ID_DEDICATED
        	common->Printf("GLimp_ExtensionPointer %s\n", name);
        	return StubFunction;
        #else
            ...
            ret = qglXGetProcAddressARB((const GLubyte *) name);
            return res;
            ...
        #endif
    }
gl_desc.txt (9,349 bytes)   

Activities

duzenko

duzenko

13.12.2018 10:35

developer   ~0010900

Having had a brief encounter with M4 I can't help but agree
I'm sure M4 is great and powerful but having to learn it in order to do maintenance on the qgl stuff feels like an overkill
Also, the way it's been used is very awkward and painful to maintain (I mean the hardcoded def sequence in gl_def.m4)
stgatilov

stgatilov

17.04.2019 15:14

administrator   ~0011746

Last edited: 17.04.2019 15:14

I have uploaded brief description of GL trash code.

Opened discussion here:
  forums.thedarkmod.com/topic/19961-gl-linking-system/

stgatilov

stgatilov

04.05.2019 09:09

administrator   ~0011778

Branch glimp_4820 has been created for GL linking refactoring.
stgatilov

stgatilov

16.05.2019 16:04

administrator   ~0011807

Merged in svn rev 8222 and 8223.

Issue History

Date Modified Username Field Change
04.06.2018 04:00 stgatilov New Issue
04.06.2018 04:00 stgatilov Status new => assigned
04.06.2018 04:00 stgatilov Assigned To => stgatilov
11.06.2018 09:41 stgatilov Target Version TDM 2.07 =>
13.12.2018 10:35 duzenko Note Added: 0010900
20.01.2019 07:20 stgatilov Target Version => TDM 2.08
17.04.2019 14:56 stgatilov File Added: gl_desc.txt
17.04.2019 15:14 stgatilov Note Added: 0011746
17.04.2019 15:14 stgatilov Note Edited: 0011746
04.05.2019 07:57 stgatilov Summary Remove M4 from Linux build => Remove M4 from Linux build | GL linking system
04.05.2019 07:57 stgatilov Additional Information Updated
04.05.2019 09:09 stgatilov Note Added: 0011778
16.05.2019 16:04 stgatilov Note Added: 0011807
16.05.2019 16:05 stgatilov Status assigned => resolved
16.05.2019 16:05 stgatilov Fixed in Version => TDM 2.08
16.05.2019 16:05 stgatilov Resolution open => fixed