2020 이전/프로그래밍 외적인 것들

Vulkan 튜토리얼 0. Overview

이상해C++ 2019. 6. 12. 01:58

처음 불칸을 들었을때 불곰이라고 잘못들었던 기억이 있다.

영어공부도 할 겸사겸사 튜토리얼 야매번역

 

불칸 API는 그래픽 하드웨어 단에서의 최대의 제어권을 주기 위한 많은 파라미터를 가진 다소 장황한 API이다. 이것은 텍스처를 생성하는 것과 같은 기본적인 동작에도 매번 많은 단계들을 반복하게 한다. 이 튜토리얼을 통하여 보조할 수 있는 함수들을 생성한다.   

원문: https://vulkan-tutorial.com/Overview

 

Overview - Vulkan Tutorial

This chapter will start off with an introduction of Vulkan and the problems it addresses. After that we're going to look at the ingredients that are required for the first triangle. This will give you a big picture to place each of the subsequent chapters

vulkan-tutorial.com

0. Overview

 

Origin of Vulkan

이전의 그래픽 API처럼 벌칸은 GPU에 대한 크로스 플랫폼으로 디자인되었습니다. 이러한 API의 대부분의 문제점은 프로그래머들은 정점 데이터들을 정해진 표준 포맷에 따라 제공해야하며, GPU 제조사들이 정의한대로 셰이딩과 라이팅 옵션을 제공해야 한다는 것입니다. 

 

그래픽 카드 아키텍쳐가 발전함에 따라, 그래픽 카드들은 프로그래밍 가능한 기능들을 제공하기 시작했습니다. 이 모든 새로운 기능들은 기존에 존재하던 API들에 통합되어야 했습니다. 프로그래머의 의도를 최신 그래픽스 아키텍쳐로 매핑하기 위해 그래픽 드라이버 단에서는 다소 덜 이상적인 추상화와 많은 추측을 남기게 되었습니다. 이는 왜 이렇게 많은 드라이버들이 때로는 상당한 마진을 감수하고 게임 퍼포먼스를 개선하기 위해 업데이트를 하는가에 대한 이유입니다. 이러한 드라이버들의 복잡성 때문에 어플리케이션 개발자들은 셰이더의 syntax와 같은 벤더간 불일치성을 다뤄야할 필요가 있습니다. 이러한 새로운 특징 외에도, 지난 10년동안에는 강력한 그래픽 하드웨어를 갖춘 모바일 디바이스들이 나왔습니다. 이러한 모바일 GPU는 모바일의 에너지/베터리 요구사항에 따른 다른 아키텍처를 가지고있습니다. 타일 렌더링이 프로그래머들에게 더 많은 제어권을 제공함으로써 향상된 퍼포먼스를 끌어낸 예입니다. 오래된 API에 의한 또 다른 한계는 CPU 병목을 야기할 수 있는 멀티 스레딩 지원입니다.

 

불칸은 처음 고안부터 이러한 문제를 해결하기 위한 현대 그래픽스 아키텍처로 디자인 되었습니다. 불칸은 프로그래머들이 명확하게 그들의 의도를 구체화할 수 있게끔 다소 장황한 API를 사용하는 것을 허용함으로 드라이버 오버해드를 줄이고 멀티 스레드가 병렬적으로 명령을 작성하고 제출할 수있게 허용합니다. 불칸은 단일 컴파일러로 표준화된 바이트 코드 포맷으로 전환하여 셰이더 컴파일에 있어서 불일치성을 줄였습니다. 마지막으로 그래픽스와 컴퓨팅을 단일 API로 통합함으로써 모던 그래픽 카드의 범용 처리 작업(GPGPU)을 지원합니다.  

 

be at the mercy of sth *(내가 제어할 수 없는)~에 거역할 수 없다.

with regards to : alternate version of the same phrase

 

 

What it takes to draw a triangle

1. Instance and physical device selection(인스턴스와 물리 디바이스 선택)

불칸 어플리케이션은 VkInstance를 통해 불칸API를 세팅하는 것으로 시작됩니다. 인스턴스는 유저의 어플리케이션과 유저가 사용할 API익스텐션을 describing 하는것으로 생성됩니다. 인스턴스를 생성한 뒤, 하드웨어가 불칸을 지원하는지 알 수 있고(you can query for Vulkan supported hardware) 작업할 수 있는 하나 이상의 VkPhysicalDevice을 선택할 수 있습니다. VRAM 사이즈와 같은 속성들과 원하는 디바이스들을 선택하기위한 디바이스 capability들을 정할 수 있습니다. 

 

2.  Logical device and queue families(로컬 디바이스와 큐 집합)

