주의 : 이 문서는 초심자 튜토리얼이 아닙니다. 기본 개념 정도는 안다고 가정합니다. 초심자는 [ Vulkan Tutorial ] 이나 [ Vulkan Samples Tutorial ] 을 보면서 같이 보시기 바랍니다.

주의 : 완전히 이해하고 작성한 것이 아니므로 잘못된 내용이 있을 수 있습니다.

주의 : 이상하면 참고자료를 참조하십시오.

정보 : 본문의 소스 코드는 Vulkan C++ exmaples and demos 를 기반으로 하고 있습니다. 



샘플 선정


직접 코드를 작성할까 아니면 이미 나와 있는 샘플을 사용할까 고민하다가, 전문가 중 한 명이 작성한 샘플을 사용하는 것이 좀 더 나은 신뢰성을 제공할 것이라는 생각에 후자를 선택했습니다( 틀려도 내탓하지 마!! ).


이 시리즈를 작성하면서 사용할 샘플은 Sascha Willems 의  [  Vulkan C++ exmaples and demos  ] 입니다. 이 분이 여러 가지 Vulkan Sample 을 만드셨더군요. 특히 이 분이 작성한 [ VulkanCapsViewer ] 는 매우 쓸만한 툴입니다. 이 분에 대해서 궁금하시다면 [ 개인 블로그 ] 를 확인하세요. 


VulkanCapsViewer 의 릴리스 빌드는 [ Vulkan GPU Info ]에서 받으실 수 있습니다. 이 시리즈를 진행하다가 제가 가진 디바이스의 Extension 같은 것들을 확인할 때 이 툴을 사용할 것입니다.


어쨌든 설명에 필요하다면 앞에서 언급한 샘플을 수정해 가면서 진행을 하도록 하겠습니다.


레이어 리스트 확인


VulkanCapsViewer 를 실행하고 가장 오른쪽 "Vulkan" Tap  에서 "Layer" 탭을 선택하면 현재 API 와 Device 에 의해 지원되는 Layer 들의 목록을 확인할 수 있습니다. 이 작업을 하다가 "Upload" 를 눌러 처음으로 "GeForce GTX 980" 을 Database 에 등록하는 영광(?)을 얻었습니다.


그림1. CapsViewer 로 살펴 본 레이어 리스트.


매우 많은 레이어를 지원하고 있네요. 문제는 이것을 어떻게 활성화하느냐는 겁니다.


명시적( Explicit ) 레이어와 묵시적( Implicit ) 레이어


Windows 에서 Vulkan loader 가 두 종류의 레이어를 검색합니다. 하나는 명식적 레이어와 묵시적 레이어입니다. 


Vulkan loader 는 다음과 같은 레지스트리를 검색해서 레이어의 목록을 찾아냅니다.


HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\ExplicitLayers

HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\ImplicitLayers


이 레지스트리 값은 DWORD 형으로서 키 이름이 레이어 파일의 경로를 담고 있습니다.


그림2. 명시적인 레이어 리스트.


그림3. 묵시적인 레이어 리스트.


명시적인 레이어는 사용자의 요청에 의해 VkInstance 생성시에 로드되고, 묵시적인 레이어는 사용자의 요청없이 특정 상황에서 묵시적으로 로드됩니다.


각 레이어를 위한 json 파일은 레이어를 로드하기 위한 여러 가지 정보를 담고 있으며, "VkLayer_core_validation.json" 파일을 살펴 보면 다음과 같이 되어 있습니다.



그리고 어떤 경우에는 여러 레이어를 하나로 묶어서 로드하는 경우도 있습니다. "VkLayer_standard_validation.json" 이 그런 경우입니다. 대부분의 샘플들을 보면 이 레이어를 사용해서 디버그 정보를 뽑습니다.



묵시적인 경우가 필요한 것인가라는 의문이 들 수 있겠지만, RenderDoc 와 같은 프로우파일러( profiler )를 사용해 보면 실시간에 애플리케이션을 어태치( Attach )하는 경우가 있습니다.


그림4. RenderDoc 의 "Attach to Running Instance" 메뉴.


