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

4. 교환 사슬(Swap Chain)과 더블 버퍼링(Double Buffering) 본문

computer graphics/DX12 book

4. 교환 사슬(Swap Chain)과 더블 버퍼링(Double Buffering)

scarecrow1992 2021. 1. 11. 20:48
  • 하나의 프레임 버퍼를 가지고 게임 화면을 표현하면 화면 깜빡임(Screen Flickering) 화면 찢어짐(Screen Tearing) 현상이 나타난다.
    • 화면 깜빡임 : 버퍼를 지우고 그릴경우 발생
    • 화면 찢어짐: 이미 그려진 화면 위에 덮어 쓸 경우 발생

화면 찢어짐 효과

 

 

더블 버퍼링(Double Buffering)

  • 화면 깜빡임 및 찢어짐 현상을 피하고자 사용되는 방법
  • 후면 버퍼(Back Buffer)와 전면 버퍼(Front Buffer) 2개의 프레임 버퍼의 교환을 통해 프레임 전환을 구현하는 기술
    • 전면 버퍼 : 화면을 표현
    • 후면 버퍼 : 다음 화면이 될 장면을 미리 저장
      • 후면버퍼는 텍스처 이므로 그 원소를 텍셀(texel)이라 부르지만 여기서는 그냥 픽셀(pixel)이라 부름
      • shader input이나 render taget output으로 쓰일 수 있음
  • 제시(presenting) : Direct3D에서 두 버퍼간의 역할 교환을 통해 프레임이 전환 되게 하는 것

 

교환 사슬(Swap Chain)

  • 플리핑을 하기 위해 전면/후면 버퍼 간의 관계를 형성하는 인스턴스
    • 플리핑(fliping) : 전면/후면 버퍼의 포인터를 서로 맞바꾸는것

 

 

IDXGISwapChain

  • Direct3D에서 SwapChain을 대표하는 인터페이스
  • 전면/후면 버퍼 텍스처를 담는다
  • 버퍼 크기 변경(IDXGISwapChain::ResizeBuffers()) 혹은 버퍼의 페레젠팅(IDXGISwapChain::Present())등을 위한 메서드 제공

 


 

교환 사슬의 서술과 생성(Describe and Create Swap Chain)

  • Swap Chain을 만드는 과정은 크게 서술과 생성으로 나뉜다.
    • 서술 : DXGI_SWAP_CHAIN_DESC 인스턴스의 멤버들을 생성하고자 하는 교환사슬에 맞게 설정한다.
    • 생성 : IDXGIFactory::CreateSwapChain 메서드를 호출해서 교환사슬을 생성한다.
  • DXGI object 이므로 factory를 통해 생성된다.

 

서술

DXGI_SWAP_CHAIN_DESC 구조체 인스턴스의 멤버들을 지금 생성하고자 하는 교환 사슬에 맞게 설정해야 한다. 이 구조체의 정의는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
typedef struct DXGI_SWAP_CHAIN_DESC {
  DXGI_MODE_DESC   BufferDesc;
  DXGI_SAMPLE_DESC SampleDesc;
  DXGI_USAGE       BufferUsage;
  UINT             BufferCount;
  HWND             OutputWindow;
  BOOL             Windowed;
  DXGI_SWAP_EFFECT SwapEffect;
  UINT             Flags;
} DXGI_SWAP_CHAIN_DESC;
cs

DXGI_SWAP_CHAIN_DESC의 각 필드에 대한 설명은 아래와 같다. 이 책의 수준에서 중요한 공통의 플래그들과 옵션들만 이야기 한다.

매개변수 기능
BufferDesc 이 구조체는 생성하고자 하는 후면 버퍼의 속성들을 서술한다.
지금 수준에서 중요한 속성은 너비(Width)와 높이(Height) 그리고 픽셀형식(Format)이다.
SampleDesc 다중표본화 표본 개수와 품질 수준을 서술하는 구조체이다.
단일표본화를 사용하고 싶으면 표본 개수를 1, 품질 수준을 0으로 설정한다.
BufferUsage 후면 버퍼의 surface usage 및 CPU access option에 대해 서술한다.

후면 버퍼에 렌더링할 것이므로 이 멤버에는 DXGI_USAGE_RENDER_TARGET_OUTPUT을 지정한다.
BufferCount 교환 사슬이 사용할 버퍼의 갯수이다.
이중 버퍼링에서는 2를 지정한다.
OutputWindow 렌더링 결과가 표시될 창의 핸들