사용할 하드웨어 디바이스를 선택하면, 멀티 뷰포트렌더링, 64bit float 사용과 같은 VkPhysicaldeviceFeatures를 자세히 명세하는 VkDevice(논리 디바이스)를 생성해야합니다. 또한 어떤 queue families를 사용할지 정의해 줘야합니다. draw command나 memory operation과 같은 불칸의 대부분의 기능들은 VkQueue에 제출되는것으로 실행됩니다. 큐들은  queue families에 의해 할당됩니다. 각각의 queue family는 특정한 작업수행을 지원합니다. 예를 들어 그래픽스, 컴퓨팅, 메모리 전송과 같은 기능들을 각각 지원하는 queue family가 존재할 수 있습니다. queue family의 가용성은 피지컬 디바이스 선택에서 구별되는 요소가 될 수 있습니다. 불칸을 지원하는 디바이스는 그래픽 기능을 제공하지 않을 수 있지만 불칸을 지원하는 모든 그래픽 카드들은 일반적으로 queue opertaion 전부를 지원합니다.   

 

3. Window surface and swap chain(윈도우 서피스와 스왑 체인)

offscreen rendering에만 관심있다고 해도 렌더된 이미지를 표시할 창을 생성해야합니다. GLFW와 SDL과 같은 native platform API또는 라이브러리들로 창을 생성할 수 있습니다. 이 튜토리얼에서는 GLFW를 사용할 것입니다.

 

윈도우 창에서 실질적으로 렌더하기위해 두개의 요소가 더 필요합니다. 윈도우 서피스인 VkSufraceKHR과 스왑체인인 VkSwapChainKHR입니다. KHR postfix는 이 오브젝트가 불칸 익스텐션의 일부분이라는 것을 뜻합니다. Vulkan API 그 자신은 완전한 플랫폼 agnostic이며 이것은 윈도우 매니저와 interact하기 위해 표준화된 WSI 확장을 사용해야하는 이유입니다. 서피스는 렌더하는 윈도우에 대한 크로스 플랫폼 추상입니다. 일반적으로 native 윈도우 핸들에 대한 레퍼런스를 제공하는 것으로 인스턴스화 됩니다. (윈도우의 HWND) 다행히, GLFW 라이브러리는 이러한 플랫폼을 다루기위한 내장 함수가 있습니다. 

 

스왑체인은 렌더타겟의 집합입니다. 이것의 기본적인 목적은 우리가 현재 렌더링하고 있는 이미지가 현재 스크린에 표시되어있는 이미지와 다른 이미지임을 보장하는 것입니다. 언제나 완전히 그려진 이미지만을 보여주는 것은 중요합니다. 프레임을 매번 그리기위해 스왑체인에게 렌더할 이미지를 제공해야할지 "ask"해야합니다. 프레임이 전부 그려지면, 이미지는 스왑체인으로 부터 스크린에 그려지기위해 반환도비니다. 렌더 타겟의 개수와 완성된 이미지를 스크린에 present하는 조건은 present mode에 따릅니다. 대부분의 present modes는 더블 버퍼링(vsync)와 트리플 버퍼링입니다. 스왑체인 생성 챕터에서 더 자세히 알아볼 예정입니다.

 

어떤 플랫폼들은 VK_KHR_display와 VK_KHR_display_swapchain 확장을 통해 윈도우 매니저와 interact하지 않고도 직접 디스플레이에 렌더할 수 있습니다. 이는 전체 스크린을 대표하는 서피스를 생성할 수 있게하거나 고유한 윈도우 매니저를 구현하는데 사용될 수 있습니다.

 

4. Image views and framebuffers(이미지 뷰와 프레임 버퍼)

스왑체인으로부터 얻어온 이미지를 그리려면 VkImageView와 VkFramebuffer로 래핑해야합니다. 이미지 뷰는 사용되는 이미지의 특정 부분을 참조하고 프레임버퍼는 color, depth뭉 stencil 타겟으로 사용되는 image view를 참조합니다. 스왑체인에는 많은 다른 이미지들이 있을 수 있기 떄문에, 이미지뷰와 프레임버퍼를 미리 작성하고 그릴 때 하나를 선택합니다.

 

5. Render passes(렌더 패스)

불칸에서의 렌더패스들은 렌더링 중 사용되는 이미지 type의 사용 방법, 내용을 처리하는가에 대한 방법을 설명합니다. 우리의 삼각형 렌더링 프로그램에서는 불칸에게 컬러 타겟으로 단일 이미지를 사용할것이며 그리기 작업 직전에 단색으로 클리어할 것을 알려줄 것입니다. 렌더 패스는 이미지 type만을 설명하지만, VkFrambuffer는 실질적으로 슬롯에 이런 특정 이미지를 바인딩합니다.

 

6. Graphics pipeline(그래픽 파이프라인)

불칸의 그래픽 파이프라인은 VkPipeline 오브젝트를 생성하는것으로 설정됩니다. 뷰포트 사이즈와 깊이 버퍼 작업 같은 그래픽 카드의 구성 가능한 state와 VkShaderModule 오브젝트를 사용하는 프로그래밍 가능한 state를 설명합니다. VkShaderModule 오브젝트들은 셰이더 바이트 코드로부터 생성됩니다. 또한 드라이버는 랜더패스를 참조하여 지정된 파이프라인에 어떤 렌더 타겟들이 사용되어야 할지 알아야합니다.  

 

