For those who read my earlier topic on managing meshes and buffers, probably will recognize this followup.
Otherwise:
- I've decided to 'correctly' abstract my renderer to be able to support multiple API's in the future
- I'm not that far in development of the engine yet (although quite some work in it), so I decided better do it now, then why the codebase grows larger
The basic lessons I've learned on 'abstraction', in this case, is as follows:
1. Create API independent Ixxxx classes (interfaces), for anything you'd like to abstract
(IRenderer, IDevice, IDeviceContext, IMeshBuffer, ICBuffer, IRenderTarget and so on)
2. Create the D3D11 versions, inherited from the Ixxx versions.
So ID3DDevice will be inherited from IDevice
3. Define which member functions of the I / abstract classes will need implementation API specific, independent or combination.
If API specific: 'virtual bool .... () = 0;
If API independent: 'bool ....();
If combined 'virtual bool ....();
With this goal in mind I went through the whole codebase and written down what and when I exactly use the (D3D11)device, context, renderer, buffers etc.
This list is the base for the v0.1 class definitions I've made, as you'll find in the code paste below.
My questions:
- am I on the right track on doing 'abstraction' in my renderer?
- what strange things do you see in the v0.1 setup?
Any input is appreciated as always.
// Classes D3DRenderer, D3DDevice, D3DDeviceContext will inherit from I classes
// functions without '= 0' will be implemented in parent + child
// functions with '= 0' will only be implemented in child/ inherited D3D11 classes
class IRenderer
{
public:
// API independent
bool LoadSettings();
// API dependent
virtual bool SetupRenderer() = 0;
virtual bool CreateSwapchain() = 0;
virtual bool CreateDepthStencil() = 0;
virtual bool SetRenderTarget(const IRenderTarget &pRenderTarget) = 0;
virtual bool OnResize() = 0;
virtual bool PrepareRender() = 0;
virtual bool Present() = 0;
// update settings API independent, rest in D3D11Renderer (inherited)
virtual bool SetFullscreen(const bool pFullscreen);
virtual bool ChangeMSAASettings(const bool pEnabled, const uint pNrSamples);
virtual bool SetVSync(const bool pEnabled);
private:
CD3dSettings mSettings;
IDevice mDevice;
IDeviceContext mDeviceContext;
};
#define VERTEX_BUFFER 0
#define INDEX_BUFFER 1
class IDevice
{
public:
// API dependent
virtual IDevice() = 0;
virtual ~IDevice() = 0;
virtual bool Create() = 0;
virtual ITexture* CreateTexture(const std::string pFilename) = 0; // add more params here
virtual IBuffer* CreateMeshBuffer(const uint pBufferType, void *pBufferData, const size_t pBufferSize, const bool pDynamic, const bool pGPUWrite) = 0;
private:
};
#define TRIANGLE_LIST 0
#define TRIANGLE_STRIP 1
// etc.
class IDeviceContext
{
public:
virtual IDeviceContext();
virtual ~IDeviceContext();
virtual bool SetShaderPack(const uint pId);
virtual bool SetInputLayout(const uint pHandle) = 0;
virtual bool SetPrimitiveTopology(const uint pTopology) = 0;
virtual bool SetSamplerState(const ISamplerState &pSamplerState) = 0;
virtual bool SetConstantBuffer(const ICBuffer &pCBuffer) = 0;
virtual bool SetTexture(const ITexture &pTexture) = 0;
virtual bool SetVertexBuffer(const IBuffer &pBuffer) = 0;
virtual bool SetIndexBuffer(const IBuffer &pBuffer) = 0;
virtual bool DrawIndexed(const uint pNrIndices, const uint pStartIndex, const uint pStartVtx) = 0;
virtual bool SetViewPort(const IViewport &pViewport) = 0;
private:
};
// PRIMARY TODO'S
// 1. Add abstract/ Iclasses (or structs) for: ConstantBuffer, RenderTarget, SamplerState, RenderState, Texture, Viewport
// 2. decide how/where to place ShaderManager/ ShaderPack/ CBufferManager / RenderTargetManager (also abstract/ IClasses?)