เป้าหมายของ Vulkan-HPP คือการให้ส่วนหัวเฉพาะการผูก C ++ สำหรับ Vulkan C API เพื่อปรับปรุงประสบการณ์นักพัฒนา Vulkan โดยไม่ต้องแนะนำค่าใช้จ่ายในการรันไทม์ CPU มันเพิ่มคุณสมบัติเช่นประเภทความปลอดภัยสำหรับ enums และ bitfields, การสนับสนุนคอนเทนเนอร์ STL, ข้อยกเว้นและการแจกแจงอย่างง่าย
| แพลตฟอร์ม | สร้างสถานะ |
|---|---|
| ลินเวกซ์ |
Vulkan-HPP เป็นส่วนหนึ่งของ Lunarg Vulkan SDK ตั้งแต่เวอร์ชัน 1.0.24 เพียงแค่ #include <vulkan/vulkan.hpp> และคุณพร้อมที่จะใช้การผูก C ++ หากคุณใช้เวอร์ชัน Vulkan ที่ยังไม่ได้รับการสนับสนุนโดย Vulkan SDK คุณสามารถค้นหาส่วนหัวเวอร์ชันล่าสุดได้ที่นี่
Vulkan-HPP ต้องการคอมไพเลอร์ที่มีความสามารถ C ++ 11 เพื่อรวบรวม คอมไพเลอร์ต่อไปนี้เป็นที่รู้จักกันในการทำงาน:
ในการสร้างตัวอย่างและการทดสอบในเครื่องคุณจะต้องโคลนที่เก็บนี้และเรียกใช้ cmake เพื่อสร้างไฟล์บิลด์ที่จำเป็น
ติดตั้งการพึ่งพา
เปิดเปลือกหอยซึ่งให้พื้นที่เก็บข้อมูลและโคลนด้วย:
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
คุณอาจต้องระบุเครื่องกำเนิดไฟฟ้าผ่าน -G สำหรับรายการทั้งหมดของเครื่องกำเนิดไฟฟ้าที่ดำเนินการ cmake -G
vulkan.hpp จากไฟล์รีจิสทรี vk.xml XML ให้เพิ่ม -DVULKAN_HPP_RUN_GENERATOR=ON ตัวเลือกลงในบรรทัดคำสั่ง cmake เปิดโครงการที่สร้างขึ้นด้วย IDE เช่น Visual Studio หรือเปิดกระบวนการสร้างด้วย cmake --build build --parallel
ตัวเลือก: ในการอัปเดต Vulkan-HPP และ submodules ของมันจะดำเนินการ git pull --recurse-submodules
คุณสามารถดาวน์โหลดและติดตั้ง Vulkan-HPP โดยใช้ VCPKG Perdency Manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install vulkan-headersพอร์ต Vulkan-HPP ใน VCPKG ได้รับการปรับปรุงให้ทันสมัยโดยสมาชิกในทีม Microsoft และผู้สนับสนุนชุมชน หากเวอร์ชันล้าสมัยโปรดสร้างปัญหาหรือดึงคำขอบนที่เก็บ VCPKG
หากพบโปรแกรม clang-format โดย cmake define CLANG_FORMAT_EXECUTABLE จะถูกตั้งค่าตามนั้น ในกรณีนั้น vulkan.hpp ที่สร้างขึ้นจะถูกจัดรูปแบบโดยใช้ไฟล์ .clang-format ที่อยู่ในไดเรกทอรีรากของโครงการนี้ มิฉะนั้นจะถูกจัดรูปแบบเป็นฮาร์ดรหัสในเครื่องกำเนิดไฟฟ้า
ไฟล์ VulkanHpp.natvis ให้มุมมองที่กำหนดเองบน vk::Flags สำหรับ Visual Studio หากคุณเพิ่มไฟล์นี้ลงในไดเรกทอรี Natvis เฉพาะผู้ใช้ของการติดตั้ง Visual Studio ของคุณ (%UserProfile% Documents Visual Studio 2022 Visualizers) คุณจะได้รับ vk::Flags ที่จัดรูปแบบได้ดีในดีบักเกอร์ของคุณด้วยโครงการ Visual Studio ทั้งหมดของคุณ
เพื่อหลีกเลี่ยงการชนกันของชื่อกับ Vulkan C API การผูก C ++ จะอยู่ในเนมสเปซ vk กฎต่อไปนี้ใช้กับการตั้งชื่อใหม่:
Vk นอกจากนี้ตัวอักษรตัวแรกของฟังก์ชั่นนั้นเป็นตัวพิมพ์เล็กvkCreateInstance สามารถเข้าถึงได้เป็น vk::createInstanceVkImageTiling สามารถเข้าถึงได้เป็น vk::ImageTilingVkImageCreateInfo สามารถเข้าถึงได้เป็น vk::ImageCreateInfoVK_ และลบ Infix หากประเภท enum เป็นส่วนขยายคำต่อท้ายส่วนขยายจะถูกลบออกจากค่า enumในกรณีอื่น ๆ ทั้งหมดคำต่อท้ายส่วนขยายยังไม่ได้ถูกลบออก
VK_IMAGETYPE_2D ตอนนี้เป็น vk::ImageType::e2DVK_COLOR_SPACE_SRGB_NONLINEAR_KHR ตอนนี้ vk::ColorSpaceKHR::eSrgbNonlinearVK_STRUCTURE_TYPE_PRESENT_INFO_KHR ตอนนี้ vk::StructureType::ePresentInfoKHR_BIT ได้ถูกลบออก ในบางกรณีอาจจำเป็นต้องย้าย Vulkan-HPP ไปยังเนมสเปซแบบกำหนดเอง สิ่งนี้สามารถทำได้โดยการกำหนด VULKAN_HPP_NAMESPACE ก่อนที่จะรวม Vulkan-HPP
Vulkan-HPP ประกาศชั้นเรียนสำหรับการจัดการทั้งหมดเพื่อให้แน่ใจว่ามีความปลอดภัยแบบเต็มรูปแบบและเพื่อเพิ่มการสนับสนุนสำหรับฟังก์ชั่นสมาชิกในการจัดการ มีการเพิ่มฟังก์ชั่นสมาชิกลงในคลาสที่จับสำหรับแต่ละฟังก์ชั่นที่ยอมรับการจับที่สอดคล้องกันเป็นพารามิเตอร์แรก แทนที่จะเป็น vkBindBufferMemory(device, ...) เราสามารถเขียน device.bindBufferMemory(...) หรือ vk::bindBufferMemory(device, ...)
มีส่วนหัวเพิ่มเติมชื่อ vulkan_raii.hpp ที่สร้างขึ้น ส่วนหัวนั้นมีคลาส wrapper ที่สอดคล้องกับ RAII สำหรับประเภทที่จับ นั่นคือสำหรับเช่นประเภทที่จับ VkInstance มี wrapper ที่สอดคล้องกับ RAII vk::raii::Instance โปรดดูตัวอย่างโดยใช้คลาสเหล่านั้นในไดเรกทอรี raii_samples
บนแพลตฟอร์ม 64 บิต Vulkan-HPP รองรับการแปลงโดยนัยระหว่าง C ++ Vulkan Handles และ C Vulkan ที่จัดการ บนแพลตฟอร์ม 32 บิตที่จับที่ไม่สามารถสลับได้ทั้งหมดถูกกำหนดเป็น uint64_t ดังนั้นจึงป้องกันการตรวจสอบประเภทการแปลงในเวลาที่รวบรวมซึ่งจะจับการมอบหมายระหว่างประเภทด้ามจับที่เข้ากันไม่ได้ เนื่องจาก Vulkan-HPP นั้นไม่ได้เปิดใช้งานการแปลงโดยนัยสำหรับแพลตฟอร์ม 32 บิตโดยค่าเริ่มต้นและขอแนะนำให้ใช้ static_cast สำหรับการแปลงเช่นนี้: VkImage = static_cast<VkImage>(cppImage) เพื่อป้องกันการเปลี่ยน หากคุณกำลังพัฒนารหัสของคุณบนแพลตฟอร์ม 64 บิต แต่ต้องการรวบรวมรหัสของคุณสำหรับแพลตฟอร์ม 32 บิตโดยไม่ต้องเพิ่ม CASTS ที่ชัดเจนคุณสามารถกำหนด VULKAN_HPP_TYPESAFE_CONVERSION เป็น 1 ในระบบการสร้างของคุณหรือก่อนรวม vulkan.hpp บนแพลตฟอร์ม 64 บิตที่กำหนดนี้ถูกตั้งค่าเป็น 1 โดยค่าเริ่มต้นและสามารถตั้งค่าเป็น 0 เพื่อปิดใช้งานการแปลงโดยนัย
คุณลักษณะ enum ที่กำหนดขอบเขตจะเพิ่มความปลอดภัยประเภทให้กับธง แต่ยังป้องกันการใช้บิตแฟล็กเป็นอินพุตสำหรับการดำเนินการ bitwise เช่น & และ | -
ในฐานะที่เป็นโซลูชัน Vulkan-HPP จัดเตรียมเทมเพลตคลาส vk::Flags ซึ่งนำการดำเนินการมาตรฐานเช่น &= , |= , & , และ | ไปยัง enums ที่กำหนดขอบเขตของเรา ยกเว้นการเริ่มต้นด้วย 0 คลาสนี้จะมีพฤติกรรมเหมือน bitmask ปกติที่มีการปรับปรุงว่ามันเป็นไปไม่ได้ที่จะตั้งค่าบิตที่ไม่ได้ระบุโดย enum ที่เกี่ยวข้องโดยบังเอิญ นี่คือตัวอย่างบางส่วนสำหรับการจัดการ Bitmask:
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 One มักจะต้องสร้างโครงสร้าง CreateInfo บางอย่างซึ่งอธิบายถึงที่จับใหม่ ซึ่งอาจส่งผลให้รหัสยาวมากเท่าที่จะเห็นได้ในตัวอย่าง 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 Struct ตามสนาม:
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 ++ รองรับการเริ่มต้นที่กำหนด เนื่องจากคุณลักษณะนั้นจำเป็นต้องไม่มีตัวสร้างที่ผู้ใช้สั่งหรือสืบทอดมาคุณต้อง #define VULKAN_HPP_NO_CONSTRUCTORS ซึ่งจะลบโครงสร้างและตัวสร้างสหภาพทั้งหมดออกจาก vulkan.hpp จากนั้นคุณสามารถใช้การเริ่มต้นรวม VK-lines สองสามตัวแรกในแหล่งที่มาของคุณอาจมีลักษณะ:
// 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); โปรดทราบว่าคำสั่ง Designator จำเป็นต้องตรงกับคำสั่งประกาศ หมายเหตุเช่นกันว่าตอนนี้คุณสามารถตั้งค่าสมาชิก sType ของโครงสร้าง VK ได้อย่างชัดเจน นี่ไม่ใช่ neccessary (เนื่องจากมีการเริ่มต้นอย่างถูกต้องโดยค่าเริ่มต้น) หรือแนะนำ
Vulkan API มีหลายสถานที่ที่ต้องการ (นับ, ตัวชี้) เป็นข้อโต้แย้งฟังก์ชั่นสองรายการและ C ++ มีคอนเทนเนอร์ไม่กี่ตัวที่แมปเข้ากับคู่นี้อย่างสมบูรณ์แบบ เพื่อลดความซับซ้อนของการพัฒนาการผูก Vulkan-HPP ได้แทนที่คู่อาร์กิวเมนต์เหล่านั้นด้วยเทมเพลต vk::ArrayProxy Class ซึ่งยอมรับอาร์เรย์ที่ว่างเปล่าและค่าเดียวเช่นเดียวกับคอนเทนเนอร์ STL std::initializer_list , std::array และ std::vector เป็นข้อโต้แย้งสำหรับการก่อสร้าง วิธีนี้เวอร์ชัน Vulkan ที่สร้างขึ้นเดียวสามารถยอมรับอินพุตที่หลากหลายได้โดยไม่ต้องมีการระเบิดแบบ combinatoric ซึ่งจะเกิดขึ้นเมื่อสร้างฟังก์ชั่นสำหรับแต่ละประเภทคอนเทนเนอร์
นี่คือตัวอย่างโค้ดเกี่ยวกับวิธีการใช้ 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 สร้างการอ้างอิงสำหรับพอยน์เตอร์ไปยัง structs การแปลงนี้ช่วยให้ผ่านโครงสร้างชั่วคราวไปยังฟังก์ชั่นซึ่งอาจส่งผลให้รหัสสั้นกว่า ในกรณีที่อินพุตเป็นตัวเลือกและยอมรับตัวชี้โมฆะประเภทพารามิเตอร์จะเป็น 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>() มันปรับเปลี่ยน structurechain เพื่อให้โครงสร้างที่ระบุไม่ได้เป็นส่วนหนึ่งของโซ่ PNEXT อีกต่อไป โปรดทราบว่าเค้าโครงหน่วยความจำจริงของ structurechain ไม่ได้รับการแก้ไขโดยฟังก์ชั่นนั้น ในกรณีที่โครงสร้างเดียวกันนี้จะต้องเพิ่มใหม่ให้เป็น structurechain อีกครั้งให้ใช้ vk::StructureChain::relink<ClassType>()
บางครั้งผู้ใช้จะต้องผ่านห่วงโซ่โครงสร้าง preelocated เพื่อสอบถามข้อมูล สำหรับกรณีเหล่านั้นมีสองฟังก์ชั่น getter ที่สอดคล้องกัน หนึ่งที่มีเทมเพลตที่หลากหลายสร้างห่วงโซ่โครงสร้างขององค์ประกอบอย่างน้อยสององค์ประกอบเพื่อสร้างค่าส่งคืน:
// 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 เป็นรหัสความสำเร็จ การเปลี่ยนแปลงเชิงตรรกะนั้นจะไม่ปรากฏใน C API แต่ใน C ++ API เช่นฟังก์ชั่นดังกล่าวจะส่งคืน vk::ResultValue<SomeType> บางครั้ง> แทนที่จะเป็นเพียง SomeType ในกรณีดังกล่าว (หายาก) คุณจะต้องปรับ CPP-sources ของคุณเพื่อสะท้อนให้เห็นถึงการเปลี่ยนแปลง API
หากการจัดการข้อยกเว้นถูกปิดใช้งานโดยการกำหนด VULKAN_HPP_NO_EXCEPTIONS ประเภทของ vk::ResultValue<SomeType>::type คือโครงสร้างที่ถือ vk::Result และ SomeType โครงสร้างนี้รองรับการเปิดตัวค่าส่งคืนโดยใช้ std::tie
ในกรณีที่คุณไม่ต้องการใช้ vk::ArrayProxy และการแปลงค่าส่งคืนคุณยังสามารถเรียกฟังก์ชัน C-style ธรรมดาได้ ด้านล่างนี้เป็นสามตัวอย่างที่แสดง 3 วิธีในการใช้ 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
}สำคัญ
Vulkan จัดการใน vk -namespace ไม่สนับสนุน Raii ดังนั้นคุณต้องล้างข้อมูลทรัพยากรของคุณในตัวจัดการข้อผิดพลาด! แต่คุณสามารถใช้คลาส Handle Wrapper ใน 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 มีที่จับที่ไม่ซ้ำกัน vk::UniqueType ซึ่งจะลบทรัพยากร Vulkan พื้นฐานเมื่อถูกทำลายเช่น vk::UniqueBuffer เป็นที่จับที่ไม่ซ้ำกันสำหรับ vk::Buffer
สำหรับแต่ละฟังก์ชั่นที่สร้างที่จับ Vulkan ประเภท vk::Type Vulkan-HPP ให้เวอร์ชันที่สองซึ่งส่งคืน vk::UniqueType เช่นสำหรับ vk::Device::createBuffer มี vk::Device::createBufferUnique และสำหรับ vk::allocateCommandBuffers มี vk::allocateCommandBuffersUnique
โปรดทราบว่าการใช้ vk::UniqueHandle นั้นมีค่าใช้จ่ายเนื่องจากการลบส่วนใหญ่จะต้องจัดเก็บ vk::AllocationCallbacks และที่จับหลักที่ใช้สำหรับการก่อสร้างเพราะจำเป็นต้องมีการทำลายอัตโนมัติ
Vulkan-HPP ให้อินเทอร์เฟซ vk::SharedHandle<Type> สำหรับแต่ละประเภทที่จับ Vulkan vk::Type มีที่จับที่ใช้ร่วมกัน vk::SharedType ซึ่งจะลบทรัพยากร Vulkan พื้นฐานเมื่อถูกทำลายเช่น vk::SharedBuffer เป็นที่จับที่ใช้ร่วมกันสำหรับ vk::Buffer
ซึ่งแตกต่างจาก vk::UniqueHandle , vk::SharedHandle ใช้ความเป็นเจ้าของทรัพยากรร่วมกันรวมถึงผู้ปกครอง ซึ่งหมายความว่าการจัดการผู้ปกครองจะไม่ถูกทำลายจนกว่าทรัพยากรเด็กทั้งหมดจะถูกลบ สิ่งนี้มีประโยชน์สำหรับทรัพยากรที่ใช้ร่วมกันระหว่างหลายเธรดหรือวัตถุ
กลไกนี้ช่วยให้มั่นใจได้ว่าคำสั่งทำลายล้างที่ถูกต้องแม้ว่าผู้ปกครอง vk::SharedHandle จะถูกทำลายก่อนที่เด็กจะจัดการ มิฉะนั้นมือจับจะทำงานเหมือน std::shared_ptr vk::SharedInstance หรือวัตถุลูกใด ๆ ของมันควรจะเป็นครั้งสุดท้ายที่จะลบ (สร้างครั้งแรกอันดับแรกในการประกาศชั้นเรียน)
ยังไม่มีฟังก์ชั่นที่ส่งคืน vk::SharedHandle โดยตรง แต่คุณสามารถสร้าง vk::SharedHandle จาก vk::Handle :
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 คุณสามารถสร้าง vk::SharedHandle Overload สำหรับประเภทด้ามจับของคุณเองหรือที่จับที่ใช้ร่วมกันของตัวเองโดยให้อาร์กิวเมนต์เทมเพลตหลายรายการแก่ SharedHandleBase :
ด้วยสิ่งนี้ให้ฟังก์ชั่นการทำลายล้างแบบคงที่แบบกำหนดเอง 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 แล้วยังมีชุดของคลาส wrapper สำหรับประเภทที่จับทั้งหมดที่ติดตาม Raii-Paradigm (การได้มาซึ่งทรัพยากรคือการเริ่มต้น) ที่มีให้ใน vk::raii Namespace
ในขณะที่ vk::UniqueHandle จับที่ห่อหุ้มด้วย std::unique_ptr และ vk::SharedHandle เลียนแบบด้ามจับที่ห่อหุ้มด้วย std::shared_ptr รวมถึงข้อมูลผู้ปกครอง vk::raii::Handle เป็นเพียงชั้นเรียน ดังนั้นคุณมีอิสระที่จะใช้เป็นค่าหรือห่อด้วยตัวชี้อัจฉริยะ
นอกเหนือจาก vk::Handles คลาสที่จัดการทั้งหมดนั้นจำเป็นต้องเก็บข้อมูลเพิ่มเติมและดังนั้นจึงไม่เหมือนกันกับ Vulkan C-handles
ในฐานะที่เป็น vk::UniqueHandles และ vk::SharedHandles ใช้ dispatcher เดียวกับ vk::Handles พวกเขาสามารถผสมและจับคู่ได้อย่างง่ายดาย vk::raii::Handles ใช้ dispatchers ที่แตกต่างกันเล็กน้อยดังนั้นจึงไม่สามารถใช้งานได้กับที่จับอื่น ๆ ! นั่นคือสำหรับ vk-Handles , vk::UniqueHandles และ vk::SharedHandles คุณต้องสร้างอินสแตนซ์ดิสแพตเชอร์ทั่วโลกตามที่อธิบายไว้ใน https://github.com/khronosgroup/vulkan-hpp#extensions สำหรับ vk::raii-Handles สิ่งนี้ไม่จำเป็นเพราะพวกเขารักษาผู้แจกจ่ายของตัวเอง ข้อได้เปรียบที่ยิ่งใหญ่ที่นี่คือเมื่อคุณมีอุปกรณ์หลายอย่าง: ฟังก์ชั่นที่เรียกว่าผ่าน vk::raii-Handles เรียกฟังก์ชั่นเฉพาะของอุปกรณ์เสมอ
บางครั้งมันจำเป็นต้องใช้ std::vector ด้วยการจัดสรรที่กำหนดเอง Vulkan-HPP รองรับเวกเตอร์ที่มีการจัดสรรแบบกำหนดเองเป็นอินพุตสำหรับ vk::ArrayProxy และสำหรับฟังก์ชั่นที่ส่งคืนเวกเตอร์ สำหรับกรณีหลังให้เพิ่มการจัดสรรแบบกำหนดเองที่คุณชื่นชอบเป็นอาร์กิวเมนต์เทมเพลตในการเรียกใช้ฟังก์ชันเช่นนี้:
std::vector<LayerProperties, MyCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties<MyCustomAllocator>(); นอกจากนี้คุณยังสามารถใช้ตัวจัดสรรแบบกำหนดเองได้โดยให้มันเป็นอาร์กิวเมนต์สำหรับฟังก์ชั่นเหล่านั้น น่าเสียดายที่การทำให้คอมไพเลอร์มีความสุขคุณต้องตั้งค่าอาร์กิวเมนต์การจัดส่งอย่างชัดเจน เพื่อให้ได้ค่าเริ่มต้นที่นั่น {} ง่าย ๆ จะพอเพียง:
MyStatefulCustomAllocator allocator;
std::vector<LayerProperties, MyStatefulCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties(allocator, {}); ทั่ว vulkan.hpp มีการโทรไปยังฟังก์ชั่นการยืนยันสองสามครั้ง โดยการกำหนด 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 จัดเตรียมกลไกการส่งต่อฟังก์ชั่นโดยการยอมรับคลาสการจัดส่งเป็นพารามิเตอร์สุดท้ายในการเรียกใช้ฟังก์ชันแต่ละครั้ง คลาส Dispatch จะต้องจัดให้มีประเภท callable สำหรับแต่ละฟังก์ชัน 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_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 จากนั้นคุณสามารถใช้งานได้โดย Macro VULKAN_HPP_DEFAULT_DISPATCHER ดังที่แสดงในตัวอย่างรหัสด้านล่าง การสร้าง vk::DispatchLoaderDynamic เต็มรูปแบบเป็นกระบวนการสองถึงสามขั้นตอนที่คุณมีสามตัวเลือกสำหรับขั้นตอนแรก:
vk::DynamicLoader : VULKAN_HPP_DEFAULT_DISPATCHER.init();getProcAddress (เปรียบเทียบกับ vk::DynamicLoader ใน vulkan.hpp ): 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);หลังจากขั้นตอนที่สองข้างต้นตัวแจกจ่ายจะทำงานได้อย่างสมบูรณ์ การเพิ่มขั้นตอนที่สามอาจส่งผลให้รหัสมีประสิทธิภาพมากขึ้น แต่ถ้าคุณตั้งใจจะใช้อุปกรณ์หลายตัวคุณสามารถละเว้นขั้นตอนที่สามนั้นและปล่อยให้ไดรเวอร์ทำอุปกรณ์สลับ
ในบางกรณีที่เก็บข้อมูลสำหรับ dispatchloadderdynamic ควรฝังใน DLL สำหรับกรณีเหล่านั้นคุณต้องกำหนด VULKAN_HPP_STORAGE_SHARED เพื่อบอก Vulkan-HPP ว่าที่เก็บข้อมูลอยู่ใน DLL เมื่อรวบรวม DLL ด้วยที่เก็บข้อมูลก็จำเป็นต้องกำหนด VULKAN_HPP_STORAGE_SHARED_EXPORT เพื่อส่งออกสัญลักษณ์ที่ต้องการ
สำหรับฟังก์ชั่นทั้งหมด VULKAN_HPP_DEFAULT_DISPATCHER นั้นเป็นค่าเริ่มต้นสำหรับอาร์กิวเมนต์สุดท้ายของฟังก์ชั่นนั้น หากคุณต้องการให้ผู้ส่งข้อมูลสำหรับการโทรแต่ละฟังก์ชันแต่ละรายการอย่างชัดเจน (เมื่อคุณมีตัวแจกจ่ายหลาย VULKAN_HPP_NO_DEFAULT_DISPATCHER สำหรับอุปกรณ์ที่แตกต่างกัน) และคุณต้องการให้แน่ใจว่าคุณไม่ได้พลาดการโทร vulkan.hpp ก์ชั่นใด ๆ
vulkan.hpp มีลักษณะสองสามประเภท, การผ่อนคลายเทมเพลตเมทโรเมด:
template <typename EnumType, EnumType value> struct CppType แผนที่ค่า IndexType ( IndexType::eUint16 , IndexType::eUint32 , ... ) กับประเภทที่สอดคล้องกัน ( uint16_t , uint32_t , ... ) ตาม Type สมาชิก; แผนที่ค่า ObjectType ( ObjectType::eInstance , ObjectType::eDevice , ... ) กับประเภทที่เกี่ยวข้อง ( vk::Instance , vk::Device , ... ) ตาม Type สมาชิก; แผนที่ค่า DebugReportObjectType ( DebugReportObjectTypeEXT::eInstance , DebugReportObjectTypeEXT::eDevice , ... ) กับประเภทที่เกี่ยวข้อง ( vk::Instance , vk::Device , ... ) ตาม Type สมาชิก;template <typename T> struct IndexTypeValue แผนที่ประเภทสเกลาร์ ( uint16_t , uint32_t , ... ) กับค่า IndexType ที่สอดคล้องกัน ( IndexType::eUint16 , IndexType::eUint32 , ... )template <typename T> struct isVulkanHandleType แมปประเภทเป็น true ถ้าและเฉพาะในกรณีที่เป็นคลาสที่จับ ( vk::Instance , vk::Device , ... ) โดย value สมาชิกคงที่HandleClass::CType แมปคลาสที่จับ ( vk::Instance , vk::Device , ... ) ไปยังประเภท C ที่สอดคล้องกัน ( VkInstance , VkDevice , ... ) โดยประเภทสมาชิก CTypeHandleClass::objectType แมปคลาสที่จับ ( vk::Instance , vk::Device , ... ) กับค่า ObjectType ที่สอดคล้องกัน ( ObjectType::eInstance , ObjectType::eDevice , ... ) โดยสมาชิก objectTypeHandleClass::debugReportObjectType แมปคลาสที่จับ ( vk::Instance DebugReportObjectTypeEXT::eInstance vk::Device DebugReportObjectTypeEXT::eDevice ... ) กับค่า DebugReportObjectTypeEXT ที่สอดคล้อง debugReportObjectType ด้วยส่วนหัวเพิ่มเติม vulkan_format_traits.hpp มีฟังก์ชั่นลักษณะสองอย่างใน vk::Format ด้วย C ++ 14 ขึ้นไปฟังก์ชั่นเหล่านั้นทั้งหมดจะถูกทำเครื่องหมายว่าเป็น constexpr ซึ่งมีอาร์กิวเมนต์ที่เหมาะสมพวกเขาจะได้รับการแก้ไขในเวลาคอมไพล์
uin8_t blockSize( vk::Format format ); รับขนาดบล็อก Texel ของรูปแบบนี้ในไบต์uint8_t texelsPerBlock( vk::Format format ); รับจำนวน Texels ในบล็อก Texelstd::array<uint8_t, 3> blockExtent( vk::Format format ); รับขอบเขตสามมิติของบล็อก Texelchar const * compressionScheme( vk::Format format ); รับคำอธิบายที่เป็นข้อความของรูปแบบการบีบอัดของรูปแบบนี้หรือข้อความที่ว่างเปล่าหากไม่ได้บีบอัดbool isCompressed( vk::Format format ); จริงถ้ารูปแบบเป็นรูปแบบบีบอัดมิฉะนั้นเท็จ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 ); รับจำนวนบิตในองค์ประกอบนี้หากไม่ได้บีบอัดมิฉะนั้น 0char const * componentName( vk::Format format, uint8_t component ); รับชื่อขององค์ประกอบนี้เป็น C-Stringchar const * componentNumericFormat( vk::Format format, uint8_t component ); รับรูปแบบตัวเลขของส่วนประกอบนี้เป็น C-Stringuint8_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 สำหรับ wrappers โครงสร้าง ด้วย VULKAN_HPP_HASH_COMBINE คุณสามารถกำหนดแฮชของคุณเองรวมอัลกอริทึมสำหรับองค์ประกอบโครงสร้าง
ด้วยส่วนหัวเพิ่มเติม vulkan_extension_inspection.hpp ฟังก์ชั่นบางอย่างเพื่อตรวจสอบส่วนขยาย ด้วย C ++ 20 ขึ้นไปฟังก์ชั่นเหล่านั้นบางอย่างจะถูกทำเครื่องหมายว่าเป็น constexpr ซึ่งมีอาร์กิวเมนต์ที่เหมาะสมพวกเขาจะได้รับการแก้ไขในเวลาคอมไพล์ แต่ละส่วนขยายจะถูกระบุโดยสตริงที่ถือชื่อ โปรดทราบว่ามีการกำหนดด้วยชื่อนั้นสำหรับแต่ละส่วนขยาย ฟังก์ชั่นบางอย่างอาจให้ข้อมูลที่ขึ้นอยู่กับเวอร์ชัน Vulkan เนื่องจากฟังก์ชั่นทั้งหมดที่นี่ทำงานเพียงอย่างเดียวกับสตริงเวอร์ชัน Vulkan จะถูกเข้ารหัสโดยสตริงที่ขึ้นต้นด้วย "VK_Version_" ตามด้วย Major และรุ่นรองซึ่งคั่นด้วย undersore เช่นนี้: "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 ); สมาชิกคน first ของ std::pair ที่ส่งคืนนั้นเป็นจริงหากมีการระบุส่วนขยายที่กำหนดไว้สำหรับเวอร์ชัน Vulkan ที่กำหนดมิฉะนั้น false สมาชิกคน second ของคู่ std::pair ที่ส่งคืนเป็นเวกเตอร์ของเวกเตอร์ของส่วนขยายโดยแสดงรายการส่วนขยายแยกต่างหากส่วนขยายที่กำหนดขึ้นอยู่กับรุ่น 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 ); ส่งคืน true หากส่วนขยายที่กำหนดถูกเลิกใช้โดยส่วนขยายอื่น ๆ หรือเวอร์ชัน VulkanVULKAN_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 ); ส่งคืน true หากส่วนขยายที่กำหนดล้าสมัยโดยส่วนขยายอื่น ๆ หรือเวอร์ชัน VulkanVULKAN_HPP_CONSTEXPR_20 bool isPromotedExtension( std::string const & extension ); ส่งคืน true หากส่วนขยายที่กำหนดได้รับการเลื่อนตำแหน่งเป็นส่วนขยายอื่น ๆ หรือเวอร์ชัน Vulkanคำเตือน
รุ่นปัจจุบันของ Microsoft Visual Studio 2022 ไม่สามารถจัดการโมดูล Vulkan.cppm ได้ มีการยื่นข้อผิดพลาด (https://developercommunity.visualstudio.com/t/on-building-a-c20-module:-fatal-error/10469799#t-nd10485943) อย่างน้อยคุณสามารถใช้คุณสมบัตินี้ได้หากคุณไม่ต้องการหรือต้องการใช้ vk::UniqueHandle หรือ vk::SharedHandle โดยการกำหนด VULKAN_HPP_NO_SMART_HANDLE
Vulkan-HPP จัดเตรียมโมดูล C ++ ชื่อ vulkan_hpp ใน vulkan.cppm โมดูล C ++ มีวัตถุประสงค์เพื่อแทนที่ไฟล์ส่วนหัว โมดูลมีศักยภาพในการปรับปรุงเวลาการรวบรวมอย่างมากสำหรับโครงการขนาดใหญ่เนื่องจากการประกาศและคำจำกัดความอาจถูกแชร์ได้ง่ายในหน่วยการแปลโดยไม่ต้องแยกวิเคราะห์ส่วนหัวซ้ำ ๆ Vulkan-HPP มีส่วนหัวที่ยาวมาก (เช่น vulkan_structs.hpp ) และโมดูล C ++ มีแนวโน้มที่จะสั้นลงเวลาคอมไพล์สำหรับโครงการที่ใช้ในปัจจุบัน
คุณสมบัตินี้ต้องการคอมไพเลอร์ล่าสุดพร้อมการสนับสนุน C ++ 20 ที่สมบูรณ์:
cl.exe 19.28 หรือใหม่กว่า)หากคุณตั้งใจจะใช้การสนับสนุนโมดูล C ++ ของ CMake (และอาจเป็นนินจา) จำเป็นต้องใช้เครื่องมือล่าสุด:
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
เว้นแต่ว่ากฎหมายที่บังคับใช้หรือตกลงเป็นลายลักษณ์อักษรซอฟต์แวร์ที่แจกจ่ายภายใต้ใบอนุญาตจะถูกแจกจ่ายตาม "ตามพื้นฐาน" โดยไม่มีการรับประกันหรือเงื่อนไขใด ๆ ไม่ว่าจะโดยชัดแจ้งหรือโดยนัย ดูใบอนุญาตสำหรับภาษาเฉพาะที่ควบคุมการอนุญาตและข้อ จำกัด ภายใต้ใบอนุญาต