기존 API에 비해 불칸에서 가장 두드러지는 특징중 하나는 그래픽 파이프라인의 거의 모든 구성은 사전에 설정되어야 하는 것입니다. 즉 다른 셰이더를 갈아끼우거나 버텍스 레이아웃을 약간이라도 바꿔야할 경우, 전체 그래픽 파이프라인을 다시 생성해야합니다. 그러므로 렌더링 작업에 필요한 모든 다른 조합에 대해 사전에 많은 VkPipeline 오브젝트들을 생성해두어야 합니다. 뷰포트 크기와 클리어 컬러와 같은 일부 기본적인 구성에 대해서는 동적으로 변경할 수 있습니다. 모든 state 또한 명시적으로 설명되어야합니다. 예를 들어 디폴트 색상 혼합 스테이트는 없습니다. 

 

The good news is that because you're doing the equivalent of ahead-of-time compilation versus just-in-time compilation

좋은 점은 just-in-time 컴파일에 해아할 작업을 ahead-of-time 컴파일에 수행하기 때문에 드라이버에 대한 최적화 기회가 더 많으며 런타임 퍼포먼스는 더 예측 가능해질것입니다. 다른 그래픽 파이프라인으로의 전환같은 큰 state change는 명시적으로 만들어지기 때문입니다.  

 

7. Command pools and command buffers(커맨드 풀과 커맨드 버퍼)

이전에 언급된 것처럼, 그리기 작업과 같이 실행되어야하는 불칸의 많은 작업들은 큐에 제출되어야합니다. 이러한 작업들은 큐에 제출되기 전 VkCommandBuffer에 먼저 기록되어야합니다. 이러한 커맨드 버퍼는 특정 큐 집합과 연관된 VkCommandPool로부터 할당됩니다. 단순한 삼각형 하나를 그리기 위해서, 다음과 같은 커맨드 버퍼를 작성해야합니다. 

 

- 렌더 패스를 시작한다.

- 그래픽 파이프라인을 바인드한다.

- 3개의 정점을 그린다.

- 렌더 패스를 종료한다.

 

프레임버퍼의 이미지는 스왑 체인이 제공할 특정 이미지에 따라 다르므로, 가능한 각 이미지에 커맨드 버퍼를 작성하고 그리는 작업을 수행할 때 적절한 이미지를 선택합니다. 대안으로 매 프레임마다 커맨드 버퍼를 작성할 수 있지만 효율적이지 않습니다. 

 

8. Main loop(메인 루프)

그리기 명령어들이 커맨드 버퍼로 래핑되었다면 메인루프는 꽤 간단합니다. 먼저 vkAcquireNextImageKHR로 스왑체인으로부터 이미지를 획득합니다. vkQueueSubmit으로 이미지에 대한 적절한 커맨드 버퍼를 선택하고 실행할 수 있습니다. 마지막으로 vkQueuePresentKHR로 스크린에 출력할 이미지를 스왑 체인에게 돌려줍니다.

 

큐에 제출되는 작업들은 비동기적으로 실행됩니다. 그러므로 실행 순서를 지키기위한 세마포어와 같은 싱크 객체를 사용해야합니다. 그리기 커맨드 버퍼의 실행은 이미지 획득이 완료되기 전까지 기다려야합니다. 그렇지 않으면 화면에 표시하기 위해 읽어들이고 있는 이미지 위에 그려지는 일이 발생할 수 있습니다. vkQueuePresentKHR 호출은 렌더링이 완료될 때까지 기다려야할 필요가 있습니다. 렌더링이 완료된 뒤 신호를 받아줄 두번째 세마포어를 사용합시다.

 

요약

- VkInstance를 생성한다.

- 지원하는 그래픽 카드를 선택(VkPhysicalDevice)

- drawing과 presentationd을 위한 VkDevice와 VkQueue를 생성한다.

- 윈도우, 윈도우 서피스, 스왑 체인을 생성한다.

- 스왑체인 이미지를 VkImageView로 래핑한다.

- 렌더 타겟을 지정하고 사용방법을 지정하는 렌더 패스를 생성한다.

- 렌더 패스를 위한 프레임 버퍼를 생성한다.

- 그래픽 파이프라인을 설정한다.

- 가능한 모든 스왑체인 이미지에 그리기 명령어들로 구성된 커맨드 버퍼를 할당하고 작성합니다.

- 획득한 이미지에 그리고, 스왑체인에 그려준 이미지를 돌려줍니다.

 

API concepts(작성중...)

Coding conventions

모든 불칸 함수, enumeration, 구조체들은 불칸 SDK에 포함된 vulkan.h 헤더에 정의되어있습니다. 

함수는 "vk" prefix를 가지고 구조체와 enum과 같은 타입들은 "Vk" prefix를 가집니다.  enum 밸류는 "VK_" prefix를 가집니다. API는 함수에 파라미터를 제공하기 위해 구조체를 많이 사용합니다. 불칸의 많은 구조체들은 sType 멤버에 명시적으로 타입을 지정하게 됩니다. 

 

Validation layers