窗口表面
介绍
在 Vulkan 中,窗口表面(VkSurfaceKHR)是一个抽象,用于表示可以在其上呈现图像的窗口。由于 Vulkan 是一个与平台无关的 API,它需要一个扩展来与窗口系统交互。在本章中,我们将创建一个窗口表面,以便我们可以在后续章节中将渲染的图像呈现到窗口。
创建窗口表面
首先,我们需要添加一个类成员来存储窗口表面:
vk::raii::SurfaceKHR surface;
接下来,我们将添加一个 createSurface 函数,并在 initVulkan 中调用它:
void initVulkan() {
createInstance();
setupDebugMessenger();
pickPhysicalDevice();
createLogicalDevice();
createSurface();
}
void createSurface() {
}
由于窗口表面是与平台相关的对象,我们需要使用 GLFW 库来创建它。GLFW 提供了一个方便的 glfwCreateWindowSurface 函数来处理平台特定的细节:
void createSurface() {
VkSurfaceKHR rawSurface;
if (glfwCreateWindowSurface(*instance, window, nullptr, &rawSurface) != VK_SUCCESS) {
throw std::runtime_error("failed to create window surface!");
}
surface = vk::raii::SurfaceKHR(instance, rawSurface);
}
注意,我们需要将 VkInstance 转换为原始句柄,因为 GLFW 是一个 C 库,不理解 Vulkan 的 C++ 绑定。
检查表面支持
在我们可以使用窗口表面之前,我们需要确保物理设备支持它。我们将修改 pickPhysicalDevice 函数以检查表面支持:
void pickPhysicalDevice() {
auto devices = instance.enumeratePhysicalDevices();
if (devices.empty()) {
throw std::runtime_error("failed to find GPUs with Vulkan support!");
}
for (const auto& device : devices) {
if (isDeviceSuitable(device)) {
physicalDevice = device;
break;
}
}
if (!physicalDevice) {
throw std::runtime_error("failed to find a suitable GPU!");
}
}
bool isDeviceSuitable(const vk::PhysicalDevice& device) {
// 检查设备是否支持图形队列
auto queueFamilies = device.getQueueFamilyProperties();
bool hasGraphicsQueue = false;
for (const auto& queueFamily : queueFamilies) {
if (queueFamily.queueFlags & vk::QueueFlagBits::eGraphics) {
hasGraphicsQueue = true;
break;
}
}
// 检查设备是否支持表面
bool hasSurfaceSupport = false;
for (uint32_t i = 0; i < queueFamilies.size(); i++) {
if (device.getSurfaceSupportKHR(i, *surface)) {
hasSurfaceSupport = true;
break;
}
}
return hasGraphicsQueue && hasSurfaceSupport;
}
现在,我们有了一个窗口表面,并确保我们的物理设备支持它。在下一章中,我们将创建交换链,以便我们可以将图像呈现到表面。