Vulkan Review
在此,我们将使用 Vulkan-Hpp & C++17
Overview
- Init
- Create Instance
- Create Surface
- Select PhysicalDevice
- Create (Logical)Device and QueueFamily
- Create CommandPool, DescriptorPool
- Create CommandBuffers, SyncObjects(Fence, Semaphore), ImageSampler,
- Create Main RenderPass
- Create Swapchain
- Render
- Destroy
Init
1. Create Instance
cpp
static vk::Instance CreateInstance(
bool enableValidationLayer,
const std::vector<const char*>& in_extensions
) {
vk::ApplicationInfo appInfo{
.pApplicationName = "N/A",
.applicationVersion = VK_MAKE_VERSION(0, 0, 1),
.pEngineName = "No Engine",
.engineVersion = VK_MAKE_VERSION(0, 0, 1),
.apiVersion = VK_API_VERSION_1_3
};
vk::InstanceCreateInfo instInfo{};
instInfo.pApplicationInfo = &appInfo;
// Instance Extensions
std::vector<const char*> extensions = in_extensions;
#ifdef __APPLE__
// for prevents VK_ERROR_INCOMPATIBLE_DRIVER err on MacOS MoltenVK sdk.
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
instInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
// for supports VK_KHR_portability_subset logical-device-extension on MacOS.
extensions.push_back("VK_KHR_get_physical_device_properties2");
#endif
if (enableValidationLayer) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
instInfo.enabledExtensionCount = extensions.size();
instInfo.ppEnabledExtensionNames = extensions.data();
vk::DebugUtilsMessengerCreateInfoEXT debugMessengerInfo{};
if (enableValidationLayer)
{
_CheckValidationLayersSupport(g_ValidationLayers);
instInfo.enabledLayerCount = g_ValidationLayers.size();
instInfo.ppEnabledLayerNames = g_ValidationLayers.data();
debugMessengerInfo.messageSeverity =
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError;
debugMessengerInfo.messageType =
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance;
debugMessengerInfo.pfnUserCallback = _DebugMessengerCallback;
debugMessengerInfo.pUserData = nullptr; // Optional
instInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugMessengerInfo;
}
vk::Instance instance = vk::createInstance(instInfo, vkx::ctx().Allocator);
if (enableValidationLayer)
{
// Setup EXT DebugMessenger
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
assert(func != nullptr);
vkx::check(func(instance, (VkDebugUtilsMessengerCreateInfoEXT*)&debugMessengerInfo, nullptr, &g_DebugUtilsMessengerEXT));
}
return instance;
}
VkBootstrap version
cpp
auto vkb_inst = vkb::InstanceBuilder().set_app_name("N/A")
.request_validation_layers(bUseValidationLayers)
.use_default_debug_messenger()
.require_api_version(1, 3, 0)
.build();
vkb::Instance vkb_inst = inst_ret.value();
//grab the instance
vk::Instance instance = vkb_inst.instance;
VkDebugUtilsMessengerEXT debugMessager = vkb_inst.debug_messenger;
2. Create Surface
cpp
VkSurfaceKHR surfaceKHR;
// GLFW
glfwCreateWindowSurface(inst, (GLFWwindow*)wnd, (VkAllocationCallbacks*)vkx::ctx().Allocator, &surfaceKHR);
// SDL
SDL_Vulkan_CreateSurface(wnd, inst, &surfaceKHR);
3. Select PhysicalDevice
cpp
static VkPhysicalDevice SelectPhysicalDevice(
vk::Instance inst,
vk::PhysicalDeviceProperties* out_pProps,
vk::PhysicalDeviceFeatures* out_pFeats,
vk::PhysicalDeviceMemoryProperties* out_pMemProps
) {
std::vector<vk::PhysicalDevice> gpus = inst.enumeratePhysicalDevices();
vk::PhysicalDevice gpu = gpus.front();
*out_pProps = gpu.getProperties();
*out_pFeats = gpu.getFeatures();
*out_pMemProps = gpu.getMemoryProperties();
return gpu;
}
VkBootstrap
cpp
//vulkan 1.3 features
VkPhysicalDeviceVulkan13Features features{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES };
features.dynamicRendering = true;
features.synchronization2 = true;
//vulkan 1.2 features
VkPhysicalDeviceVulkan12Features features12{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES };
features12.bufferDeviceAddress = true;
features12.descriptorIndexing = true;
//use vkbootstrap to select a gpu.
//We want a gpu that can write to the SDL surface and supports vulkan 1.3 with the correct features
vkb::PhysicalDeviceSelector selector{ vkb_inst };
vkb::PhysicalDevice physicalDevice = selector
.set_minimum_version(1, 3)
.set_required_features_13(features)
.set_required_features_12(features12)
.set_surface(_surface)
.select()
.value();
//create the final vulkan device
vkb::DeviceBuilder deviceBuilder{ physicalDevice };
vkb::Device vkbDevice = deviceBuilder.build().value();
// Get the VkDevice handle used in the rest of a vulkan application
_device = vkbDevice.device;
_chosenGPU = physicalDevice.physical_device;