vulkan是平台无关的,所以不能直接和窗口系统交互,而是使用WSI(window system integration)扩展。这里介绍的第一个扩展就是VK_KHR_surface,已经使用GLFW启用了,这个扩展暴露了一个VkSurfaceKHR对象作为要渲染的图像的抽象表示。
由于window surface的创建需要在vulkan实例创建之后立即进行,因此这个功能会影响到物理设备的选择。
Surface创建
VkSurfaceKHR对象和使用是平台无关的,但是其创建不是的,其创建依赖所在平台窗口系统的细节。但是我们可以利用GLFW来屏蔽掉平台相关的代码,使得代码变为平台无关的。
void createSurface() {
VkSurfaceKHR surface;
if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
throw std::runtime_error("failed to create window surface!");
}
}在vulkan instance销毁之前销毁
vkDestroySurfaceKHR(instance, surface, nullptr);设备选择
surface会影响到物理设备的选择。我们前面在2. physical devices与queue families当中选择设备的时候会选择支持图形绘制命令队列的物理设备,这里使用surface的话,还需要使用的设备额外支持一下surface展示。
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
bool isComplete() {
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
/**
* 检查物理设备是否支持所需的扩展
*/
bool isDeviceSuitable(VkPhysicalDevice device) {
QueueFamilyIndices indices = findQueueFamilies(device);
return indices.isComplete();
}
/**
* 查找满足需求的队列族
*/
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
QueueFamilyIndices indices;
// 获取queue family的属性
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount,
nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount,
queueFamilies.data());
int i = 0;
for (const auto& queueFamily : queueFamilies) {
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
indices.graphicsFamily = i;
}
VkBool32 presentSupport = false;
// queue family是否支持surface
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
if (presentSupport) {
indices.presentFamily = i;
}
if (indices.isComplete()) {
break;
}
i++;
}
return indices;
}逻辑设备创建surface queue
在3. logical device与queue创建逻辑设备的时候,加上surface要使用的queue
VkQueue presentQueue;
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
// 将原来创建逻辑设备使用的queue信息变为数组
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
std::set<uint32_t> uniqueQueueFamilies = {
indices.graphicsFamily.value(),
indices.presentFamily.value()
};
float queuePriority = 1.0f;
for (uint32_t queueFamily : uniqueQueueFamilies) {
VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = queueFamily;
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
queueCreateInfos.push_back(queueCreateInfo);
}
// 以数组的形式设置
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
createInfo.pQueueCreateInfos = queueCreateInfos.data();
// create logical device
// ...
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);