I'm developing a game. The game architecture is very modular. I have a "Graphics Engine", which uses either a Direct3D or OpenGL renderer. However the user does not have access to the renderers directly. Instead the "Graphics Engine" class is used, which uses a renderer interface.

I also have a resource management system. As for now, the renderers are respoinsible for allocating and releasing video memory. That couples my design in a bad way, since the "Graphics Engine" has undesirable logic for transferring resources between the RAM and the VideoRam through sending signals to the "Renderer". I want the resource management system to be responsible for allocating video memory.

I want to decouple the "Renderer" and "Graphics Engine" classes as much as possible, and make the renderer only responsible for rendering. Is there a way to obtain a universal pointer to a Video RAM buffer, and use it to render with both renderers?

My problem is basically that I can only obtain OpenGL or Direct3D handles, which can be used only from the relevant API. And the "Graphics Engine" should not know which renderer it uses.

  • \$\begingroup\$ isnt kinda like using a render target in xna, i guess there's no reason you can't wrap that up somehow in your own "API" \$\endgroup\$ – War Aug 17 '13 at 17:30
  • \$\begingroup\$ Are you not basically describing what most game engines do though? I personally use unity, at no point do i go near any DX or OpenGL API I simply declare game objects and add a renderer component to them, behind all that unity figures out the actual calls needed and its platform independent so whats your angle? \$\endgroup\$ – War Aug 17 '13 at 17:32
  • \$\begingroup\$ i guess you will have to code interfaces for the user to interact with and implement the neccesary functions once for each API. I don´t think there is a way of interacting with videocard in an API Independent way. \$\endgroup\$ – Luis W Aug 17 '13 at 17:35

This is just basic abstraction. Write an API-neutral interface for buffers, textures, and so on. Either use dynamic polymorphism (abstract interfaces with virtual functions) for these or compile-time static polymophism (a shared header with some ifdefs and then link different implementations whether you're compiling for a D3D-primary platforms or a GL-only platform). A simple, very incomplete draft of doing this would be:

// implement this interface for each graphics API you support
class IBuffer {
  ~IBuffer() {}

  virtual size_t GetByteWidth() const = 0;
  virtual void UpdateData(const void* data, size_t width, size_t offset = 0) = 0;
  virtual void* Map() = 0;
  virtual void Unmap() = 0;

// implement this interface for each graphics API you support
class IGraphicsDevice {
  virtual std::shared_ptr<IBuffer> CreateBuffer(size_t size) = 0;

// creates a device as appropriate
enum class EGraphicsType { Default, Direct3D, OpenGL, OpenGLES };
shared_ptr<IGraphicsDevice> GraphicsDeviceFactory(EGraphicsType type) {
  switch (type) {
  case EGraphicsType::Default:
#if defined(HAS_DIRECT3D)
  case EGraphicsType::Direct3D:
    return std::make_shared<GraphicsDeviceDirect3D>();
#if defined(HAS_OPENGL)
  case EGraphicsType::OpenGL:
    return std::make_shared<GraphicsDeviceOpenGL>();
#if defined(HAS_OPENGLES)
  case EGraphicsType::OpenGLES:
    return std::make_shared<GraphicsDeviceOpenGLES>();
    ASSERT(!"Unsupported graphics device");
    return nullptr;

For static polymorphism, get rid of the virtual calls, directly embed the ID3DWhatever* values or GLint values wrapped in an #if defined(USE_FOO) to select which implementation to use, and make a variety of .cpp files for each platform and either only link the ones you need or wrap their contents in more macro conditionals. For some of the last-gen consoles the static polymorphism approach could have a substantial impact on performance as their CPUs weren't as good at efficiently handling virtual table indirections, though on the PC and likely the next-gen consoles this shouldn't be much of a problem. I don't have any information on mobile platforms regarding this.

  • \$\begingroup\$ As an addendum, I don't think it's quite common to call the compile-time technique mentioned "static polymorphism" but I don't know any other terminology that more accurately describes it. Primary point is that you can do it all at compile-time with no virtual function calls. You can use the PIMPL pattern to keep system dependencies out of your headers if you want, too, or just use void* and a lot of casting since both the D3D COM interface pointers and the GLint handles will fit in a void* on every architecture that matters to game development. \$\endgroup\$ – Sean Middleditch Aug 18 '13 at 19:23

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.