1
\$\begingroup\$

I am developing a cross-platform game-engine with a friend, using C++, OpenGL 2 and 4, and some other low level API provided by the platform. Recently, we had an idea to adapt function definition at runtime. For example, Machine 1 provides only OpenGL 2; the engine will see that, and use only OpenGL 2 functions. Machine 2 provides OpenGl 4 ,as well, so the engine will use OpenGL 4, instead.

Our problem with this is the implementation, and how we should approach it. On first thought, we decided to use function pointers, but after trying for a bit, it led us into problems with the code. The code was hard to understand, and hard to both fix and extend. The second approach we thought about was to replace the .DLL (Windows) or .SO (Linux) file (or hot swapping). So far, we can not implement a working, stable build.

How do we enable the swapping of function definitions, at runtime?

\$\endgroup\$
4
\$\begingroup\$

A common approach is to write separate renderers or renderers with "feature gates."

That is, you can make separate files for each API (GraphicsGL2.cpp, GraphicsGL4.cpp, etc.). You can then make some kind of IRenderer interface each implements or you can simply have one header and conditionally compile the renderer .cpp files for each platform (compile-time static polymorphism of a kind).

Alternatively, if you're sticking with one API family (GL), then you would have code like so in your renderer:

draw():
  begin_frame()

  if has_instancing:
    draw_instanced()
  else:
    draw_batched()

  end_frame()

You could use function pointers as well as set them up during initialization.

Yes, this can be messy. That is one of the many "joys" of using OpenGL. After having to select the right version, find extensions, and work around the myriad of vendor bugs you end up with a hodge-podge of code.

Using shared libraries offers little benefit over just embedding the different renderers, assuming you again are sticking to one API family.

If you end up using completely different APIs (Direct3D vs OpenGL vs GL|ES etc.) then your best bet is the compilation method I first mentioned. There's zero reason to use OpenGL on Windows if you already have D3D, you need a very specific implementation of GL for OSX, mobile platforms need GL|ES, and Linux needs to be kept at an old low-level version of GL if you want to support the standard FOSS drivers.

If you're looking to maximize portability with the least amount of code then write everything with GL|ES (which is compatible with sufficiently new versions of desktop GL for the most part, given the ARB_es2_compatibility and ARB_es3_compatibility) and don't worry too much about fallbacks to old versions (and hence limit your conditional code to the narrowest cases).

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ So far, we're targeting only Desktop Systems like Winodw and Linux for the x86 system, which means we won't use OGL|ES. We want to stick to OpenGL since it's great portability to other platforms. \$\endgroup\$ – LaVolpe Jan 12 '14 at 19:34
  • \$\begingroup\$ @Techie: then again, conditional code paths and separate .cpp for larger things. OpenGL doesn't port quite as well as people like to think given that not every driver/OS implements the same version or the same set of extensions or the same bugs. A lot of GL code I've written still ended up needing different implementation files in certain subsystems for OSX vs Linux vs Windows or even for NVIDIA vs AMD vs Intel. It's not that bad, but it will come up. \$\endgroup\$ – Sean Middleditch Jan 12 '14 at 20:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.