Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Archives
Today
Total
관리 메뉴

codingfarm

Direct3D의 초기화 - 깊이, 스텐실 버퍼와 뷰 생성 본문

computer graphics/DirectX11

Direct3D의 초기화 - 깊이, 스텐실 버퍼와 뷰 생성

scarecrow1992 2020. 11. 28. 22:00

이제 깊이, 스텐실 버퍼를 생성해야 한다. 이전에 설명했듯이, 깊이 버퍼는 그냥 깊이정보를 담는 (그리고 스텐실을 사용하는 경우 스텐실 정보도 담는) 2차원 텍스처이다. 2차원 텍스처를 생성할 때에는 생성할 텍스처를 서술하는 D3D11_TEXTURE2D_DESC 구조체를 채우고 ID3D11Device::CreateTexture2D 메서드를 호출해야 한다. D3D11_TEXTURE2D_DESC 구조체의 정의는 아래와 같다.

typedef struct D3D11_TEXTURE2D_DESC {
    UINT             Width;
    UINT             Height;
    UINT             MipLevels;
    UINT             ArraySize;
    DXGI_FORMAT      Format;
    DXGI_SAMPLE_DESC SampleDesc;
    D3D11_USAGE      Usage;
    UINT             BindFlags;
    UINT             CPUAccessFlags;
    UINT             MiscFlags;
} D3D11_TEXTURE2D_DESC;

1. Width : 텍스처의 너비(텍셀 단위)

2. Height : 텍스처의 높이(xprtpf eksdnl)

3. MipLevels : 밉맵 수준의 갯수. 깊이$\cdot$스텐실 버퍼를 위한 텍스처에서는 밉맵 수준이 하나만 잇으면 된다.

4. ArraySize : 텍스처 배열의 텍스처 갯수. 깊이$\cdot$스텐실 버퍼의 경우에는 텍스처 하나만 필요하다.

5. Format : 텍셀의 형식을 뜻하는 필드로, DXGI_FORMAT 열거형의 값들 중 하나를 지정한다. 깊이$\cdot$스텐실 버퍼의 경우에 나온 형식들 중 하나를 사용해야 한다.

6. SampleDesc : 다중 표본 갯수의 품질 수준을 서술하는 구조체. 4X MSAA는 화면 해상도의 4배 크기인 후면 버퍼 하나와 깊이 버퍼 하나를 사용해서 부분 픽셀당 색상과 깊이$\cdot$스텐실 정보를 담는다. 따라서 깊이$\cdot$스텐실 버퍼를 위한 다중표본화 설정은 렌더 대상에 쓰인 설정과 일치해야 한다.

7. Usage : 텍스처의 용도를 뜻하는 필드로, D3D11_USAGE 열거형의 값들 중 하나를 지정한다.

가능한 값은 아래의 4가지이다.

value feature
D3D11_USAGE_DEFAULT $\bullet$ 자원을 GPU가 읽고 써야 한다면 이 용도를 설정한다.
$\bullet$ 이 용도를 설정하면 CPU는 자원을 읽거나 쓸 수 없다.
$\bullet$ 깊이$\cdot$스텐실 버퍼에 대한 모든 읽기$\cdot$쓰기는 GPU가 수행하므로 깊이\$cdot$스텐실 버퍼를 위한 텍스처를 생성할때에는 바로 이 D3D11_USAGE_DEFAULT 를 사용한다.
D3D11_USAGE_IMMUTABLE $\bullet$ 자원을 일단 생성한 후에는 그 내용을 바꾸지 않는 경우에 이 용도를 지정한다.
$\bullet$ 이용도를 지정하면 자원이 GPU 읽기전용이 되어서 몇가지 최적화가 가능해진다.
$\bullet$ CPU와 GPU는 이러한 불변 자원에 자료를 기록할 수 없다.
$\bullet$ CPU는 불변 자원의 자료를 읽을 수 없다.

D3D11_USAGE_DYNAMIC $\bullet$ 응용 프로그램(CPU)이 자원의 내용을 빈번하게 갱신해야 한다면(가령 매 프레임마다) 이 용도를 지정한다.
$\bullet$ 이 용도로 성된 자원은 GPU가 읽을 수 있고 CPU가 기록할 수 있다.
$\bullet$ GPU의 자원을 CPU에서 동적으로 갱신하면 성능상의 피해가 생긴다. 새 자료를 CPU 메모리(즉 시스템 RAM)에서 GPU 메모리(즉 비디오 RAM)로 전송해야하기 때문이다.
$\bullet$ 따라서 이 동적 용도 자원은 꼭 필요한 경우가 아니라면 피해야 한다.

D3D11_USAGE_STAGING $\bullet$ 응용 프로그램(CPU)이 자원의 복사본을 읽어야 한다면(즉, 자원이 자료를 비디오 메모리에서 시스템 메모리로 전송할 수 있어야 한다면) 이 용도를 지정해야 한다.
$\bullet$ GPU에서 CPU 메모리로의 자료 복사는 느린 연산이므로 꼭 필요한 경우가 아니라면 피해야 한다.

 

