2012-02-23 3 views
1

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의 키로 사용합니다.

답변

0

나는이 문제를 100 % 확신하고있다. 문제가되는 부분이 내부 리소스 포인터에 액세스하는 방법 인 경우 IBuffer에 void *를 반환하는 메소드를 추가하지 않는 이유는 무엇입니까?

// Abstract resource class 
class IBuffer 
{ 
public: 
    // Destructor 
    virtual ~IBuffer() { } 

    // Grab a pointer to the internal resource 
    void* GetResource() = 0; 
}; 

// 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(); 

    void* GetResource() { return m_resource; } 

private: 
    ID3D11Buffer* m_resource; 
}; 

그런 다음 처리 할 버퍼 유형으로 캐스팅 할 수 있습니다. 그래서이 :

CBufferD3D11* pD3DBuffer = reinterpret_cast<CBufferD3D11*>(pBuffer); 
    m_pContext->IASetVertexBuffers(0, 1, &pD3DBuffer, 0, 0); 

...된다 :

CBufferD3D11* pD3DBuffer =(CBufferD3D11*)(pBuffer->GetResource()); 
    m_pContext->IASetVertexBuffers(0, 1, &pD3DBuffer, 0, 0); 

을만큼 당신의 렌더링이 올바른 버퍼와 결합되어이 좋아 잘 작동합니다으로?

스레드 안전을 처리하면 걱정할 필요가없는 별도의 문제가 있다고 생각합니까? 적절한 보호하에 버퍼에 호출을 랩핑한다.

+0

그렇지만 메시지 패턴과 같은 디자인 패턴이 사용되지 않는 한 스레드 안전 부분은 문제가되지 않아야합니다. – Sent1nel

+0

당신이 제공 한 솔루션에 대한 문제는 이제 공백 포인터 형식이지만 자원을 고수준 프로그래머에게 노출한다는 것입니다. 높은 수준의 프로그래머는 우연히 예기치 못한 일을하거나 실수로 혼란을 겪을 수 있으므로이 리소스를 사용해서는 안됩니다. 또한 추상화 문제가 다른 곳으로 옮겨졌지만 아직 디자인 내에 남아 있다는 문제가 있습니다. – Sent1nel

+0

당신은 그 메소드를 private 메소드로 만들고 IRenderer를 IBuffer의 친구로 만들 수 있습니다 : http://stackoverflow.com/questions/17434/when-should-you-use-friend-in-c ... 그리고 GetResource '개인 회원으로 활동합니다. 그러면 GetResource는 API 사용자가 걱정할 필요가없는 내부 함수라는 것을 명확히 알 수 있습니다. –

관련 문제