0. Device Initialize

DV·2023년 12월 13일

DirectX_2D

목록 보기
2/2
post-thumbnail

Flow

DirectX 11 의 처리 흐름도는 크게 다음과 같다.

  • (1) Device & Swap Chain 생성
  • (2) Depth/Stencil Buffer 생성
  • (3) render target 설정: SwapChain의 BackBuffer
    (depth/stencil view 설정)
  • (4) 어플리케이션 실행, 필요한 처리 수행
    • 일정간격으로 화면을 렌더링하고 swapChain으로 화면 갱신
    • 윈도우 사이즈의 갱신에 따라 백 버퍼를 리사이징한다
  • (5) 종료 처리

DirectX 11 library 참조

#include <d3d11.h>
#include <d3dcompiler.h>
#include <DirectXMath.h>
#pragma comment(lib, "d3d11")
#pragma comment(lib, "d3dcompiler")
using namespace DirectX;

Smart Pointer library 참조

#include <wrl.h>
using namespace Microsoft::WRL;

Smart Pointer

DirectX의 Reference Counter는 객체에 대한 이해가 필요하므로 관리가 어렵다.
용이한 관리 위해 MS에서 만든 Smart Pointer 기능을 사용한다.

  • 원리: template class로 생성, 소멸자에서 해제될 때 release하는 식
    • template <typename T>
       class ComPtr
       {
       private:
       	T* m_Ptr;
       public:
       	void*	GetAddressOf(){return &m_Ptr;}
         T*		Get(){return m_Ptr;}
       public:
       	ComPtr() :m_Ptr(nullptr){}
         ~ComPtr(){ if(m_Ptr) Release(m_Ptr); }
       }
    • 기본생성자 호출되므로 직접 초기화할 필요 X
    • 직접 해제 관리할 필요 X
  • Caution
    • 접근지점을 명확히 정해야 함
    • GetAdressOf() : 멤버포인터의 주소를 넘김 (doublePointer)
    • Get() : 멤버포인트가 가진 주소를 넘김 (Pointer)


Step0. Feature Level 결정

Feature Level

DirectX 11에서는 6단계의 Feature Level을 정의하여 이전 버전의 디바이스여도(DirectX 9/10/10.1) 호환 가능하다.
어플리케이션은 Feature Level에 따라 DirectX 11의 기능을 사용해 실행된다.
이 전 포스팅에서도 설명하였지만 DirectX 11의 기능은 피처 레벨에 의해 6단계로 나누어져있다

  • feature level: GPU가 서포트하는 기능셋의 엄밀한 정의
  • 기본적으로는 level은 하위 level의 기능 포함함
  • 디바이스를 생성할 때 낮은 기능 레벨을 지정하면 DirectX 9, DirectX 10 하드웨어에서도 DirectX 11을 사용 가능

about D3D_FEATURE_LEVEL

// array of feature levels
 D3D_FEATURE_LEVEL featureLevels[] =                             
{
    D3D_FEATURE_LEVEL_11_0,
    D3D_FEATURE_LEVEL_10_1,
    D3D_FEATURE_LEVEL_10_0,
};

// array size
UINT numFeatureLevels = ARRAYSIZE( featureLevels );

// device 생성 시 넘길 feature level 변수
D3D_FEATURE_LEVEL       g_featureLevel = D3D_FEATURE_LEVEL_11_0;    

Step1. Device & SwapChain 생성

DirectX 11을 사용하려면 [ Device ] [ Device Context ] [ SwapChain(DXGI) ] 인터페이스를 얻어야 한다.
D3D11CreateDeviceAndSwapChain 함수를 사용하면 위에서 언급한 3개의 인터페이스를 한번에 얻을 수 있다.

interface 변수 선언

// interface
ComPtr<ID3D11Device> pDevice;
ComPtr<ID3D11DeviceContext> pImmediateContext;
ComPtr<IDXGISwapChain> pSwapChain;

Device flag 설정
debug version에서는 D3D11_CREATE_DEVICE_DEBUG를, release version에선 0으로 설정한다.

  • D3D11_CREATE_DEVICE_DEBUG: 세팅하는 경우 GPU의 log 출력됨
UINT createDeviceFlags = 0;
#ifdef _DEBUG
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

Swap Cahin 설정
DXGI_SWAP_CHAIN_DESC 구조체를 사용해 설정할 수 있으며
백버퍼 설정, SwapChain과 관련할 윈도우 멀티샘플 설정, 화면모드 설정 등을 지정한다.

  • 해당 멤버들은 디폴트 동작이 0으로 설정되어 있는 경우가 많으므로
    모든 멤버를 설정하지 않을 경우에는 ::ZeroMemory 함수로 초기화하는 것이 편리함
  • 1600*900 resolution의 backBuffer 1개 SwapChain을 설정하는 예
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );					// 구조체 초기화  

sd.BufferCount = 1;									// backBuffer Count                                               
sd.BufferDesc.Width = 1600;							// backBuffer Resolution
sd.BufferDesc.Height = 900;                                                 
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;  // backBuffer Format
sd.BufferDesc.RefreshRate.Numerator = 60;           // 화면 주사율 (기본적으로 60/1)
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;	// backBuffer 용도
sd.OutputWindow = g_hWnd;                           // buffuer output window
sd.SampleDesc.Count = 1;                            // multi sampling count
sd.SampleDesc.Quality = 0;                          // multi sampling quality
sd.Windowed = TRUE;                                 // window mod

D3D11CreateDeviceAndSwapChain 호출

  • D3D11CreateDevice, CreateSwapChain으로 나누어 호출해도 됨
  • CreateSwapChain: Factory가 호출
    • SwapChain 생성 과정: Device -> Adapter -> Factory -> Swapchain
