窗口表面

      +

      介绍

      在 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;
      }

      现在,我们有了一个窗口表面,并确保我们的物理设备支持它。在下一章中,我们将创建交换链,以便我们可以将图像呈现到表面。