Direct3D 11 또는 OpenGL 3 (또는 그 이상)에서 렌더링을 처리 할 수있는 순수 추상 인터페이스를 프로그래밍하는 중입니다. 디자인은 기본적으로 다음과 같습니다.추상 인터페이스 및 다운 캐스팅 사용에 대한 지침이 필요합니다.
// 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);
}
위의 디자인에서 내가 겪고있는 문제는 두 개의 추상 인터페이스 간의 통신입니다. 렌더링 장치는 활성화/렌더링 할 리소스를 알아야하지만 불행히도 추상화로 인해 기본 Direct3D 계층은 IRenderer::Enable
함수에 전달 된 상위 수준 인터페이스 만 인식합니다.
디자인 패턴을 사용했지만 어떤 것이 미래의 멀티 스레드 렌더링에 가장 적합한 지 알 수 없습니다. 이는 렌더링 명령 목록을 작성하고 즉각적인 컨텍스트 [생산자 고객]에서 재생되는 여러 장치 컨텍스트를 손상시킵니다.
내가 생각할 수있는 가장 효율적인 스레드 안전 방법은 reinterpret_cast 또는 경량의 사용자 정의 RTTI를 통해 다운 캐스팅을 사용하는 방법입니다. 이렇게하면 API 구현과 멀리 떨어져 있지 않은 추상화가 유지됩니다. 결과적으로 어플리케이션 프로그래머는 필요한 경우 렌더링 파이프 라인의 추가 기능을 활용할 수 있습니다.
다운 캐스팅없이 추상 인터페이스가 하위 레벨에서 서로 통신하도록하는 가장 좋은 방법은 무엇입니까? 상업용 게임 엔진은 무엇을하는 경향이 있습니까?
오픈 소스 엔진을 살펴 보았지만 실제로 구현이 내 요구에 적합하다는 것을 확신하지 못했습니다. 지금까지 본 것 중에 가장 좋은 것은 David Eberly's site에 있었는데, 더 높은 수준의 리소스를 std :: map의 키로 사용합니다.
그렇지만 메시지 패턴과 같은 디자인 패턴이 사용되지 않는 한 스레드 안전 부분은 문제가되지 않아야합니다. – Sent1nel
당신이 제공 한 솔루션에 대한 문제는 이제 공백 포인터 형식이지만 자원을 고수준 프로그래머에게 노출한다는 것입니다. 높은 수준의 프로그래머는 우연히 예기치 못한 일을하거나 실수로 혼란을 겪을 수 있으므로이 리소스를 사용해서는 안됩니다. 또한 추상화 문제가 다른 곳으로 옮겨졌지만 아직 디자인 내에 남아 있다는 문제가 있습니다. – Sent1nel
당신은 그 메소드를 private 메소드로 만들고 IRenderer를 IBuffer의 친구로 만들 수 있습니다 : http://stackoverflow.com/questions/17434/when-should-you-use-friend-in-c ... 그리고 GetResource '개인 회원으로 활동합니다. 그러면 GetResource는 API 사용자가 걱정할 필요가없는 내부 함수라는 것을 명확히 알 수 있습니다. –