hr = D3D11CreateDeviceAndSwapChain( NULL,				//사용할 IDXGIAdapter 인터페이스
									D3D_DRIVER_TYPE_HARDWARE, //DirectX 11 디바이스 종류
                                    NULL,               //보통  NULL
                                    createDeviceFlags,  //디바이스 플래그
                                    featureLevels,      //featureLevel 사용할 배열
                                    numFeatureLevels,   //featureLevel arr count
                                    D3D11_SDK_VERSION,	//DirectX SDK 버전
                                    &sd,				//스왑체인 구조체
                                    pSwapChain.GetAddressOf(),
                                    	//할당할 SwapChain 인터페이스 포인터
                                    pDevice.GetAddress(), //할당할 Device 인터페이스 포인터
                                    &g_featureLevel,    //featureLevel 얻어낼 포인터
                                    pImmediateContext.GetAddressOf() );
                                    	//할당할 Device Context 인터페이스 포인터

Step2. BackBuffer & DepthStencilBuffer 설정

swapChain의 backBuffer는 render target으로 설정되어 있지 않다.
swapChain으로부터 backBuffer를 얻어 Device의 renderTarget으로 설정해야 한다.

Get BackBuffer
SwapChain으로부터 BackBuffer를 얻어온다.

  • IDXGISwapChain::GetBuffer 함수: backBuffer의 포인터 얻음
ComPtr<ID3D11Texture2D> pBackBuffer;
hr = pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )pBackBuffer.GetAddress() );

if( FAILED( hr ) )
	return hr;

Create Render Target View
texture는 view를 통해 pipeline과 access한다.
render target view는 D3D11_RENDER_TARGET_VIEW_DESC 구조체로 설정하며, 디폴트 설정으로 NULL을 넘긴다.

hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer.Get()
									//access할 resource
                                , NULL
                                , &pRenderTargetView.GetAddressOf() );
                                	//render target view를 받아올 변수 ptr
if( FAILED( hr ) )
	return hr;

Create Depth Stencil Texture
D3D11_TEXTURE2D_DESC 구조체로 설정한다.

D3D11_TEXTURE2D_DESC Desc = {};
ZeroMemory( &descDepth, sizeof(descDepth) );    //초기화
Desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; 	// depth 24bit + stencil 8bit
Desc.Width = (UINT)m_vRenderResolution.x; 		// render target texture 해상도와 같아야 함
Desc.Height = (UINT)m_vRenderResolution.y;
Desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; 		// 용도
Desc.CPUAccessFlags = 0; 						// CPU 접근 불가
Desc.Usage = D3D11_USAGE_DEFAULT;
Desc.SampleDesc.Count = 1; 						// multi sampling
Desc.SampleDesc.Quality = 0;
Desc.MipLevels = 1; 							// 저퀄리티 버전 사본 생성여부
Desc.MiscFlags = 0;								// 그 외 설정 없음
Desc.ArraySize = 1;

hr = m_Device->CreateTexture2D(&Desc, nullptr, m_DSTex.GetAddressOf());
if (FAILED( hr ))
    return hr;

Get Depth Stencil View

  • ID3D11DepthStencilView 인터페이스 사용
  • ID3D11Device::CreateDepthStencilView 함수로 생성
m_Device->CreateDepthStencilView(m_DSTex.Get(), nullptr, m_DSView.GetAddressOf());

Set RenderTarget
Output Merger(OM)에서 render target을 설정한다.
렌더타겟은 동시에 8개까지 설정할 수 있지만 깊이/스텐실 버퍼는 1개 뿐이다.

  • ID3D11DeviceContext::OMSetRenderTargets() 함수를 통해 설정한다
g_pImmediateContext->OMSetRenderTargets( 1					//renderTarget count
                                       , pRenderTargetView.GetAddressOf()
                                       						//renderTargetView arr pp
                                       , m_DSTex.Get() );	//DepthStencil

Step3. Viewport 설정

viewport는 render target의 rendering 영역에 대한 설정이다.
render target에 rendering하려면 각 render target마다 viewport를 설정해야 한다.

  • ID3D11DeviceContext::RSSetViewports() 함수로 viewport 설정
  • D3D11_VIEWPORT 구조체로 수행하며, float 형으로 사용

Position

geometry shader, 또는 vertex shader로부터 출력되는 vertex의 위치좌표(3D)는 투영변환 후 투영좌표계의 값이 된다 (x,y = -1 ~1, z = 0~1)
rasterizer는 뷰포트변환을 수행해 3D 투영좌표계로부터 2D 스크린 좌표(x,y = 0~1)을 계산한다

  • 스크린 좌표: 왼쪽 상단이 0,0 으로 Y축이 아래를 향하는 좌표계
    • (0,0): backBuffer의 왼쪽 상단
    • (1,1): bakcBuffer의 오른쪽 하단
  • viewport 변환식:
    • X = (Y+1) * ViewPort.Width * 0.5 + ViewPort.TopLeftX
    • Y = (1-Y) * ViewPort.Height * 0.5 + ViewPort.TopLeftY
    • Z = ViewPort.MinDepth + Z * (ViewPort.MaxDepth - ViewPort.MinDepth)

Viewport 설정

D3D11_VIEWPORT vp;

vp.Width =1900.f;
vp.Height = 600.f;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pImmediateContext->RSSetViewports( 1, &vp );  // rasterizer viewport setting

References
[1] DirectX Tutorial: https://blog.naver.com/sorkelf/40161126408

0개의 댓글