이 경우에는 이미 애플리케이션이 시작되었고 VkInstance 도 생성된 상황이므로 명시적으로 레이어를 요청할 수가 없습니다. 그러므로 RendeDoc 같은 툴들이 이를 묵시적으로 로드할 수 있는 방법이 필요한 것입니다.


레이어 활성화하기


레이어를 활성화하는 방식은 여러 가지가 있지만, 여기에서는 프로그램 코드 내에서 명시적으로 활성화하는 방법에 대해서만 다루도록 하겠습니다. 명령창에서 환경변수 통해 레이어를 활성화하거나 레이어 설정 파일을 미리 만들어 놓는 등의 작업들에 대해서는 [ 1 ] 에서 확인하시기 바랍니다.


샘플의 "base/VulkanDebug.cpp" 파일에 보면 다음과 같이 디버거를 위해 사용할 레이어 이름을 설정하는 것을 보실 수 있습니다. 이 이름은 json 파일에 있는 "name" 오브젝트의 값입니다.



주의하실 점은 [ Vulkan 은 왜 C 로 구현되었을까? ] 에서 언급했듯이 Vulkan 은 C ABI 를 사용하므로 결국 ANSI 문자열을 사용한다는 겁니다. 요새 대부분은  Unicode( UTF-8 ) 문자열 프로젝트를 사용하기 때문에 이에 주의하셔야 합니다. 왠만하면 ANSI 와 UTF8 사이의 변환을 자유롭게 할 수 있는 유틸리티 클래스를 만들고 작업을 시작하시는 것이 좋습니다.


어쨌든 이러한 목록은 VkInstance 를 생성할 때 명시적으로 지정됩니다. 27 ~ 28 라인에서 이 작업을 수행하고 있습니다.



그런데 단순히 레이어를 생성한다고 해서 기능이 동작하는 것은 아닙니다. 이 레이어를 구동하는데 필요한 익스텐션( extension ) 들을 지정할 필요가 있죠. 20 라인에서 validation 을 위한 익스텐션을 추가하고 있는 것을 보실 수 있습니다.


우리가 처음에 "VkLayer_core_validation.json" 파일을 확인했었죠? 거기에는 "instance_extensions" 라는 오브젝트가 있는데 그것의 배열 값에는 해당 레이어를 위해서 요구되는 익스텐션의 리스트가 들어갑니다.


"VkLayer_core_validation.json" 의 경우에는 "VK_EXT_debug_report" 을 요구하구요, 만약 다른 익스텐션이 필요하다면 그것을 추가해 줄 필요가 있습니다. 이러한 익스텐션 이름은 보통 "vulkan_core.h" 에 매크로로 정의되어 있습니다. 이 경우에는 VK_EXT_DEBUG_REPORT_EXTENSION_NAME 입니다. 물론 직접 텍스트를 입력하셔도 무방하지만, 실수를 줄이려면 이런 매크로를 사용하시는 것이 좋겠죠.



이렇게 해서 VkInstance 와 함께 레이어를 로드하면, VkGetInstanceProcAddr() 를 사용해서 해당 레이어의 익스텐션을 위한 API 를 가지고 와서 사용할 수 있습니다. 다음은 "VulkanDebug.cpp" 에서 VK_EXT_Debug_Report 익스텐션을 위한 콜백들을 생성하고 파괴하는 메서드를 구현하는 모습을 보여 줍니다.



정리


레이어는 명시적 혹은 묵시적으로 로드되며, 명시적으로 로드되는 경우에는 VkInstance 생성시에 지정됩니다. 이 때 필요한 익스텐션들도 지정해 줄 필요가 있습니다. 인스턴스 생성 후에는 VkGetInstanceProcAddr() 함수를 통해서 관련 API 를 호출할 수 있습니다.


다음 시간에는 Vulkan Layer 의 내부적인 동작 방식에 대해서 자세히 알아 보도록 하겠습니다. [ 2 ] 에 대한 번역이 될 것입니다.


참고자료


[ 1 ] Layers Overview and Configuration, LUNAR XCHANGE.


[ 2 ] Brief guide to Vulkan layers, RenderDoc.

+ Recent posts