Vulkan-HPP의 목표는 CPU 런타임 비용을 도입하지 않고도 Vulkan 경험을 향상시키기 위해 Vulkan C API에 대한 헤더 만 C ++ 바인딩을 제공하는 것입니다. 열거 및 비트 필드의 유형 안전, STL 컨테이너 지원, 예외 및 간단한 열거와 같은 기능을 추가합니다.
| 플랫폼 | 상태 빌드 상태 |
|---|---|
| 리눅스 |
Vulkan-HPP는 버전 1.0.24 이후 Lunarg Vulkan SDK의 일부입니다. #include <vulkan/vulkan.hpp> c ++ 바인딩을 사용할 준비가되었습니다. Vulkan SDK가 아직 지원하지 않은 Vulkan 버전을 사용하는 경우 여기에서 최신 버전의 헤더를 찾을 수 있습니다.
Vulkan-HPP는 컴파일을 위해 C ++ 11 능력 컴파일러가 필요합니다. 다음 컴파일러는 작동하는 것으로 알려져 있습니다.
로컬 샘플과 테스트를 구축하려면이 저장소를 복제하고 CMAKE를 실행하여 필요한 빌드 파일을 생성해야합니다.
종속성을 설치하십시오.
git을 제공하는 쉘을 열고 저장소를 다음과 함께 복제하십시오.
git clone --recurse-submodules https://github.com/KhronosGroup/Vulkan-Hpp.git
현재 디렉토리를 새로 만든 Vulkan-HPP 디렉토리로 변경하십시오.
cmake를 사용하여 빌드 환경을 만듭니다.
cmake -DVULKAN_HPP_SAMPLES_BUILD=ON -DVULKAN_HPP_SAMPLES_BUILD_WITH_LOCAL_VULKAN_HPP=ON -DVULKAN_HPP_TESTS_BUILD=ON -DVULKAN_HPP_TESTS_BUILD_WITH_LOCAL_VULKAN_HPP=ON -B build
전체 생성기 목록이 cmake -G 실행하려면 -G 통해 생성기를 지정해야 할 수도 있습니다.
vk.xml xml 레지스트리 파일에서 vulkan.hpp 재구성하려면 cmake 명령 줄에 옵션 -DVULKAN_HPP_RUN_GENERATOR=ON 추가하십시오. IDE와 예를 들어 Visual Studio를 사용하여 생성 된 프로젝트를 열거 나 cmake --build build --parallel 사용하여 빌드 프로세스를 시작하십시오.
선택 사항 : Vulkan-HPP를 업데이트하고 하위 모듈을 업데이트하려면 git pull --recurse-submodules 실행합니다.
VCPKG 종속성 관리자를 사용하여 Vulkan-HPP를 다운로드하여 설치할 수 있습니다.
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install vulkan-headersVCPKG의 Vulkan-HPP 포트는 Microsoft 팀원 및 커뮤니티 기고자가 최신 상태로 유지됩니다. 버전이 오래된 경우 VCPKG 저장소에서 문제를 만들거나 요청을 가져 오십시오.
cmake에 의해 clang-format 프로그램을 찾으면 define CLANG_FORMAT_EXECUTABLE 이 그에 따라 설정됩니다. 이 경우 생성 된 vulkan.hpp 이 프로젝트의 루트 디렉토리에있는 .clang-format 파일을 사용하여 형식화됩니다. 그렇지 않으면 생성기에서 하드 코딩 된 형식입니다.
VulkanHpp.natvis 파일은 Visual Studio 용 vk::Flags 에서 사용자 정의보기를 제공합니다. Visual Studio 설치의 사용자 별 Natvis 디렉토리 에이 파일을 추가하면 (%userprofile% documents Visual Studio 2022 Visualizers) 모든 비주얼 스튜디오 프로젝트와 함께 디버거에서 vk::Flags 잘 포맷합니다.
Vulkan C API와의 이름 충돌을 피하기 위해 C ++ 바인딩은 vk 네임 스페이스에 있습니다. 다음 규칙은 새로운 이름에 적용됩니다.
Vk 접두사가 제거되었습니다. 이 외에도 첫 번째 기능 문자는 소문자입니다.vkCreateInstance vk::createInstance 로 액세스 할 수 있습니다.VkImageTiling vk::ImageTiling 으로 액세스 할 수 있습니다.VkImageCreateInfo vk::ImageCreateInfo 로 액세스 할 수 있습니다.VK_ 접두사와 유형 디픽스가 제거 된 'E' + Camelcase로 변경되었습니다. 열거 유형이 확장자 인 경우, 확장 접미사는 열거 값에서 제거되었습니다.다른 모든 경우에 확장 접미사는 제거되지 않았습니다.
VK_IMAGETYPE_2D 는 이제 vk::ImageType::e2D 입니다.VK_COLOR_SPACE_SRGB_NONLINEAR_KHR 이제 vk::ColorSpaceKHR::eSrgbNonlinear 입니다.VK_STRUCTURE_TYPE_PRESENT_INFO_KHR 는 이제 vk::StructureType::ePresentInfoKHR 입니다._BIT 접미사도 제거되었다는 추가로 스코핑 된 열거처럼 처리됩니다. 경우에 따라 Vulkan-HPP를 사용자 정의 네임 스페이스로 이동해야 할 수도 있습니다. Vulkan-HPP를 포함하기 전에 VULKAN_HPP_NAMESPACE 정의하여 달성 할 수 있습니다.
Vulkan-HPP는 모든 핸들에 대한 클래스를 선언하여 전체 유형 안전을 보장하고 핸들의 멤버 기능에 대한 지원을 추가합니다. 해당 핸들을 첫 번째 매개 변수로 수락하는 각 함수의 핸들 클래스에 멤버 함수가 추가되었습니다. vkBindBufferMemory(device, ...) 대신 device.bindBufferMemory(...) 또는 vk::bindBufferMemory(device, ...) 를 쓸 수 있습니다.
vulkan_raii.hpp 라는 추가 헤더가 생성되었습니다. 이 헤더는 핸들 유형에 대한 RAII 호환 래퍼 클래스를 보유하고 있습니다. 즉, 핸들 유형의 VkInstance 를 위해 RAII 호환 래퍼 vk::raii::Instance 가 있습니다. 디렉토리 RAII_SAMPLES에서 해당 클래스를 사용하여 샘플을 살펴보십시오.
64 비트 플랫폼에서 Vulkan-HPP는 C ++ vulkan 핸들과 C vulkan 핸들 사이의 암시 적 변환을 지원합니다. 32 비트 플랫폼에서는 제거 할 수없는 모든 핸들은 uint64_t 로 정의되므로 컴파일 시간에 유형 조정 검사를 방지하여 호환되지 않는 핸들 유형 간의 할당을 포착합니다. Vulkan-HPP VkImage = static_cast<VkImage>(cppImage) 기본적으로 32 비트 플랫폼의 암시 적 변환을 가능하게하지 않으며 다음과 같은 변환에 static_cast 사용하는 것이 좋습니다. 64 비트 플랫폼에서 코드를 개발하고 있지만 명시 적 캐스트를 추가하지 않고 32 비트 플랫폼의 코드를 컴파일하려는 경우 VULKAN_HPP_TYPESAFE_CONVERSION 빌드 시스템에서 또는 vulkan.hpp 포함하기 전에 1 로 정의 할 수 있습니다. 64 비트 플랫폼 에서이 정의는 기본적으로 1 로 설정되어 있으며 암시 적 변환을 비활성화하기 위해 0 으로 설정할 수 있습니다.
스코핑 된 열거 기능은 플래그에 유형 안전을 추가하지만 & 와 같은 비트 비트 작업에 대한 입력으로 플래그 비트를 사용하는 것을 방지합니다 | .
솔루션으로 Vulkan-HPP는 클래스 템플릿 vk::Flags 를 제공하여 &= , |= , & 및 | 우리의 경계 열거에. 0 의 초기화를 제외 하고이 클래스는 일반 비트 마스크와 똑같이 동작하여 우연히 해당 열거에 의해 지정되지 않은 비트를 설정하는 것이 불가능하다는 개선으로 동작합니다. 비트 마스크 처리에 대한 몇 가지 예는 다음과 같습니다.
vk::ImageUsageFlags iu1; // initialize a bitmask with no bit set
vk::ImageUsageFlags iu2 = {}; // initialize a bitmask with no bit set
vk::ImageUsageFlags iu3 = vk::ImageUsageFlagBits::eColorAttachment; // initialize with a single value
vk::ImageUsageFlags iu4 = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage; // or two bits to get a bitmask
PipelineShaderStageCreateInfo ci ({} /* pass a flag without any bits set */ , ...); vulkan에 핸들을 구성 할 때는 일반적으로 새 핸들을 설명하는 CreateInfo struct를 만들어야합니다. 이로 인해 다음 Vulkan C 예에서 볼 수 있듯이 매우 긴 코드가 발생할 수 있습니다.
VkImageCreateInfo ci;
ci. sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
ci.pNext = nullptr ;
ci.flags = ...some flags...;
ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = VK_FORMAT_R8G8B8A8_UNORM;
ci.extent = VkExtent3D { width, height, 1 };
ci.mipLevels = 1 ;
ci.arrayLayers = 1 ;
ci.samples = VK_SAMPLE_COUNT_1_BIT;
ci.tiling = VK_IMAGE_TILING_OPTIMAL;
ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
ci.queueFamilyIndexCount = 0 ;
ci.pQueueFamilyIndices = 0 ;
ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
vkCreateImage (device, &ci, allocator, &image); Vulkan 개발자가 CreateInfo 하는 두 가지 일반적인 문제가 있습니다.
sType 이 잘못되었습니다.특히 첫 번째는 감지하기 어렵습니다.
Vulkan-HPP는 각 멤버 변수에 대해 하나의 매개 변수를 허용하는 모든 CreateInfo 객체에 대한 생성자를 제공합니다. 이렇게하면 값을 잊어 버린 경우 컴파일러가 컴파일러 오류를 던집니다. 이 sType 외에도 기본적으로 올바른 값과 pNext 로 설정된 nullptr 으로 자동으로 채워집니다. 동일한 코드가 생성자와 어떻게 보이는지는 다음과 같습니다.
vk::ImageCreateInfo ci ({}, vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm,
{ width, height, 1 },
1 , 1 , vk::SampleCountFlagBits:: e1 ,
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment,
vk::SharingMode::eExclusive, 0 , nullptr , vk::ImageLayout::eUndefined);
vk::Image image = device.createImage(ci); CreateInfo 구조를위한 생성자를 사용하면 다음과 같은 Vulkan 함수로 임시를 전달할 수도 있습니다.
vk::Image image = device.createImage({{}, vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm,
{ width, height, 1 },
1 , 1 , vk::SampleCountFlagBits:: e1 ,
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment,
vk::SharingMode::eExclusive, 0 , nullptr , vk::ImageLayout::eUndefined}); C ++ 20부터 C ++는 지정된 이니셜 라이더를 지원합니다. 해당 기능에는 사용자가 선언하거나 상속 된 생성자가 없어야하므로 vulkan.hpp 에서 모든 구조 및 Union 생성자를 제거하는 #define VULKAN_HPP_NO_CONSTRUCTORS 필요합니다. 대신 집계 초기화를 사용할 수 있습니다. 소스의 처음 몇 번의 VK 라인은 다음과 같습니다.
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo{ . pApplicationName = AppName,
. applicationVersion = 1 ,
. pEngineName = EngineName,
. engineVersion = 1 ,
. apiVersion = VK_API_VERSION_1_1 };
// initialize the vk::InstanceCreateInfo
vk::InstanceCreateInfo instanceCreateInfo{ . pApplicationInfo = &applicationInfo };대신
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo (AppName, 1 , EngineName, 1 , VK_API_VERSION_1_1);
// initialize the vk::InstanceCreateInfo
vk::InstanceCreateInfo instanceCreateInfo ({}, &applicationInfo); 지정자 명령은 선언 순서와 일치해야합니다. 또한 이제 VK 구조의 sType 멤버를 명시 적으로 설정할 수 있습니다. 이는 (기본적으로 올바르게 초기화되었으므로) NECCESSARY가 아닙니다.
Vulkan API에는 두 개의 함수 인수로서 (카운트, 포인터)가 필요한 여러 장소가 있으며 C ++에는이 쌍에 완벽하게 매핑되는 컨테이너가 몇 개 있습니다. 개발을 단순화하기 std::array Vulkan-HPP 바인딩은 해당 인수 쌍을 vk::ArrayProxy 클래스 템플릿으로 대체하여 빈 std::initializer_list 및 단일 값과 STL 컨테이너 std::vector 수용 할 수 있습니다. 이런 식으로 단일 생성 된 Vulkan 버전은 각 컨테이너 유형에 대한 기능을 생성 할 때 발생하는 조합 폭발없이 다양한 입력을 수용 할 수 있습니다.
다음은 vk::ArrayProxy 사용하는 방법에 대한 몇 가지 코드 샘플입니다.
vk::CommandBuffer c;
// pass an empty array
c.setScissor( 0 , nullptr );
// pass a single value. Value is passed as reference
vk::Rect2D scissorRect = { { 0 , 0 }, { 640 , 480 } };
c.setScissor( 0 , scissorRect);
// pass a temporary value.
c.setScissor( 0 , { { 0 , 0 }, { 640 , 480 } });
// pass a fixed size array
vk::Rect2D scissorRects[ 2 ] = { { { 0 , 0 }, { 320 , 240 } }, { { 320 , 240 }, { 320 , 240 } } };
c.setScissor( 0 , scissorRects);
// generate a std::initializer_list using two rectangles from the stack. This might generate a copy of the rectangles.
vk::Rect2D scissorRect1 = { { 0 , 0 }, { 320 , 240 } };
vk::Rect2D scissorRect2 = { { 320 , 240 }, { 320 , 240 } };
c.setScissor( 0 , { scissorRect, scissorRect2 });
// construct a std::initializer_list using two temporary rectangles.
c.setScissor( 0 , { { { 0 , 0 }, { 320 , 240 } },
{ { 320 , 240 }, { 320 , 240 } } });
// pass a std::array
std::array<vk::Rect2D, 2 > arr{ scissorRect1, scissorRect2 };
c.setScissor( 0 , arr);
// pass a std::vector of dynamic size
std::vector<vk::Rect2D> vec;
vec.push_back(scissorRect1);
vec.push_back(scissorRect2);
c.setScissor( 0 , vec); Vulkan-HPP는 스트러크에 대한 포인터에 대한 참조를 생성합니다. 이 변환은 임시 스트러크를 함수로 전달하여 코드가 짧아 질 수 있습니다. 입력이 선택 사항이므로 널 포인터를 수락하는 경우 매개 변수 유형은 vk::Optional<T> const& 입니다. 이 유형은 T 또는 nullptr 에 대한 참조를 입력으로 받아들이므로 선택적인 임시 스트러크를 허용합니다.
// C
VkImageSubresource subResource;
subResource.aspectMask = 0 ;
subResource.mipLevel = 0 ;
subResource.arrayLayer = 0 ;
VkSubresourceLayout layout;
vkGetImageSubresourceLayout (device, image, &subresource, &layout);
// C++
auto layout = device.getImageSubresourceLayout(image, { {} /* flags */ , 0 /* miplevel */ , 0 /* arrayLayer */ }); Vulkan은 pNext 포인터를 통해 구조의 사슬을 허용합니다. Vulkan-HPP에는 최소한의 노력으로 이러한 구조 체인을 구축 할 수있는 다양한 클래스 템플릿이 있습니다. 이 외에도 사양이 해당 pNext 체인의 구성을 허용하는 경우 컴파일 시간을 확인합니다.
// This will compile successfully.
vk::StructureChain<vk::MemoryAllocateInfo, vk::ImportMemoryFdInfoKHR> c;
vk::MemoryAllocateInfo &allocInfo = c.get<vk::MemoryAllocateInfo>();
vk::ImportMemoryFdInfoKHR &fdInfo = c.get<vk::ImportMemoryFdInfoKHR>();
// This will fail compilation since it's not valid according to the spec.
vk::StructureChain<vk::MemoryAllocateInfo, vk::MemoryDedicatedRequirementsKHR> c;
vk::MemoryAllocateInfo &allocInfo = c.get<vk::MemoryAllocateInfo>();
vk::ImportMemoryFdInfoKHR &fdInfo = c.get<vk::ImportMemoryFdInfoKHR>(); Vulkan-HPP는 체인의 모든 구조 부분의 목록을 수용하는 CreateInfo 객체와 유사한 이러한 체인에 대한 생성자를 제공합니다. pNext 필드는 자동으로 올바른 값으로 설정됩니다.
vk::StructureChain<vk::MemoryAllocateInfo, vk::MemoryDedicatedAllocateInfo> c = {
vk::MemoryAllocateInfo (size, type),
vk::MemoryDedicatedAllocateInfo (image)
}; structureChain의 구조 중 하나를 제거하려면 일부 선택적 설정으로 인해 vk::StructureChain::unlink<ClassType>() 를 사용할 수 있습니다. 지정된 구조가 더 이상 pnext-chain의 일부가되지 않도록 구조체를 수정합니다. StructureChain의 실제 메모리 레이아웃은 해당 함수에 의해 수정되지 않습니다. 동일한 구조가 구조체에 다시 다시 구조되어야하는 경우 vk::StructureChain::relink<ClassType>() 사용하십시오.
때로는 사용자가 Preallocated 구조 체인을 전달하여 정보를 쿼리해야합니다. 이 경우 두 가지 해당 Getter 기능이 있습니다. 변수 템플릿이있는 하나는 반환 값을 구성하기 위해 최소 2 개의 요소의 구조 체인을 생성합니다.
// Query vk::MemoryRequirements2HR and vk::MemoryDedicatedRequirementsKHR when calling Device::getBufferMemoryRequirements2KHR:
auto result = device.getBufferMemoryRequirements2KHR<vk::MemoryRequirements2KHR, vk::MemoryDedicatedRequirementsKHR>({});
vk::MemoryRequirements2KHR &memReqs = result.get<vk::MemoryRequirements2KHR>();
vk::MemoryDedicatedRequirementsKHR &dedMemReqs = result.get<vk::MemoryDedicatedRequirementsKHR>();기본 구조 만 얻기 위해 체인없이 제공되는 다른 getter 기능은 구조에 대한 템플릿 인수가 필요하지 않습니다.
// Query just vk::MemoryRequirements2KHR
vk::MemoryRequirements2KHR memoryRequirements = device.getBufferMemoryRequirements2KHR({}); 기본적으로 Vulkan-HPP에는 예외가 활성화되어 있습니다. 이는 Vulkan-HPP가 vk::Result 반환하는 각 함수 호출의 반환 코드를 확인합니다. vk::Result 실패하면 std::runtime_error 가 던져집니다. 더 이상 오류 코드를 반환 할 필요가 없기 때문에 C ++ 바인딩은 이제 실제 원하는 리턴 값 (즉, Vulkan 핸들)을 반환 할 수 있습니다. 이 경우 vk::ResultValue<SomeType>::type 반환 된 유형으로 정의됩니다.
장치를 만들려면 이제 다음과 같이 쓸 수 있습니다.
vk::Device device = physicalDevice.createDevice(createInfo); 일부 기능은 단순한 vk::Result::eSuccess 성공 코드로 간주 될 수 있습니다. 이러한 함수의 경우 항상 vk::ResultValue<SomeType> 반환합니다. 예를 들어 acquireNextImage2KHR 은 다음과 같이 사용할 수 있습니다.
vk::ResultValue< uint32_t > result = device-> acquireNextImage2KHR (acquireNextImageInfo);
switch (result.result)
{
case vk::Result::eSuccess:
currentBuffer = result. value ;
break ;
case vk::Result::eTimeout:
case vk::Result::eNotReady:
case vk::Result::eSuboptimalKHR:
// do something meaningful
break ;
default :
// should not happen, as other return codes are considered to be an error and throw an exception
break ;
} 시간이 지남에 따라 일부 vulkan 기능이 변경 될 수 있으므로 vk::Result::eSuccess success보다 더 많은 결과 코드를 지원하기 시작합니다. 그 논리적 변경은 C API에서는 보이지 않지만 C ++ API에서는 이러한 함수가 이제 vk::ResultValue<SomeType> SomeType 하기 때문에 이러한 (드문) 경우 API 변경을 반영하기 위해 CPP 소스를 조정해야합니다.
VULKAN_HPP_NO_EXCEPTIONS 정의하여 예외 처리가 비활성화 된 경우 vk::ResultValue<SomeType>::type 의 유형은 vk::Result 와 SomeType 보유하는 구조물입니다. 이 구조물은 std::tie 사용하여 반환 값을 풀기를 지원합니다.
vk::ArrayProxy 및 리턴 값 변환을 사용하고 싶지 않은 경우에도 여전히 일반 C 스타일 기능을 호출 할 수 있습니다. 다음은 API를 사용하는 세 가지 방법을 보여주는 세 가지 예입니다.
첫 번째 스 니펫은 예외없이 API를 사용하는 방법과 반환 값 변환을 보여줍니다.
// No exceptions, no return value transformation
vk::ShaderModuleCreateInfo createInfo (...);
vk::ShaderModule shader1;
vk::Result result = device.createShaderModule(&createInfo, allocator, &shader1);
if (result.result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}
vk::ShaderModule shader2;
vk::Result result = device.createShaderModule(&createInfo, allocator, &shader2);
if (result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}두 번째 스 니펫은 반환 값 변환을 사용하여 API를 사용하는 방법을 보여줍니다. 이미 원래 코드보다 약간 짧습니다.
vk::ResultValue<ShaderModule> shaderResult1 = device.createShaderModule({...} /* createInfo temporary */ );
if (shaderResult1.result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}
// std::tie support.
vk::Result result;
vk::ShaderModule shaderModule2;
std::tie (result, shaderModule2) = device.createShaderModule({...} /* createInfo temporary */ );
if (result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}결과를 풀리는 더 좋은 방법은 C ++ 17에서 구조화 된 바인딩을 사용하는 것입니다. 그들은 우리가 한 줄의 코드로 결과를 얻을 수있게 해줄 것입니다.
auto [result, shaderModule2] = device.createShaderModule({...} /* createInfo temporary */ );마지막으로, 마지막 코드 예제는 예외 및 반환 값 변환을 사용하는 것입니다. 이것은 API의 기본 모드입니다.
vk::ShaderModule shader1;
vk::ShaderModule shader2;
try
{
shader1 = device. createShaderModule ({...});
shader2 = device. createShaderModule ({...});
}
catch (std:: exception const &e)
{
// handle error and free resources
}중요한
vk -namespace의 Vulkan 핸들은 RAII를 지원하지 않으므로 오류 처리기에서 리소스를 정리해야합니다! 대신 vk::raii -namespace에서 핸들 래퍼 클래스를 사용할 수 있습니다.
C ++ 17 이상의 경우 일부 기능은 [[nodiscard]] 에 기인하여 어떤 식 으로든 반환 값을 사용하지 않으면 경고가 발생합니다. VULKAN_HPP_NO_NODISCARD_WARNINGS 정의하여 해당 경고를 끕니다.
반환 값 변환의 경우 특별한 처리가 필요한 특수 클래스의 반환 값이 하나 있습니다 : 열거. 열거의 경우 일반적으로 다음과 같은 코드를 작성해야합니다.
std::vector<LayerProperties, Allocator> properties;
uint32_t propertyCount;
vk::Result result;
do
{
// determine number of elements to query
result = static_cast <vk::Result>( vk::enumerateDeviceLayerProperties (m_physicalDevice, &propertyCount, nullptr ));
if ((result == vk::Result::eSuccess) && propertyCount)
{
// allocate memory & query again
properties. resize (propertyCount);
result = static_cast <vk::Result>( vk::enumerateDeviceLayerProperties (m_physicalDevice, &propertyCount, reinterpret_cast
<VkLayerProperties*>(properties. data ())));
}
} while (result == vk::Result::eIncomplete);
// it's possible that the count has changed, start again if properties was not big enough
properties.resize(propertyCount);이 루프를 반복해서 쓰기 때문에 지루하고 오류가 발생하기 쉽습니다. C ++ 바인딩은 열거를 처리하여 다음과 같이 쓸 수 있습니다.
std::vector<LayerProperties> properties = physicalDevice.enumerateDeviceLayerProperties(); Vulkan-HPP는 vk::UniqueHandle<Type, Deleter> 인터페이스를 제공합니다. 각 vulkan 핸들 유형 vk::Type 에 대해 파괴시 기본 Vulkan 리소스를 삭제하는 고유 한 핸들 vk::Buffer vk::UniqueBuffer vk::UniqueType 가 있습니다.
유형 vk::Type vulkan-hpp의 vulkan 핸들을 구성하는 각 함수에 대해 vk::UniqueType 반환하는 두 번째 버전을 제공합니다. vk::Device::createBuffer 의 경우 vk::Device::createBufferUnique 가 있으며 vk::allocateCommandBuffers vk::allocateCommandBuffersUnique 가 있습니다.
vk::UniqueHandle 사용하면 대부분의 델리 트는 자동 파괴에 필요하기 때문에 vk::AllocationCallbacks 및 Construction에 사용되는 부모 핸들을 저장해야하므로 비용이 많이 듭니다.
Vulkan-HPP는 vk::SharedHandle<Type> 인터페이스를 제공합니다. 각 vulkan 핸들 유형 vk::Type 에 대해 공유 핸들 vk::SharedType 가 있으며 vk::SharedBuffer 이는 파괴시 기본 Vulkan 리소스 vk::Buffer 삭제할 수 있습니다.
vk::UniqueHandle 과 달리 vk::SharedHandle 부모뿐만 아니라 자원의 공유 소유권을 가져옵니다. 즉, 모든 아동 자원이 삭제 될 때까지 부모 핸들이 파괴되지 않음을 의미합니다. 이것은 여러 스레드 또는 객체간에 공유되는 리소스에 유용합니다.
이 메커니즘은 부모 vk::SharedHandle 이 아동 처리 전에 파괴 되더라도 올바른 파괴 순서를 보장합니다. 그렇지 않으면 핸들은 std::shared_ptr 처럼 작동합니다. vk::SharedInstance 또는 자식 객체는 마지막으로 삭제해야합니다 (첫 번째로 생성 된 첫 번째 클래스 선언).
vk::SharedHandle 직접 반환하는 기능은 없습니다. 대신 vk::SharedHandle vk::Handle sharedhandle을 구성 할 수 있습니다.
vk::Buffer buffer = device.createBuffer(...);
vk::SharedBuffer sharedBuffer (buffer, device); // sharedBuffer now owns the buffer 다양한 핸들 유형에 대한 vk::SharedHandle 의 여러 전문 분야가 있습니다. 예를 들어, vk::SharedImage 이미지가 Swapchain이 소유하고 있는지 지정하기 위해 추가 인수를 할 수 있습니다.
vk::Image image = swapchain.getImages(...)[ 0 ]; // get the first image from the swapchain
vk::SharedImage sharedImage (image, device, SwapChainOwns::yes); // sharedImage now owns the image, but won't destroy it vk::SwapchainKHR 에 대한 전문화도 있습니다.
vk::SwapchainKHR swapchain = device.createSwapchainKHR(...);
vk::SharedSwapchainKHR sharedSwapchain (swapchain, device, surface); // sharedSwapchain now owns the swapchain and surface SharedHandleBase 에 여러 템플릿 인수를 제공하여 자신의 핸들 유형 또는 공유 핸들에 대한 vk::SharedHandle 오버로드를 만들 수 있습니다.
이를 통해 부모 핸들과 손잡이를 파괴 할 수있는 맞춤형 정적 파괴 기능 internalDestroy 제공하십시오. 기본 클래스에 친구 선언을 추가하는 것을 잊지 마십시오.
// Example of a custom shared device, that takes in an instance as a parent
class shared_handle <VkDevice> : public vk::SharedHandleBase<VkDevice, vk::SharedInstance, shared_handle<VkDevice>>
{
using base = vk::SharedHandleBase<VkDevice, vk::SharedInstance, shared_handle<VkDevice>>;
friend base;
public:
shared_handle () = default ;
explicit shared_handle (VkDevice handle, vk::SharedInstance parent) noexcept
: base(handle, std::move(parent)) {}
const auto & getParent () const noexcept
{
return getHeader ();
}
protected:
static void internalDestroy ( const vk::SharedInstance& /* control */ , VkDevice handle) noexcept
{
kDestroyDevice (handle);
}
};API는 향후 창조 기능을 제공하기 위해 확장 될 것입니다.
vk::UniqueHandles 및 vk::SharedHandles 외에도 vk::raii 네임 스페이스에 제공된 Raii-Paradigm (리소스 획득 초기화)을 따르는 모든 핸들 유형에 대한 래퍼 클래스 세트가 있습니다.
vk::UniqueHandle 핸들은 std::unique_ptr 손잡이를 모방하는 반면, vk::SharedHandle 부모 정보를 포함하여 std::shared_ptr 에 의해 포장 된 핸들을 모방하지만, vk::raii::Handle 그 구성원에서 근본적인 VK 핸들을 획득하는 클래스 일뿐입니다. 따라서, 당신은 그것들을 값으로 사용하거나 스마트 포인터로 랩핑 할 수 있습니다.
vk::Handles 외에 모든 핸들 래퍼 클래스는 추가 데이터를 보유해야하므로 Vulkan C 핸들과 동일하지 않습니다.
vk::UniqueHandles 및 vk::SharedHandles vk::Handles 과 동일한 디스패처를 사용하므로 쉽게 혼합 및 일치 할 수 있습니다. vk::raii::Handles 약간 다른 디스패처를 사용하므로 다른 핸들과 호환되지 않습니다! 즉, vk-Handles , vk::UniqueHandles 및 vk::SharedHandles 의 경우 https://github.com/khronosgroup/vulkan-hp#extensions- https://github.com/khronosgroup/vulkan-hp#extensions-- revice-function-pointers에 설명 된대로 글로벌 디스패처를 인스턴스화해야합니다. vk::raii-Handles 의 경우 자체 파견자를 유지하므로 필요하지 않습니다. 여기서 가장 큰 장점은 여러 장치 vk::raii-Handles 있을 때입니다.
때로는 사용자 정의 할당 자와 함께 std::vector 사용해야합니다. Vulkan-HPP는 vk::ArrayProxy 에 대한 입력 및 벡터를 반환하는 함수에 대한 사용자 정의 할당 자로 벡터를 지원합니다. 후자의 경우, 좋아하는 사용자 정의 할당자를 다음과 같은 기능 호출에 템플릿 인수로 추가하십시오.
std::vector<LayerProperties, MyCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties<MyCustomAllocator>(); 또한 해당 기능에 대한 인수로 제공하여 Stateful Custom 할당자를 사용할 수도 있습니다. 불행히도 컴파일러를 행복하게하려면 디스패치 인수를 명시 적으로 설정해야합니다. 기본값을 얻으려면 간단한 {} 만 충분합니다.
MyStatefulCustomAllocator allocator;
std::vector<LayerProperties, MyStatefulCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties(allocator, {}); vulkan.hpp 에는 Assert 기능에 대한 몇 가지 호출이 있습니다. VULKAN_HPP_ASSERT 정의하면 대신 호출 할 자신의 사용자 정의 어제 기능을 지정할 수 있습니다.
기본적으로 VULKAN_HPP_ASSERT_ON_RESULT VULKAN_HPP_NO_EXCEPTIONS 정의 될 때 결과를 확인하는 데 사용됩니다. 직접 오류를 처리하려면 VULKAN_HPP_ASSERT 처럼 비활성화/사용자 정의 할 수 있습니다.
각 핸들 클래스에 대한 몇 가지 정적 어설 션이 있으며 vulkan_static_assertions.hpp 파일에는 각 구조물이 있습니다. 소스 파일 중 하나 이상에 해당 파일을 포함시킬 수 있습니다. VULKAN_HPP_STATIC_ASSERT 정의하면 해당 경우에 사용할 자신의 사용자 정의 정적 어설 션을 지정할 수 있습니다. 즉, NOP로 정의함으로써 컴파일 시간을 조금 줄일 수 있습니다.
Vulkan 로더는 Vulkan 코어 함수와 제한된 수의 확장 만 노출됩니다. 확장자와 함께 Vulkan-HPP를 사용하려면 모든 사용 된 Vulkan 기능에 스터브를 제공하는 라이브러리가 있어야하거나 Vulkan-HPP에 해당 기능 포인터를 파견하도록 지시해야합니다. Vulkan-HPP는 각 기능 호출에서 마지막 매개 변수로 디스패치 클래스를 수락하여 기능 당 발송 메커니즘을 제공합니다. 디스패치 클래스는 각각의 사용 된 Vulkan 함수에 대해 호출 가능한 유형을 제공해야합니다. Vulkan-HPP는 하나의 구현 인 DispatchLoaderDynamic 제공하며 라이브러리에 알려진 모든 기능 포인터를 가져옵니다.
// Providing a function pointer resolving vkGetInstanceProcAddr, just the few functions not depending an an instance or a device are fetched
vk::DispatchLoaderDynamic dld (getInstanceProcAddr);
// Providing an already created VkInstance and a function pointer resolving vkGetInstanceProcAddr, all functions are fetched
vk::DispatchLoaderDynamic dldi (instance, getInstanceProcAddr);
// Providing also an already created VkDevice and optionally a function pointer resolving vkGetDeviceProcAddr, all functions are fetched as well, but now device-specific functions are fetched via vkDeviceGetProcAddr.
vk::DispatchLoaderDynamic dldid ( nstance, getInstanceProcAddr, device);
// Pass dispatch class to function call as last parameter
device.getQueue(graphics_queue_family_index, 0 , &graphics_queue, dldid); vk::DispatchLoaderDynamic 기본 디스패처로 사용하려면 (수단 : 모든 함수 호출에 명시 적으로 추가 할 필요가 없습니다) #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 해야하며 Macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE despatcher에서 정확히 한 번 Sourt Code를 제공합니다. 그런 다음 아래 코드 스 니펫에 표시된 것처럼 매크로 VULKAN_HPP_DEFAULT_DISPATCHER 에서 사용할 수 있습니다. 전체 특집 vk::DispatchLoaderDynamic 만드는 것은 2 ~ 3 단계 프로세스이며, 첫 번째 단계를위한 세 가지 선택이 있습니다.
vk::DynamicLoader 를 사용하여 모든 작업을 수행하십시오. VULKAN_HPP_DEFAULT_DISPATCHER.init();getProcAddress 제공하는 데 필요한 자체 동적 로더를 사용하십시오 ( vulkan.hpp 의 vk::DynamicLoader 와 비교) : YourDynamicLoader ydl;
VULKAN_HPP_DEFAULT_DISPATCHER.init(ydl);메모
프로그램에서 Vulkan 함수를 마지막으로 호출 할 때까지 해당 동적 로더 객체를 살려야합니다. 예를 들어, 정적으로 만들거나 전역으로 저장함으로써.
PFN_vkGetInstanceProcAddr 유형의 초기 기능 포인터를 사용하십시오. PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = your_own_function_pointer_getter();
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);vk::Instance 로 초기화하십시오. vk::Instance instance = vk::createInstance({}, nullptr );
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);vk::Device 로 초기화하여 장치 별 함수 포인터를 얻습니다. std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
assert (!physicalDevices.empty());
vk::Device device = physicalDevices[ 0 ].createDevice({}, nullptr );
VULKAN_HPP_DEFAULT_DISPATCHER.init(device);위의 두 번째 단계 후에는 디스패처가 완전히 작동합니다. 세 번째 단계를 추가하면 더 효율적인 코드가 발생할 수 있습니다. 그러나 여러 장치를 사용하려는 경우 그 세 번째 단계를 생략하고 드라이버가 장치를 사용하여 수행 할 수 있습니다.
경우에 따라 DispatchloaderDynamic에 대한 저장소는 DLL에 포함되어야합니다. 이러한 경우 저장소가 DLL에 상주한다고 Vulkan-HPP에 알리기 위해 VULKAN_HPP_STORAGE_SHARED 정의해야합니다. 스토리지로 DLL을 컴파일 할 때 필요한 기호를 내보내기 위해 VULKAN_HPP_STORAGE_SHARED_EXPORT 정의해야합니다.
모든 함수의 경우 VULKAN_HPP_DEFAULT_DISPATCHER 가 해당 함수에 대한 마지막 인수의 기본값입니다. 예를 들어 각 기능 호출에 대한 디스패처를 명시 적으로 제공하려면 (예를 들어 다른 장치에 대한 여러 디스패처가있을 때) 실수로 기능 호출을 놓치지 않도록 확인하려면 vulkan.hpp 포함시키기 전에 VULKAN_HPP_NO_DEFAULT_DISPATCHER 정의하여 해당 기본 인수를 제거 할 수 있습니다.
vulkan.hpp 템플릿 메타 프로 그램을 완화하는 몇 가지 유형의 특성을 제공합니다.
template <typename EnumType, EnumType value> struct CppType 맵 IndexType 값 ( IndexType::eUint16 , IndexType::eUint32 , ...)에 해당 Type ( uint16_t , uint32_t , ...); MAPS ObjectType 값 ( ObjectType::eInstance , ObjectType::eDevice , ...) 멤버 유형 Type 로 해당 유형 ( vk::Instance , vk::Device , ...)에; 맵 멤버 유형 Type 로 해당 유형 ( vk::Instance 인스턴스, vk::Device DebugReportObjectTypeEXT::eDevice , ...)에 대한지도 DebugReportObjectType 값 ( DebugReportObjectTypeEXT::eInstance einstance, debugreportobjecttypeext :: edevice, ...);template <typename T> struct IndexTypeValue 맵 스칼라 유형 ( uint16_t , uint32_t , ...)에 해당하는 IndexType 값 ( IndexType::eUint16 , IndexType::eUint32 , ...).template <typename T> struct isVulkanHandleType value 클래스 ( vk::Instance , vk::Device , ...) 인 경우에만 true 에 유형을 맵핑합니다.HandleClass::CType 핸들 클래스 ( vk::Instance , vk::Device , ...)를 멤버 유형 CType 의 해당 c- 타입 ( VkInstance , VkDevice , ...)에 맵핑합니다.HandleClass::objectType 정적 멤버 대체 objectType 에 의해 핸들 클래스 ( vk::Instance , vk::Device , ...)를 해당 ObjectType 값 ( ObjectType::eInstance , ObjectType::eDevice , ...)에 맵핑합니다.HandleClass::debugReportObjectType 핸들 클래스 ( vk::Instance , vk::Device , ...)를 해당 DebugReportObjectTypeEXT value ( DebugReportObjectTypeEXT::eInstance , debugReportObjectType DebugReportObjectTypeEXT::eDevice , ...)에 매핑합니다. 추가 헤더 vulkan_format_traits.hpp 사용하면 vk::Format 에 대한 몇 가지 특성 기능이 제공됩니다. C ++ 14 이상을 사용하면 모든 함수는 constexpr 로 표시되며, 즉 적절한 인수가 있으며 컴파일 시간에 해결됩니다.
uin8_t blockSize( vk::Format format ); 이 형식의 Texel 블록 크기를 바이트로 가져옵니다.uint8_t texelsPerBlock( vk::Format format ); 텍셀 블록에서 텍셀 수를 얻습니다.std::array<uint8_t, 3> blockExtent( vk::Format format ); 텍셀 블록의 3 차원 범위를 얻습니다.char const * compressionScheme( vk::Format format ); 이 형식의 압축 체계에 대한 텍스트 설명 또는 압축되지 않은 경우 빈 텍스트를 가져옵니다.bool isCompressed( vk::Format format ); 사실, 형식이 압축 형식 인 경우, 그렇지 않으면 false.uint8_t packed( vk::Format format ); 형식이 포장 된 비트 수를 얻습니다. 이 형식의 단일 이미지 요소는이 비트 너비의 스칼라 유형과 동일한 공간에 저장 될 수 있습니다.uint8_t componentCount( vk::Format format ); 이 형식의 구성 요소 수를 얻습니다.bool componentsAreCompressed( vk::Format format ); 사실,이 형식의 구성 요소가 압축되면, 그렇지 않으면 거짓입니다.uint8_t componentBits( vk::Format format, uint8_t component ); 압축되지 않은 경우이 구성 요소의 비트 수를 가져옵니다. 그렇지 않으면 0.char const * componentName( vk::Format format, uint8_t component ); 이 구성 요소의 이름을 C- 스트링으로 가져옵니다.char const * componentNumericFormat( vk::Format format, uint8_t component ); 이 구성 요소의 숫자 형식을 C- 스트링으로 가져옵니다.uint8_t componentPlaneIndex( vk::Format format, uint8_t component ); 비행기 색인을 가져 오면이 구성 요소는 있습니다.uint8_t planeCount( vk::Format format ); 이 형식의 이미지 평면 수를 얻습니다.vk::Format planeCompatibleFormat( vk::Format format, uint8_t plane ); 이 평면과 호환되는 단일 비행기 형식을 가져옵니다.uint8_t planeHeightDivisor( vk::Format format, uint8_t plane ); 이 평면의 상대적 높이를 얻습니다. K의 값은이 평면이 전체 형식의 높이 1/k임을 의미합니다.uint8_t planeWidthDivisor( vk::Format format, uint8_t plane ); 이 평면의 상대 너비를 얻습니다. K의 값은이 평면이 전체 형식의 너비 1/k임을 의미합니다. 추가 헤더 vulkan_hash.hpp 사용하면 핸들 래퍼 클래스의 경우 std::hash 의 전문화 및 구조 랩퍼의 경우 C ++ 14를 제공합니다. VULKAN_HPP_HASH_COMBINE 사용하면 구조 요소에 대한 자신의 해시를 결합한 알고리즘을 정의 할 수 있습니다.
추가 헤더 vulkan_extension_inspection.hpp 사용하면 확장을 검사하는 일부 기능이 제공됩니다. C ++ 20 이상을 사용하면 이러한 기능 중 일부는 constexpr 로 표시되며, 즉 적절한 인수가 있으며 컴파일 시간에 해결됩니다. 각 확장자는 이름을 가진 문자열로 식별됩니다. 각 확장자에 대해 해당 이름을 가진 정의가 있습니다. 일부 기능은 Vulkan 버전에 의존하는 정보를 제공 할 수 있습니다. 여기의 모든 기능은 문자열에서만 작동하므로 Vulkan 버전은 "vk_version_"로 시작하는 문자열로 인코딩되며, 다음과 같은 "vk_version_1_0"과 같은 미드 버전과 마이너 버전이 뒤 따릅니다.
std::set<std::string> const & getDeviceExtensions(); 현재 플랫폼에 지정된 모든 장치 확장을 가져옵니다. 실제 장치에서 모든 것이 지원되는 것은 아닙니다.std::set<std::string> const & getInstanceExtensions(); 현재 플랫폼에 지정된 모든 인스턴스 확장을 가져옵니다. 실제 인스턴스에 의해 그들 모두가 뒷받침되는 것은 아닙니다.std::map<std::string, std::string> const & getDeprecatedExtensions(); 해당 기능을 대체 해야하는 확장자 또는 Vulkan 버전에 대한 모든 감가 상각 된 확장 맵을 가져옵니다.std::map<std::string, std::vector<std::vector<std::string>>> const & getExtensionDepends( std::string const & extension ); 일부 확장은 다른 확장에 따라 다릅니다. 이러한 의존성은 Vulkan 버전에 대해 다를 수 있으며 동일한 Vulkan 버전의 경우 다른 종속성 세트가있을 수 있습니다. 이 함수는 주어진 확장자가 의존하는 Vulkan 버전 당 확장자 벡터의 벡터를 가져옵니다.std::pair<bool, std::vector<std::vector<std::string>> const &> getExtensionDepends( std::string const & version, std::string const & extension ); 반환 된 std::pair 의 first 멤버는 주어진 vulkan 버전에 주어진 확장자가 지정되면, 그렇지 않으면 false . 반환 된 std::pair 의 second 멤버는 확장 벡터의 벡터이며, 주어진 확장자가 주어진 Vulkan 버전에 의존하는 별도의 확장 세트를 나열합니다.std::map<std::string, std::string> const & getObsoletedExtensions(); 그 확장이 불가능한 확장자 또는 Vulkan 버전에 대한 모든 쓸모없는 확장 맵을 얻습니다.std::map<std::string, std::string> const & getPromotedExtensions(); Vulkan 버전의 확장에 대한 다른 확장자 또는 Vulkan 버전으로 홍보 된 모든 확장 맵을 얻습니다.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionDeprecatedBy( std::string const & extension ); 주어진 확장자가 감가 상각 된 확장자 또는 vulkan 버전을 가져옵니다.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionObsoletedBy( std::string const & extension ); 주어진 확장자가 쓸모없는 확장자 또는 vulkan 버전을 가져옵니다.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionPromotedTo( std::string const & extension ); 주어진 확장자가 홍보되는 확장자 또는 Vulkan 버전을 가져옵니다.VULKAN_HPP_CONSTEXPR_20 bool isDeprecatedExtension( std::string const & extension ); 주어진 확장자가 다른 확장자 또는 Vulkan 버전으로 더 이상 사용되지 않으면 true 반환합니다.VULKAN_HPP_CONSTEXPR_20 bool isDeviceExtension( std::string const & extension ); 주어진 확장자가 장치 확장자 인 경우 true 반환합니다.VULKAN_HPP_CONSTEXPR_20 bool isInstanceExtension( std::string const & extension ); 주어진 확장자가 인스턴스 확장자 인 경우 true 반환합니다.VULKAN_HPP_CONSTEXPR_20 bool isObsoletedExtension( std::string const & extension ); 주어진 확장자가 다른 확장자 또는 Vulkan 버전에 의해 쓸모없는 경우 true 반환합니다.VULKAN_HPP_CONSTEXPR_20 bool isPromotedExtension( std::string const & extension ); 주어진 내선이 다른 확장자 또는 Vulkan 버전으로 홍보되는 경우 true 반환합니다.경고
Microsoft Visual Studio 2022의 현재 버전은 Vulkan.cppm 모듈을 처리 할 수 없습니다. 버그가 제출됩니다 (https://developercommunity.visualstudio.com/t/on-building-a-c20-module:-fatal-error/10469799#t-110485943). VULKAN_HPP_NO_SMART_HANDLE 정의하여 vk::UniqueHandle 또는 vk::SharedHandle 이 필요하지 않거나 사용하려면이 기능을 사용할 수 있습니다.
Vulkan-HPP는 vulkan.cppm 에서 C ++라는 이름의 모듈, vulkan_hpp 제공합니다. C ++ 모듈은 헤더 파일을 대체하기위한 것입니다. 모듈은 대규모 프로젝트의 컴파일 시간을 크게 개선 할 수있는 잠재력을 가지고 있습니다. 선언과 정의는 반복적으로 구문 분석하지 않고 번역 장치에서 쉽게 공유 될 수 있기 때문입니다. Vulkan-HPP에는 매우 긴 헤더 (예 : vulkan_structs.hpp )가 있으며 C ++ 모듈은 현재 사용중인 프로젝트의 컴파일 시간을 단축 할 수 있습니다.
이 기능은 완전한 C ++ 20 지원을 제공하는 최근 컴파일러가 필요합니다.
cl.exe 19.28 이상 제공)CMake의 C ++ 모듈 지원 (및 닌자)을 사용하려는 경우보다 최근의 도구가 필요합니다.
cl.exe 19.34 이상 제공)경고
Vulkan-HPP C ++ 명명 된 모듈은 여전히 실험적입니다. Some suggested ways to use it in your projects are below. The long-term goal is to submit patches to the CMake FindVulkan module so that users may transparently configure the named module, without needing to declare it as an additional library in consumer CMake code.
CMake is recommended for use with the Vulkan-Hpp named module, as it provides a convenient platform-agnostic way to configure your project. CMake version 3.28 or later is required to support C++ modules. Refer to the CMake documentation on the topic.
CMake provides the FindVulkan module, which may be used to source the Vulkan SDK and Vulkan headers on your system.
# find Vulkan SDK
find_package ( Vulkan REQUIRED )
# Require Vulkan version ≥ 1.3.256 (earliest version when the Vulkan module was available)
if ( ${Vulkan_VERSION} VERSION_LESS "1.3.256" )
message ( FATAL_ERROR "Minimum required Vulkan version for C++ modules is 1.3.256. "
"Found ${Vulkan_VERSION} ."
)
endif ()
# set up Vulkan C++ module as a library
add_library ( VulkanHppModule )
target_sources ( VulkanHppModule PRIVATE
FILE_SET CXX_MODULES
BASE_DIRS ${Vulkan_INCLUDE_DIR}
FILES ${Vulkan_INCLUDE_DIR} /vulkan/vulkan.cppm
)
target_compile_features ( VulkanHppModule PUBLIC cxx_std_20 )
target_link_libraries ( VulkanHppModule PUBLIC Vulkan::Vulkan )
# link Vulkan C++ module into your project
add_executable ( YourProject main.cpp )
target_link_libraries ( YourProject PRIVATE VulkanHppModule ) Configuring the named module is straightforward; add any required Vulkan-Hpp feature macros (listed in Configuration Options) to target_compile_definitions . 예를 들어:
# Disable exceptions, disable smart handles, disable constructors
target_compile_definitions ( VulkanHppModule PRIVATE
VULKAN_HPP_NO_EXCEPTIONS
VULKAN_HPP_NO_SMART_HANDLE
VULKAN_HPP_NO_CONSTRUCTORS
) It is important to have VULKAN_HPP_DISPATCH_LOADER_DYNAMIC defined equally for both the module and an importing project. To use the dynamic dispatcher, set it to 1 ; otherwise, leave it undefined or set it to 0 . In CMake, do this in a single line with target_compile_definitions and the PUBLIC scope:
target_compile_definitions ( VulkanHppModule PUBLIC
VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1
)
# ...
target_link_libraries ( YourProject PRIVATE VulkanHppModule ) Furthermore, you may also prefer linking VulkanHppModule to just the Vulkan::Headers target with the PUBLIC scope instead of Vulkan::Vulkan , so that the vulkan-1 library is not linked in, and the Vulkan headers are available to your consuming project, as detailed further below.
target_link_libraries ( VulkanHppModule PUBLIC Vulkan::Headers ) Finally, supply the macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE exactly once in your source code, just as in the non-module case. In order to have that macro available, include vulkan_hpp_macros.hpp , a lightweight header providing all Vulkan-Hpp related macros and defines. And as explained above, you need to initialize that dispatcher in two or three steps:
import vulkan_hpp;
# include < vulkan/vulkan_hpp_macros.hpp >
# if VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
# endif
auto main ( int argc, char * const argv[]) -> int
{
# if ( VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1 )
// initialize minimal set of function pointers
VULKAN_HPP_DEFAULT_DISPATCHER. init ();
# endif
auto appInfo = vk::ApplicationInfo ( " My App " , 1 , " My Engine " , 1 , vk::makeApiVersion ( 1 , 0 , 0 , 0 ));
// ...
} An example is provided in tests/Cpp20Modules/Cpp20Modules.cpp .
Finally, you can configure and build your project as usual. Note that CMake currently only supports the Ninja and Visual Studio generators for C++ modules.
If you want to use the Vulkan-Hpp C++ module without CMake, you must first pre-compile it, and then import it into your project. You will also need to define any macros that control various features of Vulkan-Hpp, such as VULKAN_HPP_NO_EXCEPTIONS and VULKAN_HPP_NO_SMART_HANDLE . Different compilers have different command-lines for module pre-compilation; however, for initial use, some examples are provided below, assuming the same main.cpp consumer as above.
For MSVC, source vcvars64.bat or use a Developer Command Prompt/Developer PowerShell instance, and run the following:
cl.exe /std:c++20 /interface /TP < path-to-vulkan-hpp > vulkan.cppm
cl.exe /std:c++20 /reference vulkan=vulkan.ifc main.cpp vulkan.obj
.main.exeFor Clang, run the following:
clang++ -std=c++20 < path-to-vulkan-hpp > /vulkan.cppm -precompile -o vulkan.pcm
clang++ -std=c++20 -fprebuilt-module-path=. main.cpp vulkan.pcm -o main
./mainMore information about module compilation may be found at the respective compiler's documentation:
When you configure your project using CMake, you can enable SAMPLES_BUILD to add some sample projects to your solution. Most of them are ports from the LunarG samples, but there are some more, like CreateDebugUtilsMessenger, InstanceVersion, PhysicalDeviceDisplayProperties, PhysicalDeviceExtensions, PhysicalDeviceFeatures, PhysicalDeviceGroups, PhysicalDeviceMemoryProperties, PhysicalDeviceProperties, PhysicalDeviceQueueFamilyProperties, and RayTracing. All those samples should just compile and run. When you configure your project using CMake, you can enable TESTS_BUILD to add some test projects to your solution. Those tests are just compilation tests and are not required to run.
As vulkan.hpp is pretty big, some compilers might need some time to digest all that stuff. In order to potentially reduce the time needed to compile that header, a couple of defines will be introduced, that allow you to hide certain features. Whenever you don't need that corresponding feature, defining that value might improve your compile time. Currently, there are just a couple of such defines:
VULKAN_HPP_NO_SPACESHIP_OPERATOR , which removes the spaceship operator on structures (available with C++20)VULKAN_HPP_NO_TO_STRING , which removes the various vk::to_string functions on enums and bitmasks.VULKAN_HPP_USE_REFLECT , this one needs to be defined to use the reflection function on structures. It's very slow to compile, though! As Vulkan-Hpp often needs to switch between C++ vk-types and corresponding bit-identical C-types, using reinterpret_cast , it is highly recommended to use the compile option -fno-strict-aliasing to prevent potentially breaking compile optimizations.
There are a couple of defines you can use to control the feature set and behaviour of vulkan.hpp :
At various places in vulkan.hpp an assertion statement is used. By default, the standard assert funtions from <cassert> is called. By defining VULKAN_HPP_ASSERT before including vulkan.hpp , you can change that to any function with the very same interface.
If there are no exceptions enabled (see VULKAN_HPP_NO_EXCEPTIONS ), an assertion statement checks for a valid success code returned from every vulkan call. By default, this is the very same assert function as defined by VULKAN_HPP_ASSERT , but by defining VULKAN_HPP_ASSERT_ON_RESULT you can replace just those assertions with your own function, using the very same interface.
Every vk-function gets a Dispatcher as its very last argument, which defaults to VULKAN_HPP_DEFAULT_DISPATCHER . If VULKAN_HPP_DISPATCH_LOADER_DYNAMIC is defined to be 1 , it is defaultDispatchLoaderDynamic . This in turn is the dispatcher instance, which is defined by VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE , which has to be used exactly once in your sources. If, on the other hand, VULKAN_HPP_DISPATCH_LOADER_DYNAMIC is defined to something different from 1 , VULKAN_HPP_DEFAULT_DISPATCHER is set to be DispatchLoaderStatic() . You can use your own default dispatcher by setting VULKAN_HPP_DEFAULT_DISPATCHER to an object that provides the same API. If you explicitly set VULKAN_HPP_DEFAULT_DISPATCHER , you need to set VULKAN_HPP_DEFAULT_DISPATCHER_TYPE accordingly as well.
This names the default dispatcher type, as specified by VULKAN_HPP_DEFAULT_DISPATCHER . Per default, it is DispatchLoaderDynamic or DispatchLoaderStatic, depending on VULKAN_HPP_DISPATCH_LOADER_DYNAMIC being 1 or not 1 , respectively. If you explicitly set VULKAN_HPP_DEFAULT_DISPATCHER , you need to set VULKAN_HPP_DEFAULT_DISPATCHER_TYPE accordingly as well.
If you have not defined your own VULKAN_HPP_DEFAULT_DISPATCHER , and have VULKAN_HPP_DISPATCH_LOADER_DYNAMIC defined to be 1 (the default), you need to have the macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE exactly once in any of your source files to provide storage for that default dispatcher. VULKAN_HPP_STORAGE_API then controls the import/export status of that default dispatcher.
When this is defined before including vulkan.hpp , you essentially disable all enhanced functionality. All you then get is:
vk::Flags for bitmasks;vk::StructureChain for compile-time construction of structure chains.If this is not defined, you additionally get:
vk::ArrayProxy<> ), simplifying handling of array data; returning requested data; throwing exceptions on errors (as long as VULKAN_HPP_NO_EXCEPTIONS is not defined);VULKAN_HPP_NO_STRUCT_CONSTRUCTORS is not defined) (consuming vk::ArrayProxyNoTemporaries<> );vk::ArrayProxyNoTemporaries<> );vk::ArrayProxy<> and vk::ArrayProxyNoTemporaries<>vulkan_raii.hpp This either selects the dynamic (when it's 1 ) or the static (when it's not 1 ) DispatchLoader as the default one, as long as it's not explicitly specified by VULKAN_HPP_DEFAULT_DISPATCHER . By default, this is defined to be 1 if VK_NO_PROTOTYPES is defined, otherwise 0 .
By default, a little helper class DynamicLoader is used to dynamically load the vulkan library. If you set it to something different than 1 before including vulkan.hpp , this helper is not available, and you need to explicitly provide your own loader type for the function DispatchLoaderDynamic::init() .
When this is not externally defined and VULKAN_HPP_CPP_VERSION is at least 23 , VULKAN_HPP_EXPECTED is defined to be std::expected , and VULKAN_HPP_UNEXPECTED is defined to be std::unexpected .
By default, the member m_mask of the Flags class template is private. This is to prevent accidentally setting a Flags with some inappropriate value. But it also prevents using a Flags , or a structure holding a Flags , to be used as a non-type template parameter. If you really need that functionality, and accept the reduced security, you can use this define to change the access specifier for m_mask from private to public, which allows using a Flags as a non-type template parameter.
This define can be used to enable m_handle = exchange( rhs.m_handle, {} ) in move constructors of Vulkan-Hpp handles, which default-initializes the rhs underlying value. By default Vulkan-Hpp handles behave like trivial types -- move constructors copying value.
This define can be used to specify your own hash combiner function. In order to determine the hash of a vk-structure, the hashes of the members of that struct are to be combined. This is done by this define, which by default is identical to what the function boost::hash_combine() does. It gets the type of the to-be-combined value, the seed, which is the combined value up to that point, and finally the to-be-combined value. This hash calculation determines a "shallow" hash, as it takes the hashes of any pointer in a structure, and not the hash of a pointed-to value.
This is set to be the compiler-dependent attribute used to mark functions as inline. If your compiler happens to need some different attribute, you can set this define accordingly before including vulkan.hpp .
By default, the namespace used with vulkan.hpp is vk . By defining VULKAN_HPP_NAMESPACE before including vulkan.hpp , you can adjust this.
By default, the file vulkan_to_string.hpp is included by vulkan.hpp and provides functions vk::to_string for enums and bitmasks. If you don't need those functions, you can define VULKAN_HPP_NO_TO_STRING to prevent that inclusion. If you have certain files where you want to use those functions nevertheless, you can explicitly include vulkan_to_string.hpp there.
With C++20, designated initializers are available. Their use requires the absence of any user-defined constructors. Define VULKAN_HPP_NO_CONSTRUCTORS to remove constructors from structs and unions.
When a vulkan function returns an error code that is not specified to be a success code, an exception is thrown unless VULKAN_HPP_NO_EXCEPTIONS is defined before including vulkan.hpp .
With C++17, all vk-functions returning something are declared with the attribute [[nodiscard]] . This can be removed by defining VULKAN_HPP_NO_NODISCARD_WARNINGS before including vulkan.hpp .
By defining VULKAN_HPP_NO_SETTERS before including vulkan.hpp , setter member functions will not be available within structs and unions. Modifying their data members will then only be possible via direct assignment.
By defining VULKAN_HPP_NO_SMART_HANDLE before including vulkan.hpp , the helper class vk::UniqueHandle and all the unique handle types are not available.
With C++20, the so-called spaceship-operator <=> is introduced. If that operator is supported, all the structs and classes in vulkan.hpp use the default implementation of it. As currently some implementations of this operator are very slow, and others seem to be incomplete, by defining VULKAN_HPP_NO_SPACESHIP_OPERATOR before including vulkan.hpp you can remove that operator from those structs and classes.
By default, if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL is enabled on Win32, vulkan.hpp declares HINSTANCE , LoadLibraryA , and other required symbols. It could cause conflicts with the Windows.h alternatives, such as WindowsHModular . With this define, you can disable these declarations, but you will have to declare them before the vulkan.hpp is included.
If both, VULKAN_HPP_NO_EXCEPTIONS and VULKAN_HPP_EXPECTED are defined, the vk::raii-classes don't throw exceptions. That is, the actual constructors are not available, but the creation-functions must be used. For more details have a look at the vk_raii_ProgrammingGuide.md .
Even though vk::UniqueHandle and vk::SharedHandle are semantically close to pointers, an implicit cast operator to the underlying vk::Handle might be handy. You can add that implicit cast operator by defining VULKAN_HPP_SMART_HANDLE_IMPLICIT_CAST .
With this define you can specify whether the DispatchLoaderDynamic is imported or exported (see VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE ). If VULKAN_HPP_STORAGE_API is not defined externally, and VULKAN_HPP_STORAGE_SHARED is defined, depending on the VULKAN_HPP_STORAGE_SHARED_EXPORT being defined, VULKAN_HPP_STORAGE_API is either set to __declspec( dllexport ) (for MSVC) / __attribute__( ( visibility( "default" ) ) ) (for gcc or clang) or __declspec( dllimport ) (for MSVC), respectively. For other compilers, you might specify the corresponding storage by defining VULKAN_HPP_STORAGE_API on your own.
32-bit vulkan is not typesafe for non-dispatchable handles, so we don't allow copy constructors on this platform by default. To enable this feature on 32-bit platforms, #define VULKAN_HPP_TYPESAFE_CONVERSION 1 . To disable this feature on 64-bit platforms, #define VULKAN_HPP_TYPESAFE_CONVERSION 0 .
See VULKAN_HPP_EXPECTED .
With this define you can include a reflection mechanism on the vk-structures. It adds a function reflect that returns a tuple-version of the structure. That tuple then could easily be iterated. But at least for now, that feature takes lots of compile-time resources, so currently it is recommended to enable that feature only if you're willing to pay that price.
Feel free to submit a PR to add to this list.
Copyright 2015-2020 The Khronos Group Inc.
Apache 라이센스, 버전 2.0 ( "라이센스")에 따라 라이센스가 부여되었습니다. 라이센스를 준수하는 것 외에는이 파일을 사용할 수 없습니다. 라이센스 사본을 얻을 수 있습니다
http://www.apache.org/licenses/LICENSE-2.0
해당 법률에 의해 요구되거나 서면에 동의하지 않는 한, 라이센스에 따라 배포 된 소프트웨어는 명시 적 또는 묵시적 보증 또는 조건없이 "그대로"기준으로 배포됩니다. 라이센스에 따른 특정 언어 통치 권한 및 제한 사항에 대한 라이센스를 참조하십시오.