Vulkan API는 드라이버 오버헤드를 최소화한다는 아이디어를 중심으로 설계되었으며, 그 목표의 표현 중 하나는 기본적으로 API에서 매우 제한된 오류 검사가 있다는 것입니다. 잘못된 값으로 열거형을 설정하거나 필수 매개변수에 nullptr을 전달하는 것과 같은 단순한 실수도, 일반적으로는 명시적으로 처리되지 않으며 단순히 크래시나 정의되지 않은 동작을 일으킵니다. Vulkan은 수행하는 모든 작업에 대해 매우 명시적이어야 하기 때문에, 새로운 GPU 기능을 사용하거나 논리적 장치 생성을 할 때 요청하는 것을 잊어버리는 등의 작은 실수를 하기 쉽습니다.
그러나 이러한 검사를 API에 추가할 수 없다는 것은 아닙니다. Vulkan은 유효성 검사 레이어라는 우아한 시스템을 도입했습니다. 유효성 검사 레이어는 Vulkan 함수 호출에 연결하여 추가 작업을 적용하는 선택적인 구성 요소입니다. 유효성 검사 레이어 작업은 일반적으로 다음과 같습니다.
다음은 진단 유효성 검사 레이어에서 기능을 구현하는 예입니다:
VkResult vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* instance) {
if (pCreateInfo == nullptr || instance == nullptr) {
log("Null pointer passed to required parameter!");
return VK_ERROR_INITIALIZATION_FAILED;
}
return real_vkCreateInstance(pCreateInfo, pAllocator, instance);
}
이러한 유효성 검사 레이어는 관심있는 모든 디버깅 기능을 포함하도록 자유롭게 쌓을 수 있습니다. 디버그 빌드에 대해 유효성 검사 레이어를 활성화하고 릴리즈 빌드에 대해 비활성화하면 두 가지 장점을 모두 누릴 수 있습니다!
Vulkan에는 검증 레이어가 내장되어 있지 않지만, LunarG Vulkan SDK는 일반적인 오류를 확인하는 훌륭한 레이어 세트를 제공합니다. 이것들은 모두 완전히 오픈소스이므로, 어떤 종류의 실수를 하는지 확인하고 기여할 수 있습니다. 유효성 검사 계층을 사용하는 것은 정의되지 않은 동작에 의해 어플리케이션이 중단되는 것을 막는 좋은 방법입니다.
검사 계층은 시스템에 설치된 경우에만 사용할 수 있습니다. 예를 들어, LunarG 유효성 검사 레이어는 Vulkan SDK가 설치된 PC에서만 사용할 수 있습니다.
Vulkan에는 이전에 두 가지 유형의 유효성 검사 레이어가 있었습니다:인스턴스 레이어와 장치별 레이어입니다. 이 아이디어는 인스턴스 레이어가 인스턴스와 같은 전역 Vulkan 객체에 관련된 호출만 확인하고, 장치별 레이어는 특정 GPU와 관련된 호출만 확인한다는 것입니다. 장치별 레이어는 더 이상 사용되지 않습니다. 즉, 인스턴스 유효성 검사 레이어가 모든 Vulkan 호출에 적용됩니다. 사양 문서에는 일부 구현에 필요한 호환성을 위해 장치 수준에서 유효성 검사 레이어를 활성화할 것을 여전히 권장합니다. 나중에 볼 논리적 디바이스 수준에서 인스턴스와 동일한 레이어를 지정하기만 하면 됩니다.
이 섹션에서는 Vulkan SDK에서 제공하는 표준 진단 레이어를 활성화하는 방법을 살펴보겠습니다. 확장과 마찬가지로 유효성 검사 레이어는 이름을 지정하여 활성화해야 합니다. 모든 유용한 표준 유효성 검사는 VK_LAYER_KHRONOS_validataion이라고 하는, SDK에 포함되어 있는 레이어에 번들로 제공됩니다.
먼저 활성화할 계층과 활성화 여부를 지정하기 위해 프로그램에 두 개의 구성 변수를 추가해보겠습니다. 프로그램이 디버그 모드에서 컴파일되는지 여부에 따라, 해당 값을 기반으로 할 것입니다. NDEBUG 매크로는 C++ 표준의 일부이며, ‘디버그가 아님’을 의미합니다.
const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;
const std::vector<const char*> validationLayers = {
"VK_LAYER_KHRONOS_validation"
};
#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif
새로운 함수 checkValidationLayerSupport를 추가하겠습니다. 이 함수는 요청된 모든 레이어를 사용할 수 있는지 확인합니다. 먼저 vkEnumerateInstancelayerProperties를 사용하여 사용 가능한 모든 레이어를 나열합니다. 사용법은 vkEnumerateInstanceExtensionProperties와 동일합니다. 이는 이전 챕터에서 논의했었습니다.
bool checkValidationLayerSupport() {
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
return false;
}