Swap chain

We now have the device, but we do not have anything we can render to yet. In DirectX 11, a swapchain is created using DXGI, and the DirectX 11 device is made the owner of this swapchain. A swapchain represents a number of backbuffers managed by DXGI, allowing access to a single buffer at a time, while another buffer is shown inside a window or covering the entire screen.

In this case, we would like to create a swap chain for a window, so we use the CreateSwapChainForHwnd function of IDXGIFactory4 to create a swapchain for the window we would like our frames to be rendered to.

IDXGISwapChain1* swapChain;
result = renderer->dxgiFactory->lpVtbl->CreateSwapChainForHwnd(
    renderer->dxgiFactory,
    (IUnknown*)renderer->device,
    window,
    &(DXGI_SWAP_CHAIN_DESC1){
        .Width  = 0,
        .Height = 0,
        .Format = DXGI_FORMAT_R8G8B8A8_UNORM,
        .Stereo = FALSE,
        .SampleDesc = {
            .Count = 1,
        },
        .BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
        .BufferCount = FRAME_BUFFER_COUNT,
        .Scaling     = DXGI_SCALING_STRETCH,
        .SwapEffect  = DXGI_SWAP_EFFECT_FLIP_DISCARD,
        .AlphaMode   = DXGI_ALPHA_MODE_UNSPECIFIED,
        .Flags       = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH,
    },
    NULL,
    NULL,
    &swapChain
);

if ( !SUCCEEDED ( result ) )
    RETURN_ERROR(-1, "CreateSwapChainForHwnd failed (0x%08X)", result );

result = swapChain->lpVtbl->QueryInterface (
    swapChain,
    &IID_IDXGISwapChain3,
    &renderer->dxgiSwapChain
);

if ( !SUCCEEDED ( result ) )
    RETURN_ERROR(-1, "QueryInterface failed (0x%08X)", result );

ID3D11Texture2D* tex;
result = renderer->dxgiSwapChain->lpVtbl->GetBuffer (
	renderer->dxgiSwapChain,
	0,
	&IID_ID3D11Texture2D,
	&tex
);
if ( !SUCCEEDED ( result ) )
	RETURN_ERROR(-1, "GetBuffers failed (0x%08X)", result );
result = renderer->device->lpVtbl->CreateRenderTargetView (
	renderer->device,
	(ID3D11Resource*)tex,
	&(D3D11_RENDER_TARGET_VIEW_DESC){
		.Format = DXGI_FORMAT_R8G8B8A8_UNORM,
		.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D,
	},
	&renderer->rtv
);
if ( !SUCCEEDED ( result ) )
	RETURN_ERROR(-1, "CreateRenderTargetView failed (0x%08X)", result );
tex->lpVtbl->Release ( tex );

We specify 0 for the Width and Height properties in DXGI_SWAP_CHAIN_DESC1 to create a swap chain of the same size as the window, and specify DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH to be allowed to switch between full screen and windowed later. We also specify the amount of buffers in the swap chain using BufferCount.

In BufferUsage we must specify DXGI_USAGE_RENDER_TARGET_OUTPUT in order to be allowed to render to it. In addition, DXGI_USAGE_SHADER_INPUT if use as a texture is desired, but we will not require this behaviour.

The SwapEffect field can include a variety of swap methods, as seen here. The flip methods should be preferred if available, as there is less latency and overhead involved in the flip swap effects than with the other swap methods available. Do note the limited availability of flip modes however; DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL is only supported in Windows 8 and up, while DXGI_SWAP_EFFECT_FLIP_DISCARD is only supported since Windows 10.