When creating a system abstraction is better to have the platform different APIs hidden by a common interface at the lowest level that makes sense.

Taking in account the different modern (with no fixed function pipeline) native graphics APIs: OpenGLES 2.0+, OpengGL 3.0+, DirectX 10.0+, Xbox DirectX 9, LibGCM

If one was to create a stateless low level graphic API to sit on top of them all, what would be the best way to go to make it as thin and as fast as possible?

  • \$\begingroup\$ The requirement for the API to be stateless is interesting. OpenGL, for example, is stateful, and I think a stateless API that wraps it would only make sense if it were much higher level, so that it isn't, for example, having to push and pop the same matricies for each and every surface it renders. \$\endgroup\$ Jul 19, 2010 at 7:14
  • \$\begingroup\$ Avoiding useless state changes could still be implemented at a higher level, like by sorting the render calls based on their state before submitting them to the device. And by setting the state only if it's different from the current one. \$\endgroup\$
    – user274
    Jul 19, 2010 at 8:25
  • \$\begingroup\$ That's not stateless though. Maybe I'm wrong, but what I think of when I think of stateless, is an API where each call does not depend on previous calls at all. That means that any information that would normally be stored in state somewhere has to be passed in every call that that needs that information. For OpenGL, for example, these would be matricies on the stack, lighting, z-buffering and normalization options. \$\endgroup\$ Jul 25, 2010 at 12:31
  • \$\begingroup\$ Yes, for every draw call you would need, the mesh data, the blending state, the textures to bind, the sampling states etc.. Optimizations could be done later, without changing the API tho. Or maybe I'm reading your comment wrong.. \$\endgroup\$
    – user274
    Jul 25, 2010 at 13:37

5 Answers 5


The lowest level that makes sense from my point of view is something that talks about the resources involved in rendering - vb/ib, render surfaces, textures, shaders, state blocks, etc.

The problem here is that some of these need to be in different formats, depending on the API - that's where it gets a bit tricky. The easiest way around it is to pre-process static resources for the respective API. For dynamic ones, use only shaders to generate them - that makes it fairly straightforward to stay in native formats.

All you then do on the higher level is set up pipelines with attached resources and hand them to the GPU. You'll find that not everything can be abstracted out nicely in that way, especially if you take advantage of hardware-specific tricks. But it's a good start.

(Sidenote: if you treat platform-specific tricks as a special kind of resource, you can push this whole concept quite far. )

So in a way, you'll create two things: A hardware resource manager, plus a toolkit to set up a DAG of these resources.

  • \$\begingroup\$ I never thought about treating platform-specific things as resources. It sounds like a very good idea! Thanks. \$\endgroup\$
    – user274
    Jul 19, 2010 at 6:17

Given the broad range of APIs you wish to cover, the typical wrapping approach is likely to be inefficient and prone to difficulty in mapping API concepts across several other APIs which may or may not support particular functions to varying degrees.

As a result, the most sensible approach would be to create a feature-centric API. While this approach prevents the API user from utilizing all available functionality, it greatly simplifies the implementation of each backend, and enables backend-specific optimizations that would not otherwise be possible.

It also greatly simplifies management of unsupported functionality for the API user; they no longer have to check if function X exists, and determine which features are affected, but instead need only query the feature itself to see if it is supported with the current configuration. Even if you support partial or limited modes for features, the context provided makes it much easier to manage.

In terms of creating a stateless (also known as submission-based) renderer, typically a 64bit key is used to pack and submit commands for rendering. From that point there is a great deal of flexibility in terms of how to execute commands and what information to submit depending on what features and capabilities you want to support.

  • \$\begingroup\$ This is actually a good Idea. And it is part of the design I'm trying to create, but what I had in mind was to implement this features on top of a common low level API. But it might be the case that for some features you'd still need to deep into the native API for some more particular cases. \$\endgroup\$
    – user274
    Jul 18, 2010 at 22:55
  • \$\begingroup\$ Part of the idea is to avoid building a common low-level API, and having to deal with wrapping with a lowest-common denominator approach. By moving the level of abstraction up a notch, you do restrict the feature set somewhat, but you also gain the ability to exploit each platform. To handle the occasional need for deeper access, I prefer to provide a header that exposes the platform headers and some internal helpers; it might break version to version, but it's there if you need it. \$\endgroup\$ Jul 22, 2010 at 23:50

To start with, each API does things differently so it should go without saying that wrapping all of the above APIs would be difficult. That said, it is sometimes necessary to do so: at some point a game simply needs to run on more than one platform regardless of how hard it is to do so.

I think the best way to go about doing this is to come up with the functionality that can be implemented on all of the underlying API's and abstract that and only that. If you are developing a multiplatform game, you wouldn't implement every obscure piece of functionality that each API supports, you would only implement what you need. This also helps to keep the API small and fast.

To avoid the clutter of each different API's implementation being packed into the output, compiling should be done with platform neutral header files and platform specific code files. Then, the code file specific to the target platform would be the only one compiled keeping the API small.


There is an article on GPU Pro about this, by Emil Persson (Humus)


A cross-platform interface for rendering. The advantages of having one, and how we crammed DX10 into a common interface with DX9 consoles and maintained good performance.


You might want to check out the SDL library or Allegro. Both of them are low level, highly-portable game libraries, which have a way to plug them in an OpenGL context so you can render your graphics there. SDL has the fame of being used by he defunct Loki Games to port some popular games from the 2000s to Linux, and Allegro has a lot of time running on and has a great community of amateur game developers.

  • 4
    \$\begingroup\$ This doesn't really answer the question, not to mention that it is very much possible to wrap both OpenGL and DirectX (see Ogre3D, Irrlicht, etc.). \$\endgroup\$ Jul 18, 2010 at 20:46
  • \$\begingroup\$ Consider the games you've played. How many of them have options to use DirectX or OpenGL? That's how many create wrappers for the two libraries to be able to support either one. You have a limited imagination. :-P \$\endgroup\$
    – Ricket
    Jul 18, 2010 at 21:59
  • \$\begingroup\$ I recognize that there are some games that allow you to choose whether you want to render graphics with OpenGL or DirectX, but the question is about a cross-platform API, so I think the answer is adequate, I'll edit the first paragraph, though. \$\endgroup\$
    – chiguire
    Jul 19, 2010 at 13:51
  • 1
    \$\begingroup\$ the question is about a cross-platform stateless low level API. SDL and Allegro have nothing to do with it. \$\endgroup\$
    – user274
    Jul 19, 2010 at 14:00
  • \$\begingroup\$ @NocturnDragon - the question title is a bit misleading. At first glance I expected the question to be about the choices of API available, and I assume this answerer did as well. \$\endgroup\$
    – a_m0d
    Aug 13, 2010 at 2:52

You must log in to answer this question.