I'm in the middle of programming a pure abstract interface that is capable of handling rendering in either Direct3D 11 or OpenGL 3 (or greater). The design basically looks like this:
// Abstract resource class
class IBuffer
{
public:
// Destructor
virtual ~IBuffer() { }
// some pure virtual functions....
};
// Acts as a proxy class for ID3D11Buffer,
// on destruction calls COM Release()
class CBufferD3D11 : public IBuffer
{
public:
// Construction and destruction.
CBufferD3D11(ID3D11Buffer* buffer);
// Releases the D3DResource
~CBufferD3D11();
// Just left public for demo
ID3D11Buffer* m_resource;
};
// Abstract rendering class
class IRenderer
{
public:
// Virtual destructor
virtual ~IRenderer() {}
// Factory function
static IRenderer* Create(RenderType type);
// Function to create a vertex buffer
virtual IBuffer* CreateBuffer() = 0;
// Function to enable a vertex buffer
virtual void Enable(IBuffer* pBuffer) = 0;
};
// Acts a proxy class for the device object of Direct3D
class CRenderDevice : public IRenderer
{
public:
// Constructor to create a rendering device
CRenderDevice();
// Function to enable a vertex buffer
void Enable(IBuffer* pBuffer)
{
// This is a down cast, it could use dynamic_cast.
// However this would be slow :(
CBufferD3D11* pD3DBuffer = reinterpret_cast<CBufferD3D11*>(pBuffer);
m_pContext->IASetVertexBuffers(0, 1, &pD3DBuffer, 0, 0);
}
private:
ID3D11Device* m_pDevice;
ID3D11DeviceContext* m_pContext;
};
// Usage
void Foo()
{
// Create the renderer which can then create a D3D11 buffer
IRenderer* pRenderer = IRenderer::Create(D3D11);
IBuffer* pBuffer = pRenderer->CreateBuffer();
// Later during rendering
pRenderer->Enable(pBuffer);
}
The issue I am having with the above design is the communication between the two abstract interfaces. The rendering device needs to know which resource to enable/render, but unfortunately due to the abstraction, the underlying Direct3D layer is only aware of a higher level interface that has been passed into the IRenderer::Enable
function.
I have looked into using design patterns, but can't quite figure out which one would be the most suitable for use in future multi-threaded rendering. This would compromise of multiple device contexts that build rendering command lists and are played back on an immediate context [producer consumer].
So far the most efficient and thread safe method that I can think of is the one that uses down casting, either via a reinterpret_cast or through a lightweight custom RTTI. This keeps the abstraction light and not to far from the API implementation. As a result, the the application programmer is able to utilise additional functionality of the rendering pipeline, should they need to.
What is the best way to make abstract interfaces communicate together on a lower level without the need of down casting? What do commercial game engines tend to do?
I have looked into open source engines, but I am really not convinced their implementations are suitable for my needs. The best I've seen so far has been on David Eberly's site, which uses the higher level resources as a key to a std::map.