1. yotis
  2. glxx
  3. Issues
Issue #5 resolved

Source and header is too big

Jason McKesson
created an issue

The glxx.h file weighs in at 3MB, while the glxx.cpp file weighs in at 4. Indeed, the latter is so huge that Visual Assist patently refuses to parse it. Any project I use these files in slows to a crawl as Visual Assist uses up a massive quantity of memory to hold all of this stuff.

This makes using your library a non-starter, as it makes my IDE non-responsive.

Comments (6)

  1. yotis repo owner

    Well, I could for start remove the core versions up to OpenGL 2.1, since this code has really no meaning. This should drop the size a bit. A quick calculation shows a drop to glxx.h size around 200k. A similar drop would be for the implementation glxx.cpp file. This removal was in my todo list.

    Another thing you could try is to use the code as a library (static or dynamic), so that your IDE parses only the header file and not the .cpp. Also you could try qt-creator, this IDE parses the files in seconds.

    Furthermore, I am exploring another design using inheritance classes for the various OpenGL versions. For example OpenGL_1_0 _Loader is defined and OpenGL_1_1 is defined as

    class OpenGL_1_1_Loader : public OpenGL_1_0_Loader {
    //...
    }
    

    The various versions code is 2/3 of the whole since it duplicates functions for each version. The main negative of this design is that you lose the nice syntax

    using namespace glxx::gl_version_3_3;
    glColor3f(..)
    ...
    

    and you would have to use the loader objects directly.

    Any thoughts and suggestions on this would be welcome.

  2. Jason McKesson reporter

    Is the goal of this design to ensure that you only get the symbols (GL versions and extensions) you actually intend to use? Because your system seems overly complicated for such a design.

    The main problem with the header is the repetition of code. A function defined in 1.1 is also defined in 1.2, 1.3, 1.4, 1.5, 2.0, 2.1, and 3.0, and that's assuming that it was removed in 3.1. If it wasn't, then that includes 3.1, 3.2, 3.3, 4.0, 4.1 and 4.2.

    If the intent is to make it so that you can write `using namespace gl_version_X_Y` and get only the relevant symbols, then it seems that the following would be a better design:

    namespace gl_version_1_1_core
    {
      //functions for 1.1 that were not removed.
    }
    
    namespace gl_version_1_1_removed_3_1
    {
      //functions for 1.1 that were removed from 3.1
    }
    
    namespace gl_version_1_1
    {
      using namespace gl_version_1_1_core;
      using namespace gl_version_1_1_removed_3_1;
    }
    
    ...
    
    namespace gl_version_1_2
    {
      using namespace gl_version_1_1_core;
      using namespace gl_version_1_1_removed_3_1;
      using namespace gl_version_1_2_core;
      using namespace gl_version_1_2_removed_3_1;
    }
    
    ...
    
    namespace gl_version_3_1
    {
      using namespace gl_version_1_1_core;
      using namespace gl_version_1_2_core;
      ...
    }
    

    Each version's namespace would have only the functions that were added in that version. There would be variants for core and removed functions, up until 3.1 of course. This way, every function pointer is defined exactly one time, and it has a unique name.

    Also, rather than #defines, you should use enumerators. That way, you can put them in the namespace where those enumerators are relevant, so they don't all pollute the global namespace.

  3. yotis repo owner

    First of all, thank you for your very nice feedback.

    This duplication of pointers is a major issue indeed. Yes, the design goal is to get only the symbols you intend to use. The motivation to start this library was mainly because I wanted to refactor my OpenGL code to use core context functionality only and to be able to control which extensions are being used and where they are used. Also it must be able to work with compatibility contexts, until all code is ported to core functionality, as well as support multiple contexts. After reviewing almost all major extensions loading libraries, none could offer what I wanted, plus they contained some bugs when used with core contexts at that time (1.5 years ago).

    Commit 20f7d0f4ca0a brings major API changes to fix this issue. The meaning of the gl_version_... namespaces are changed and now they include only the pointers as suggested. gl_version_1_0 includes only core functions from OpenGL 1.0, gl_version_1_0_deprecated includes only deprecated functionality from OpenGL 1.0 and so on. New namespaces are now introduced and these should be used from now on. gl_1_0, gl_1_1, ..., gl_3_0 have all the functions (core & deprecated) for OpenGL versions up to 3.0. For OpenGL 3.1 to 4.2 there are two namespaces for each version, gl_3_1_compatibility, gl_3_1_core, gl_3_2_compatibility, gl_3_2_core, ..., gl_4_2_compatibility, gl_4_2_core. Also there are new load_gl_1_0(), ..., load_gl_4_2_core(), one for each namespace. Finally there are new functions following this new wording, has_gl_1_0(), ..., has_gl_4_2().

    This is an example with the new wording

    #include <glxx.h>
    using namespace glxx::gl_3_3_core;
    on_OpenGL_init()
    {
        if (!has_gl_3_3())
            exit(0);
        glxx::load_gl_3_3_core();
        glGetString(GL_VERSION);
        // ...
    }
    on_OpenGL_draw()
    {
        glClear(GL_COLOR_BUFFER_BIT);
        // ...
    }
    

    With theses changes the filesize drops from 3MB to 1MB for glxx.h and from 4MB to 1.1MB for glxx.cpp. A drop like this justifies the API brake. As a result compile time also drops significantly (I am testing this with vs2008 compiler on win7 x64).

    Moreover, I also introduced new Loader objects for each new namespace. These are mainly used for multiple contexts. Internally all gl.. functions are calling these loader objects, in .cpp code they are declared as default_..._loader for each version and each extension. When I was writing these Loaders, I noticed that compile times for client code are getting up (due to multiple inheritance). They are still much faster than the previous versions, but since this is a major redesign of the library I want with the next commit to tackle this issue. Note that the new namespaces are not using these new loaders and they are there mainly to keep the API consistent.

    What I think is to not expose Loaders at all to the public API, just keep them internally in the .cpp file and change the way you use multiple contexts like this:

    #include <glxx.h>
    int gl21;
    int gl33c;
    glxxCreateLoaders(1, &gl21);
    glxxCreateLoaders(1, &gl33);
    
    // Create an OpenGL 2.1 context and make it current
    glxxBindLoader(gl21);
    glGetString(GL_VERSION); // this returns 2.1
    
    // Create an OpenGL 3.3 core context and make it current
    glxxBindLoader(gl33);
    glGetString(GL_VERSION); // this returns 3.3
    
    // ....
    
    glxxDeleteLoaders(1, &gl21);
    glxxDeleteLoaders(1, &gl33);
    

    One implementation I am considering is to keep vectors of each extension / version Loaders and glxxBindLoader() will change the current index. As a side effect with some more effort, this will make the library also C compatible. since no classes would be exposed to the public.

    Finally for the enums, at first when I started the library I tried to use enums, but the main problem was that there are enums like this TIMEOUT_IGNORED = 0xFFFFFFFFFFFFFFFFull. This is a 64-bit unsigned int, so when assigned as an enum value, the compiler treats it like a 64-bit unsigned int. So this

    enum ARB_sync_enum {
         MAX_SERVER_WAIT_TIMEOUT = 0x9111,
         ...
         TIMEOUT_IGNORED = 0xFFFFFFFFFFFFFFFFull
    }
    

    would expand all enums in there to 64-bit unigned int, when most gl functions are accepting GLenum (==32 bit int). Maybe using unnamed enums, one for each constant is a solution, i will think about this some more and test it. Maybe the function signatures will have to change too?

    So to summarize, my current planning is for the next 0.4 version tag to remove Loaders from the public API, 0.5 will add C support and dll support as well (from there we will have binary releases also), 0.6 some cleanups/refactor in the generator scripts, leaving 0.7-0.9 to tackle the enum issues and eliminating all known bugs as glxx approaches version 1.0.

    ps. As a bonus, commit 20f7d0f4ca0a fixes issue #4 ;)

  4. Log in to comment