Day 5 (Dec 17, 2020) ~~~ Presenting Images to a Surface Using Swap Chains - kwilson33/learning-vulkan GitHub Wiki

Progress Today

I made it through these pages today of the official Vulkan tutorial. I started the Presentation part of Drawing a triangle after a 2 day hiatus.

Here are some major takeaways

1. Vulkan can't interface directly with the window system on its own.

  • Remember, the GLFW library is used to create a window to begin with, since Vulkan doesn't include tools for the creation of a window either.
  • To make a connection between the two, you need to use the WSI (Window System Integration) extensions.
  • The first WSI extension is VK_KHR_surface. It exposes a VkSurfaceKHR object that represents an abstract type of surface to present rendered images to.
  • GLFW has a function (glfwCreateWindowSurface) to take care of the filling in of the VkSurfaceKHR object. The creation is platform specific (as in Windows vs Mac vs Linux).

2. The window surface can influence physical device creation (as in what queue families the device needs).

  • It's possible that the queue family supporting drawing commands (called graphicsFamily in the tutorial code) doesn't overlap with queue family supporting presentation. If there are two separate queue families, this may change the possibilities for physical devices.
  • So, the window surface must be created right after instance creation and before physical device selection.

3. Swap chains are essentially queues of images that are waiting to be presented to the screen.

  • Vulkan doesn't have the concept of a "default framebuffer", so it requires an infrastructure that will contain the buffers that will we will render to before we present them to the screen. This infrastructure in Vulkan is a swap chain.
  • The general purpose of a swap chain is to synchronize the presentation of images with the refresh rate of the screen.
  • Render images --> swap chain (queue of images) --> present images to screen.
  • Must check if physical device (ie. a GPU) is capable of presenting images directly to the screen by checking if the physical device allows the VK_KHR_SWAPCHAIN_EXTENSION_NAME extension (macro is defined as VK_KHR_swapchain)
  • Furthermore, just checking if a swap chain is available on a physical device is NOT enough. You must also check if the swap chain is compatible with the window surface.
    • Need to check 3 kind of properties for a swap chain
      • Basic surface capabilities (min/max # of images in swap chain, min/max width & height of images)
      • Surface formats (pixel format, color space).
      • Available presentation modes.

4. Even if a swap chain is adequate, there are varying levels of adequate-ness for the best possible swap chain.

  • The 3 types of settings to consider are:
    • Surface format (color depth)
      • A surface format (VkSurfaceFormatKHR ) is composed of format and colorSpace members. We would like the format to be VK_FORMAT_B8G8R8A8_SRGB , meaning 8 bits in that order for 32 bits per pixel, and is in the SRGB format. We would like the colorSpace to support the SRGB color space.
    • Presentation mode (conditions for "swapping" images to the screen)
      • Arguably the most important setting, as it represents actual conditions for putting images on the screen. Click here to see the 4 possible modes and their pros/cons.
    • Swap extent (resolution of images in swap chain)
      • This is the resolution of the images and it's almost always = to the resolution of the window that we're drawing to in pixels. GLFW uses 2 units when measuring sizes, pixels and screen coords. Vulkan works with pixels, so the swap chain extend must be specified in pixels as well. For high DPI displays like Apple Retina's display, the screen coords don't correspond to pixels (the resolution of the window in pixels will be > resolution in screen coords). So, we have to use glfwGetFramebufferSize to query the resolution of the window in pixel before matching it against the min and max image extent. NOTE! You only have to do this if not using the default width and height. If either the default width or height (capabilities.currentExtent.width in chooseSwapExtent()) are set to UINT32_MAX, then that means to do some special logic to figure out the swap extent like explained above.

5. There are two ways to handle images that are accessed from multiple queues for a swap chain.

  • For example, in this tutorial there may be one queue family that draws on the images in the swap chain (graphics queue) and then submitting them on a separate presentation queue.
  • The 2 modes are VK_SHARING_MODE_EXCLUSIVE and VK_SHARING_MODE_CONCURRENT
    • VK_SHARING_MODE_EXCLUSIVE offers the best performance and requires explicit transfers of ownership of an image.
    • VK_SHARING_MODE_CONCURRENT allows using images across multiple queue families w/o explicit ownership transfers. Not as fast, but easier to use with multiple queue families than VK_SHARING_MODE_EXCLUSIVE.

6. If a swap chain becomes un-optimized while the application is still running, need to recreate it from scratch by providing reference to an old one.

  • For example, this can happen if the window is resized and the swap chain doesn't know how to handle it. For this chapter, ignoring this feature, but it is important according to the tutorial.

7. To use any VkImage, including those in the swap chain, you must create a VkImageView object.

  • An image view basically is a view into an image, describing how to access the image and which part of the image to access.
    • For example, if it should be treated as a 2D depth texture w/o any mipmapping levels.
  • Unlike images (VkImage) the image views (VkImageView) are explicitly created by the programmer and they must be explicitly destroyed.

See ya!

WOW! Got a ton done today. I was frustrated I wasn't able to keep up with the momentum (I missed two days), but I definitely made up for that today. Also, by keeping these notes it for sure makes me remember the content way better. I'm 5 days in and tons of lines of code in, and there is still a ways to go before I can draw a triangle. Things just keep piling on and on, but the content from this section (Drawing a triangle --> Presentation) made way more sense to me than the hardest content in the previous section (Drawing a triangle --> Setup) which was validation layers. The swap chain stuff took awhile to setup, but the things required to specify for it had to do with concepts I could visualize (image format, color space, screen width/height, how to draw an image, etc.). I'm having a lot of fun with this work and I hope it stays enjoyable. I'm at the tip of the iceberg, but so far this idea (keeping track of my progress) has been a great idea.