Intro.

vulkan은 OpenGL을 만든 크로노스 그룹에서 Modern GPU Architecture에 맞게 새롭게 설계한 API이다. 실제 프로그래머를 위한 SDK는 LunarG에서 제공한다.
기존 OpenGL의 경우 single thread를 가정해서 만들었기 때문에 대부분의 변수가 전역변수로 선언된 상태로 멀티 스레딩을 이용할 경우 문제가 발생한다.
또한 매우 추상화 되어있어 해당 함수에서 어떤 작업을 하는지 알 수 없다는 문제가 있다.
Vulkan은 OpenGL에서 추상적으로 해주던 작업들을 Application 단으로 올려서 low-level Control을 가능하게 했다.
또한 command queue 개념을 이용하여 멀티 스레딩으로 작업을 가능하게 하였다.
대부분의 HW단에서 작업하던 것을 SW 단으로 올리면서 프로그래머의 능력에 따라 성능 차이가 많이 나게 된다.
Vulkan build 환경 구축
Vulkan SDK 설치 (https://vulkan.lunarg.com/app/download )
glm 설치 (선택) (https://glm.g-truc.net/0.9.8/index.html)
Visual Studio Setting

라이브러리 폴더 (~/Lib) 링크 추가

입력 라이브러리(vulkan-1.lib) 설정

Include (~/Include, 헤더) 폴더 추가
Vulkan 아키텍처

Vulkan의 아키텍처는 다음과 같다.
Instance
- Vulkan과 application 간의 연결을 하기 위한 객체이다. Vulkan driver에게 application 정보를 넘겨준다.
- OpenGL의 Context와 유사한 역할
- PC에 설치된 vulkan에 대한 Handle로써, 운영 체제 및 드라이버의 인터페이스 역할을 한다.
- App의 정보와, instance layer, instance extension의 정보들로 구성한다.
- Layer
- Vulkan API의 호출의 상태를 검사하고, 디버깅 메시지를 캡처하며, 성능 문제를 식별하는 등의 역할을 한다.
- Vulkan은 성능의 극대화를 위해서 기본적으로 Error code를 보여주지 않는다. 따라서 layer를 통해 디버깅을 해야한다. -> Vulkan Configuration 프로그램을 통해 강제로 validation layer를 사용하여 error를 출력할 수 있다.
- Vulkan의 layer 종류 : validation layer, debugging layer, ...
- validation layer : Vulkan API 호출을 검증한다. 스레드 동기화, 메모리 오버플로우 등
- debugging layer : vulkan 호출에 대한 디버깅 정보를 제공한다.
- Instance extension
- Vulkan의 코어와는 별도로 특정 플랫폼(ex> Windows, Linux, Android, Nvidia, AMD, ...)에만 작동하는 확장같은 기능을 사용가능하다. ( OS 수준의 확장 / Debug )
- 예를 들어, Windows 운영체제에서 프로그램 창을 띄울텐데 이 창에 대한 핸들을 연결하는 역할과 같은 일을 한다.

Physical Device
- Instance를 통하여 physical device를 선택
- available한 GPU의 Handle을 의미한다.
(Logical) Device
- Device는 physical device로 부터 Logical Device로 생성이 가능하며 1개의 physical device로부터 여러 개의 logical device를 생성할 수 있다.
- Vulkan program과 GPU(physical device) 간의 논리적인 연결을 담당하는 handle이다. 이를 통해서 추상적으로 같은 method를 통해서 모든 GPU에 대해서 처리할 수 있다.
- logical device는 physical device에 대한 설정을 포함한다.
- ex> swapchain 설정 여부, queue를 얼마나 사용할 것인지
- instance에서 instance extension를 추가하듯이, device extension을 통해서 추가적인 구성을 설정한다. ( GPU Specific HW 수준의 확장 )
- ex> swapcahin

- 몇몇 extension은 추가적인 구조체가 필요한데, 이때 구조체에서 pNext 변수로 가르키면 되고, pNext 변수가 가르키는 구조체에서 (추가적으로 구조체가 필요하면) 다시 pNext로 필요 구조체를 가르키면 된다.
Queue
- vulkan의 명령어들은 command buffer에 저장되어, command buffer를 한 번에 queue에 제출한다.
- Physical device에는 다수의 다중타입 queue들이 존재한다.
Queue Family
- 서로 다른 queue type을 queue family로 구분한다.
- 각각의 queue family는 수행할 수 있는 명령어가 정해져있다. 범용성 queue family보다 특화 queue family가 빠를 수 있다.
- 아래 vulkan hardware capability viewer로 본인의 GPU에서의 queue family의 종류와 개수를 확인할 수 있다.
- Flags를 통해 각 queue family가 수행할 수 있는 명령어를 확인할 수 있다. ex> TRANSFER_BIT : GPU-CPU 데이터 통신
- vulkan hardware capability viewer 설치

나머지 용어는 다른 tutorial에서 설명한다.
API Naming Convention
Prefix
- VK : Define
- Vk : Type structure
- vk : Function
- p/ PFN/ pfn : 포인터 및 함수 포인터
- vkCmd : command buffer에 저장할 command
(Instance) Extension
- Type structure / 함수
- VkSurfaceFormatKHR() / vkDestorySurfaceKHR()
- 접미사로 instance extension이 들어간다. ex> KHR : 크로노스 그룹, EXT : Multi-vendor(여러 회사 협약), NV : NVidia, AMD, INTEL
- Define
- VK_KHR_mirror_clamp_to_edge / VK_EXT_debug_marker
- Define할 때는 prefix 뒤에 instance extion이 들어간다. ex> KHR, EXT
https://github.com/daemyung-archive/ogl_to_vlk/blob/master/chapter03/main.cpp
예제 코드는 장대명님의 github 코드를 참고하길 바란다.
uint32_t count{ 0 };
vkEnumeratePhysicalDevices(instance_, &count, nullptr);
vector<VkPhysicalDevice> physical_devices;
physical_devices.resize(count);
vkEnumeratePhysicalDevices(instance_, &count, &physical_devices[0]);
코드를 보면 대부분 다음과 같은 형태를 취한다.
먼저 해당 데이터에 대한 목록을 불러오는데 데이터 공간을 주지 않고 개수만 구한 후, 데이터 공간을 할당 후 데이터를 얻어오는 방식으로 데이터를 얻어온다.
그 후 데이터를 만드는데 사용된다.
전체 코드의 구조를 보면 다음과 같다.
1. physical device 선택
2. physical device로부터 queue family 정보 획득
3. logical device를 만들 때 어떤 physical device를 선택할지와, queue family의 개수는 어떻게 할지 설정하여 만든다.