DirectX에서 제공하는 하위 수준의 API 세트이다. 위의 다이어그램에서 볼 수 있는 것처럼 DXGI에 직접 접근할 수도 있고 DirectX에서 제공되는 헤더를 통해서도 접근 가능하다. DXGI를 통해서 물리적으로 연결되어 있는 모니터와 같은 하드웨어를 열거할 수 있다.
Direct3D Device는 그래픽 드라이버, 하드웨어와 통신하는 개체이다. 디바이스 컨텍스트라는 개체를 사용하여 디바이스에게 명령을 내릴 수 있다.
그러나 후술하겠지만 DirectX12부터는 이렇게 디바이스 컨텍스트를 통해서 디바이스에게 명령을 내리는 방식을 폐기하고 Command Queue를 사용하여 명령을 처리하는 방식을 사용한다.
DirectX12에서는 ID3D12Device 클래스를 통해 접근할 수 있다.
DirectX12가 이전 버전에 비해서 변경된 것중 가장 두드러지는 것은 명령을 실행시키는 부분이라고 볼 수 있다.
DirectX11에서는 디바이스와 연결되어있는 컨텍스트가 존재했으나, Directx12부터는 이런 컨텍스트를 없에고 렌더링을 하기위해서 렌더링 API를 호출할 수 있는 명령 목록을 만든다. 명령 큐는 이렇게 실행할 명령 목록을 전달할 때 사용된다.
마소 공식 문서에서는 이렇게 변경했을 때 아래와 같은 이점들을 얻을 수 있다고 한다.
효율적으로 동기화를 관리할 수 있음, 명령을 일일이 컨텍스트에 접근해서 처리하는게 아니라 어떤 일을 시킬 지 명령 큐에 저장만 하면되니까.. 라고 이해하면 되나?
그 외에는 병렬 처리 증가 등등
CreateCommandQueue 함수를 통해서 생성하고 ExecuteCommandLists 함수를 사용하여 만든 명령 리스트를 실행할 수 있다.
후속 작업을 시작할 수 있는지 여부를 따지기위해, 즉 명령 큐의 작업 동기화를 위해서 Command Queue Fence라는 것을 사용할 수도 있다.
적절한 비유일지는 모르겠지만 컴퓨터가 모니터에 프레임을 그려주는 행위는 마치 학창시절 수업시간에 교과서 몇 페이지 한모퉁이에 졸라맨이 달리는 그림을 여러장 그려넣고 쫘르륵 펼치면서 보여주는 것과 유사하다.
그런데 생각해보면 우리가 게임을 플레이하면서 모니터를 바라볼 때 월드가 있고 키를 입력하면 캐릭터가 움직이면서 화면의 상태는 수시로 바뀐다. 분명히 상태가 실시간으로 바뀌는데 그에 대한 변화를 컴퓨터는 화면에 매우 빠른속도로 그려주고 있는 것이다, 여기서 들수있는 의문은 아무리 컴퓨터의 연산속도가 빠르다고 하더라도 그 그리는 과정이 왜 화면에 전혀 드러나지 않을까?이다.
Swap Chain이란 위에서 언급한바와 같이 화면들이 그려지는 일련의 순간들 즉 프레임을 표시하는 데 사용되는 버퍼의 컬렉션이다. 스왑 체인을 구현하는데에 사용되는 버퍼는 전면 버퍼와 후면 버퍼로 나뉘어지는데 이미 그려져서 사용자에게 보여지는 화면은 전면 버퍼에 고정되고 아직 그려지지 않은 화면들은 후면 버퍼에서 열심히 그린다. 그리고 후면 버퍼에서 그림을 모두 그리면 다시 전면 버퍼와 후면 버퍼의 역할을 맞바꾸게된다(Flipping), 사용자 입장에서는 이미 그려진 화면만 보게되고 후면 버퍼의 작업상황은 볼 일이 없으니 자연스럽게 화면이 이어지는 것을 볼 수 있게 되는것이다.
DirectX12에서 Swap Chain은 위와 같이 DXGI_SWAP_CHAIN_DESC를 통해 Swap Chain의 속성들을 설정해주고 DXGI에서 CreateSwapChain()함수를 통해 생성할 수 있다.
Swap Chain을 통해 화면을 나타낼 때는 Present() 함수를 호출하여 분사한다.
입력으로 들어가는 데이터의 컬렉션이다. 그러니까.. 내가 짠 프로그램에서 GPU에 보내는 데이터 유형? 방식? 이라고 이해하면 될 것 같다.
도형을 그릴 때 사용되는 정점 데이터가 포함되는 버퍼이다. 정점 버퍼에는 위치 좌표, 색상 데이터, 텍스처 좌표 데이터, 기본 데이터 등이 포함된다.
위의 코드는 마소에서 제공해주는 예제이다.
triangleVertices를 선언하여 그리고자하는 삼각형의 정보를 입력해주고, CD3DX12_RESOURCE_DESC::Buffer를 통해 버퍼의 구조를 정의해준뒤 아래의 CreateCommittedResource 함수를 통해 버퍼를 생성해준다.
https://vulkan-tutorial.com/Vertex_buffers/Index_buffer
Vulkan 튜토리얼에서 설명이 잘 되어있어서 참고했다.
삼각형 두개로 하나의 사각형을 만드는 경우를 생각해보자 오른쪽과 같이 Vertex Buffer만 사용하여 사각형을 구성한다고 가정하면 총 6개의 Vertex가 필요하게된다. 문제는 사각형의 좌측 상단, 우측 하단 정점의 경우 (v0, v5)(v2, v3)정점들의 위치정보가 겹치는 문제가 발생하게되는데 이렇게 겹치는 정보들은 하나의 정점으로 나타낼 수 있어야 비용상으로 이점을 얻을 수 있게 될 것이다.
따라서 정점 버퍼에 대한 포인터 배열인 인덱스 버퍼를 사용하여 위와같은 문제랄 해결할 수 있다. 필요한 정점 데이터 정보만 인덱스로 접근하여 사용하는 것이다.
DirectX12에서 제공하는 Index Buffer 구조체는 아래와 같다.
상수 데이터를 보내주는 버퍼이다. 주로 카메라 뷰, 월드 행렬과 같은 행렬 정보들을 보내서 각 정점에 곱하여 사용한다.