Swapchain은 DirectX에서 Backbuffer 역할을 하는 객체이다. Device Context의 Draw 류 함수를 호출해서 렌더링한 결과는 모두 SwapChain에 그려지고, 마지막으로 Swapchain의 Present() 함수를 호출해서 연결되어 있는 윈도우에 출력을 한다. Swapchain의 생성과정과 렌더링 과정을 정리해보겠다.
SwapChain
SwapChain은 DirectX에서 Double Buffering을 수행하는 IDXGISwapChain 타입의 객체이다. DXGI는 DirectX Graphics Infrastructure라는 뜻으로, Swapchain을 관리하는 것이 주 역할이다. GPU에서 생성된 프레임을 백버퍼에 저장하고, 프론트버퍼와 swap하는 역할이다.
SwapChain은 CreateDevice를 통해 만들어진 Device로부터 생성하거나 CreateDeviceAndSwapChain을 통해 생성할 수 있다.
1. CreateSwapChain() (Factory)
우선 DXGI_SWAP_CHAIN_DESC 구조체 변수를 선언해서 swap chain의 옵션 값을 설정한다. 주요 설정 값들에 주석을 설정해뒀다. BufferUsage에서 RenderTargetOutput 으로 설정하는 것은 이 swapchain을 render target 용도로 사용하겠음을 설정하는 것이다. RenderTarget은 Backbuffer라고 생각하면 된다. Format은 픽셀의 비트수를 설정하는 것으로, RGBA를 사용할 것이므로 DXGI_FORMAT_R8G8B8A8_UNORM으로 설정해준다 (RGBA 각각 8bit(=1byte), 총 32bit). 참고로 이 Format 값은 RGBA와 상관없이 한 픽셀을 몇 비트 포맷으로 사용할 것인지를 생각하여 설정하면 된다. 그리고, OutputWindow 값을 설정해서 출력할 윈도우 핸들값을 전달한다. 마지막으로 SwapEffect의 경우 DXGI_SWAP_EFFECT_DISCARD로 설정한다. 이는 swapchain의 Present()를 호출할 때 기존의 백버퍼 콘텐츠를 삭제한다는 뜻으로, 매 Tick마다 렌더링을 할 것이기 때문에 필요없는 기존 백버퍼 콘텐츠를 삭제해서 효율성을 높인다.
DXGI_SWAP_CHAIN_DESC Desc{};
Desc.BufferCount = 1; // BackBuffer 개수
Desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // Swapchain BackBuffer 용도
Desc.BufferDesc.Width = (UINT)m_Resolution.x;
Desc.BufferDesc.Height = (UINT)m_Resolution.y;
Desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 픽셀 Format (RGBA 32bit)
Desc.BufferDesc.RefreshRate.Numerator = 60; // 화면 갱신 속도, 분자
Desc.BufferDesc.RefreshRate.Denominator = 1; // 화면 갱신 속도, 분모
Desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; // 설정 안함
Desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; // 설정 안함
Desc.OutputWindow = m_hWnd; // 출력할 윈도우 지정. Swapchain이 출력까지 담당
Desc.Windowed = true; // 창모드 (true) / 전체화면
Desc.SampleDesc.Count = 1;
Desc.SampleDesc.Quality = 0;
Desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // 이전에 그려진 이미지를 저장하지 않음. 백버퍼 관리 방식
Desc.Flags = 0;
그 다음 Factory 객체에서 CreateSwapChain을 호출한다. Factory를 생성하는 방법 2가지를 정리하자면,
(1) DXGIDevice -> DXGIAdapter -> DXGIFactory
ComPtr<IDXGIDevice> pIDXGIDevice = nullptr;
ComPtr<IDXGIAdapter> pAdapter = nullptr;
ComPtr<IDXGIFactory> pFactory = nullptr;
// GUID (Global Unique ID) - 128 bit .. __uuiof() = 자료형의 id
m_Device->QueryInterface(__uuidof(IDXGIDevice), (void**)pIDXGIDevice.GetAddressOf());
pIDXGIDevice->GetAdapter(pAdapter.GetAddressOf()); // 범용적인 방법 (QueryInterface) : pIDXGIDevice->QueryInterface(__uuidof(IDXGIAdapter), (void**)&pAdapter);
pAdapter->GetParent(__uuidof(IDXGIFactory), (void**)pFactory.GetAddressOf());
// Factory에서 swapchain 생성
pFactory->CreateSwapChain(m_Device.Get(), &Desc, m_SwapChain.GetAddressOf());
(2) CreateDXGIFactory() - DXGI.lib
ComPtr<IDXGIFactory> pFactory = nullptr;
CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)pFactory.GetAddressOf());
// Factory에서 swapchain 생성
pFactory->CreateSwapChain(m_Device.Get(), &Desc, m_SwapChain.GetAddressOf());
참고로 ComPtr은 DirectX에서 사용되는 스마트 포인터라고 생각하면 된다. 나중에 한 번 정리해보겠다.
이렇게 swapchain이 생성되면 백버퍼도 생성되어, 백버퍼 텍스쳐를 받아오거나, Present()를 통해 backbuffer과 frontbuffer 내용을 swap할 수 있다.
[DirectX11] Graphics Pipeline 1 - Input Assembler (0) | 2024.08.24 |
---|---|
[DirectX11] Render Target View, Depth Stencil View (0) | 2024.08.23 |
[DirectX11] ComPtr (0) | 2024.08.23 |
[DirectX11] Device & Device Context (0) | 2024.08.18 |
[DirectX11] DirectX (0) | 2024.08.08 |