본문 바로가기

그래픽스

[DX12] 장치 초기화 개요

DirectX에서는 3d를 화면으로 그리기 때문에 지금까지 했던 것에 비해 훨씬 많은 계산이 필요하다. 그래서 CPU에서만 계산하는 것은 부족하기 때문에 GPU에서도 계산을 하게 된다. 이것을 외주라고 비유한다. 지금부터 외주를 보내는데 필요한 클래스들을 소개하겠다.

 

 

Device

 

Device는 인력 사무소다. 외주를 보낼 때 Device를 통해 보낸다. Device를 초기화할 때 CreateDXGIFactory로 DXGI를 사용할 수 있게 하고 CreateDevice는 그래픽 카드를 나타내는 객체를 생성한다. 그래서 외주를 보낼 때 이 객체를 통해 진행한다.

 

// DXGI(DirectX Graphics Infrastructure)
// Direct3D와 함께 쓰이는 API	
::CreateDXGIFactory(IID_PPV_ARGS(&_dxgi));

// CreateDevice
// - 디스플레이 어댑터(그래픽 카드)를 나타내는 객체	
::D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&_device));

 

 

CommandQueue

 

CommandQueue는 외주 목록이다. 외주를 보낼 때 하나씩 보내면 비효율적이기 때문에 목록을 쌓아놨다가 한꺼번에 보낸다. ExcuteCommandList를 동해 GPU 큐에 Command들을 집어 넣는다. GPU에서 즉시 실행되는 것은 아니다.

 

_swapChain = swapChain;

	D3D12_COMMAND_QUEUE_DESC queueDesc = {};
	queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
	queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;

	device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&_cmdQueue));

	device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&_cmdAlloc));
	device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, _cmdAlloc.Get(), nullptr, IID_PPV_ARGS(&_cmdList));
	_cmdList->Close();

	device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&_resCmdAlloc));
	device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, _resCmdAlloc.Get(), nullptr, IID_PPV_ARGS(&_resCmdList));

	// CreateFence
	// - CPU와 GPU의 동기화 수단으로 쓰인다
	device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&_fence));
	_fenceEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);

 

CommandQueue를 초기화할 때는 CommandQueue를 생성하고 CommandList들을 할당하고 생성한다. 그리고 CPU와 GPU의 동기화를 위해 Fence를 생성한다.

 

Fence

 

CPU와 GPU가 병렬적으로 작동하기 위해서는 동기화가 필요하다. CPU가 GPU가 데이터를 처리하는 것을 기다리지 않고 CommandQueue에 다음 데이터를 넣어버리면 문제가 발생한다. 그것을 방지하는 것이 Fence이다. 

 

 

 

SwapChain

 

SwapChain은 더블 버퍼링을 사용한다. 후면 버퍼에서 프로그램의 계산을 진행하고 전면 버퍼와 교체한다. 버퍼는 RTV(RenderTargetView)로 관리하는데 View는 다른 개체에게 전달하기 위해 작성되는 정보이다.

 

	CreateSwapChain(info, dxgi, cmdQueue);
	CreateRTV(device);

 

SwapChain을 초기화할 때 SwapChain을 생성하고 전면 버퍼와 후면버퍼를 RTV(RenderTargetView)를 생성해 저장한다. 

 

 

 

DescriptorHeap

 

외주를 맡길 때 리소스를 어떤 용도로 사용하는지 꼼꼼하게 적어서 넘겨주는 용도이다. View라고도 하며 DX11의 RTV, DSV,  CBV, SRV, UAV 를 전부 포함한다. 

 

 

Root Signature

 

RootSignature은 CPU에서 GPU로 외주를 보낼 때 프로그램에 맞게 작성했는지 확인하는 계약서 / 결재와 같은 의미를 가진다. 어떠한 레지스터, 버퍼를 사용할지 작성한다.

 

 

ConstantBuffer

 

ConstantBuffer은 말 그대로 상수를 저장하는 버퍼이다. PushData로 CPU에서 GPU로  데이터를 전달하며 CBV(ConstantBufferView)로 전달한다.

 

	CreateBuffer();
	CreateView();

 

데이터를 저장하는 버퍼와 그것을 포장하는 뷰를 생성한다.

 

 

TableDescriptorHeap

 

Descriptor은 View와 같이 정보를 포함하는 자료구조이다. 정보를 전달할 때 CBV로 전달 할 수도 있고 TableDescriptorHeap처럼 Table을 만들어 통째로 전달할 수도 있다. 

 

 

DepthStencilBuffer

 

DepthStencilBuffer은 Depth와 Stencil을 가지고 있는 Resource의 버퍼이다. Depth는 렌더링할 사물의 깊이를 나타내고 Stencil은 따로 지정하는 값으로 선택적으로 렌더링할 수 있게 한다.

 

 

 

'그래픽스' 카테고리의 다른 글

[DX12] Normal Mapping  (0) 2022.02.28
[DX12] Projection, Screen 변환 행렬  (0) 2022.02.26
[DX12] World, View 변환 행렬  (0) 2022.02.26
[DX12] 좌표계 변환 행렬  (0) 2022.02.25
[DX12] 삼각형 그리기  (0) 2022.02.24