CreateWindow 함수의 반환 값을 넣는다.
Windowed 창 모드이면 true, 전체화면 모드이면 false
SwapEffect 이 멤버에는 DXGI_SWAP_EFFECT_FLIP_DISCARD를 지정한다.
Flags 추가적인 플래그들, 여기에 DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH를 지정하면, 응용 프로그램이 전체 화면으로 전환될 때 Direct3D는 응용 프로그램 창의 현재 크기에 가장 잘 맞는 디스플레이 모드를 선택한다. 이 플래그를 지정하지 않으면, 응용 프로그램이 전체 화면으로 전환될 때 Direct3D는 현재 데스크톱 디스플레이 모드를 사용한다.

 

 

생성

교환사슬을 서술하는 구조체를 다 채웠으면, IDXGIFactory::CreateSwapChain 메서드를 호출해서 교환 사슬을 생성한다.

1
2
3
4
5
HRESULT CreateSwapChain(
  IUnknown             *pDevice,
  DXGI_SWAP_CHAIN_DESC *pDesc,
  IDXGISwapChain       **ppSwapChain
);
cs
매개변수 기능
IUnknown Direct3D 11 및 초기버전 : swap chain을 위한 Direct3D device 포인터
Direct3D 12 : command queue 포인터
NULL을 전달해선 안된다.
DXGI_SWAP_CHAIN_DESC DXGI_SWAP_CHAIN_DESC 서술자 인스턴스의 포인터
NULL을 전달해선 안된다
IDXGISwapChain CreatSwapChain이 만드는 SwapChain 을 받아올 포인터

 

다음 코드는 이 책의 예제 프레임 워크에서 교환사슬을 생성하는 방법을 보여준다. 이 함수가 여러 번 호출되어도 문제가 없도록 설계되어 잇음을 주목하라. 이 함수는 기존 교환 사슬을 먼저 해제한 후 새 교환 사슬을 생성한다. 이 덕분에 응용 프로그램은 이전과는 다른 설정으로 교환 사슬을 다시 생성할 수 있다. 특히, 실행 도중에 다중표본화 설정을 변경할 수 있다.

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
void D3DApp::CreateSwapChain()
{
    // Release the previous swapchain we will be recreating.
    mSwapChain.Reset();
 
    DXGI_SWAP_CHAIN_DESC sd;
    sd.BufferDesc.Width = mClientWidth;
    sd.BufferDesc.Height = mClientHeight;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferDesc.Format = mBackBufferFormat;
    sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    sd.SampleDesc.Count = m4xMsaaState ? 4 : 1;
    sd.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.BufferCount = SwapChainBufferCount;
    sd.OutputWindow = mhMainWnd;
    sd.Windowed = true;
    sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
    sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
 
    // Note: Swap chain uses queue to perform flush.
    ThrowIfFailed(mdxgiFactory->CreateSwapChain(
        mCommandQueue.Get(),
        &sd, 
        mSwapChain.GetAddressOf()));
}
cs

 

 

DXGI_MODE_DESC 형식은 또 다른 구조체로, 다음과 같이 정의되어 있다.

1
2
3
4
5
6
7
8
typedef struct DXGI_MODE_DESC {
  UINT                     Width;
  UINT                     Height;
  DXGI_RATIONAL            RefreshRate;
  DXGI_FORMAT              Format;
  DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
  DXGI_MODE_SCALING        Scaling;
} DXGI_MODE_DESC;
cs

 

 

 

https://docs.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgifactory-createswapchain

MSDN에 의하면, Direct3D 11.1 이후로 swap chain을 만들기 위해 CreateSwapChain 함수의 사용을 권장하지 않으며, 대안으로 CreateSwapChainForHwndCreateSwapChainForCoreWindow, or CreateSwapChainForComposition 사용을 제시한다.

 

 

 

 

'computer graphics > DX12 book' 카테고리의 다른 글

4. 자원과 서술자 / Descriptor Heap, RTV, DSV  (0) 2021.01.11
4. 깊이 버퍼링(Depth Buffer)  (0) 2021.01.11
4. 텍스처 형식  (0) 2021.01.11
4. COM(Component Object Model)  (0) 2021.01.11
4. Direct3D 초기화 - 개요  (0) 2021.01.11
Comments