8. BindFlags : 자원을 파이프라인에 어떤 식으로 묶을 것인지를 지정하는 하나이상의 플래그들을 OR로 결합해서 지정한다. 깊이$\cdot$스텐실 버퍼의 경우 D3D11_BIND_DEPTH_STENCIL 플래그를 지정해야 한다. 그 외에 텍스처에 대해 가능한 결속 플래그(bind flag)를 들자면

   (a) D3D11_BIND_RENDER_TARGET : 텍스처를 렌더 대상으로서 파이프라인에 묶는다.

   (b) D3D11_BIND_SHADER_RESOURCE : 텍스처를 셰이더 자원으로서 파이프라인에 묶는다.

 

9. CPUAccessFlags : CPU가 자원에 접근하는 방식을 결정하는 플래그들을 지정한다.

value 기능
D3D11_CPU_ACCESS_WRITE CPU가 자원에 자료를 기록해야 할경우
D3D11_USAGE_DYNAMIC
D3D11_USAGE_STAGING
CPU의 쓰기 접근이 가능해야 할 경우
D3D11_CPU_ACCESS_READ CPU가 자원을 읽어야 할 경우
0 깊이$\cdot$스텐실 버퍼의 경우 GPU만 깊이$\cdot$스텐실 버퍼를 읽고 쓸 뿐 CPU는 전혀 접근하지 않을 경우

 

10. MiscFalgs : 기타 플래그들로, 깊이$\cdot$스텐실 버퍼에는 적용되지 않으므로 그냥 0을 지정하면 된다.

 

참고

앞에서 용도 플래그 D3D11_USAGE_DYNAMIC과 D3D11_USAGE_STAGING은 성능상의 피해가 있으므로 피해야 한다고 말했다. 이 둘의 공통 요인은 CPU가 관여한다는것으로, CPU 메모리와 GPU 메모리 사이에서 자료가 오가면 성능에 악영향이 미친다. 최대 속도를 위한 최선의 방법은 모든 자원을 생성해서 GPU에 올린 후 GPU 메모리에 유지하고 GPU만이 그것을 읽고 쓰는 식으로 그래픽 하드웨어가 작동하게 만드는 것이다. 응용 프로그램에 따라서는 CPU가 반드시 관여해야 하므로 이 플래그들을 피할 수 없는 경우도 있지만, 어쨋든 이 플래그들은 최소한으로만 사용하는 것이 바람직하다.

 

 

다양한 옵션들의 활용은 나중에 살펴보고, 지금은 깊이$\cdot$스텐실 버퍼의 생성에 필요한 옵션들에 집중한다.

후면버퍼와 마찬가지로, 깊이$\cdot$스텐실 버퍼를 사용하려면 그에 대한 깊이$\cdot$스텐실 뷰를 생성해서 파이프라인에 붙여야 한다. 그 과정은 렌더 대상 뷰의 것과 비슷하다. 다음은 깊이$\cdot$스텐실 텍스처와 해당 깊이$\cdot$스텐실 뷰를 생성하는 방법을 보여주는 코드이다.

D3D11_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = mClientWidth;
depthStencilDesc.Height = mClientHeight;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;

//4X MSAA를 사용하는가? 반드시 교환 사슬의 MSAA 설정과 일치해야 함.
if( mEnable4xMsaa ){
    depthStencilDesc.SampleDesc.Count = 4;
    depthStencilDesc.SampleDesc.Quality = m4xMsaaQuality-1;
}
//MSAA를 사용하지 않음
else{
    depthStencilDesc.SampleDesc.Count = 1;
    depthStencilDesc.SampleDesc.Quality = 0;
}

depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = 0;

ID3D11Texture2D* mDepthStencilBuffer;
ID3D11DepthStencilView* mDepthStencilView;

HR(md3dDevice->CreateTexture2D(
    &depthStencilDesc,                  // 생성할 텍스처를 서술하는 구조체
    0,
    &mDepthStencilBuffer));             // 깊이, 스텐실 버퍼를 가리키는 포인터를 돌려준다.
    
HR(md3dDevice->CreateDepthStencilView(
    mDepthStencilBuffer,                // 뷰를 생성하고자 하는 자원.
    0,
    mDepthStencilView));                // 깊이, 스텐실 뷰를 돌려준다.

CreateTexture2D의 두번째 매개변수는 텍스처에 채울 초기 자료를 가리키는 포인터이다. 그런데 지금 이 텍스처는 깊이, 스텐실 버퍼로 사용할 것이므로 따로 자료를 채울 필요가 없다. 깊이 버퍼링과 스텐실 연산을 수행할 때 Direct3D가 직접 깊이, 스텐실 버퍼를 기록한다. 따라서 이 둘째 매개변수에는 널 값을 설정한다.

 

CreateDepthStencilView 메서드의 둘째 매개변수는 D3D11_DEPTH_STENCIL_VIEW_DESC 구조체를 가리키는 포인터이다. 이 구조체는 특히 자원의 원소의 자료형식을 서술한다. 형식을 완전히 지정해서 자원을 생성햇다면(즉 무형식 자원이 아니라면) 이 매개변수에 NULL 값을 지정해도 된다. 그러면 메서드는 주어진 자원을 생성했을 때 지정한 형식을 적용해서 자원의 첫 번째 밉맵 수준에 대한 뷰를 생성한다. 지금 예의 경우 깊이, 스텐실 버퍼는 형식을 지정해서 생성한 자원이므로 널 값을 지정했다.

 

 

Comments