duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

vulkan_swap_chain.h (5041B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #pragma once
      5 
      6 #include "vulkan_loader.h"
      7 #include "vulkan_texture.h"
      8 #include "window_info.h"
      9 
     10 #include "common/types.h"
     11 
     12 #include <array>
     13 #include <memory>
     14 #include <optional>
     15 #include <vector>
     16 
     17 class VulkanSwapChain
     18 {
     19 public:
     20   // We don't actually need +1 semaphores, or, more than one really.
     21   // But, the validation layer gets cranky if we don't fence wait before the next image acquire.
     22   // So, add an additional semaphore to ensure that we're never acquiring before fence waiting.
     23   static constexpr u32 NUM_SEMAPHORES = 4; // Should be command buffers + 1
     24 
     25   ~VulkanSwapChain();
     26 
     27   // Creates a vulkan-renderable surface for the specified window handle.
     28   static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo* wi);
     29 
     30   // Destroys a previously-created surface.
     31   static void DestroyVulkanSurface(VkInstance instance, WindowInfo* wi, VkSurfaceKHR surface);
     32 
     33   // Create a new swap chain from a pre-existing surface.
     34   static std::unique_ptr<VulkanSwapChain> Create(const WindowInfo& wi, VkSurfaceKHR surface,
     35                                                  VkPresentModeKHR present_mode,
     36                                                  std::optional<bool> exclusive_fullscreen_control);
     37 
     38   // Determines present mode to use.
     39   static bool SelectPresentMode(VkSurfaceKHR surface, GPUVSyncMode* vsync_mode, VkPresentModeKHR* present_mode);
     40 
     41   ALWAYS_INLINE VkSurfaceKHR GetSurface() const { return m_surface; }
     42   ALWAYS_INLINE VkSwapchainKHR GetSwapChain() const { return m_swap_chain; }
     43   ALWAYS_INLINE const VkSwapchainKHR* GetSwapChainPtr() const { return &m_swap_chain; }
     44   ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_window_info; }
     45   ALWAYS_INLINE u32 GetWidth() const { return m_window_info.surface_width; }
     46   ALWAYS_INLINE u32 GetHeight() const { return m_window_info.surface_height; }
     47   ALWAYS_INLINE float GetScale() const { return m_window_info.surface_scale; }
     48   ALWAYS_INLINE u32 GetCurrentImageIndex() const { return m_current_image; }
     49   ALWAYS_INLINE const u32* GetCurrentImageIndexPtr() const { return &m_current_image; }
     50   ALWAYS_INLINE u32 GetImageCount() const { return static_cast<u32>(m_images.size()); }
     51   ALWAYS_INLINE VkFormat GetImageFormat() const { return m_format; }
     52   ALWAYS_INLINE VkImage GetCurrentImage() const { return m_images[m_current_image].image; }
     53   ALWAYS_INLINE VkImageView GetCurrentImageView() const { return m_images[m_current_image].view; }
     54   ALWAYS_INLINE VkFramebuffer GetCurrentFramebuffer() const { return m_images[m_current_image].framebuffer; }
     55   ALWAYS_INLINE VkSemaphore GetImageAvailableSemaphore() const
     56   {
     57     return m_semaphores[m_current_semaphore].available_semaphore;
     58   }
     59   ALWAYS_INLINE const VkSemaphore* GetImageAvailableSemaphorePtr() const
     60   {
     61     return &m_semaphores[m_current_semaphore].available_semaphore;
     62   }
     63   ALWAYS_INLINE VkSemaphore GetRenderingFinishedSemaphore() const
     64   {
     65     return m_semaphores[m_current_semaphore].rendering_finished_semaphore;
     66   }
     67   ALWAYS_INLINE const VkSemaphore* GetRenderingFinishedSemaphorePtr() const
     68   {
     69     return &m_semaphores[m_current_semaphore].rendering_finished_semaphore;
     70   }
     71 
     72   // Returns true if the current present mode is synchronizing (adaptive or hard).
     73   ALWAYS_INLINE bool IsPresentModeSynchronizing() const { return (m_present_mode == VK_PRESENT_MODE_FIFO_KHR); }
     74   ALWAYS_INLINE VkPresentModeKHR GetPresentMode() const { return m_present_mode; }
     75 
     76   VkResult AcquireNextImage();
     77   void ReleaseCurrentImage();
     78   void ResetImageAcquireResult();
     79 
     80   bool RecreateSurface(const WindowInfo& new_wi);
     81   bool ResizeSwapChain(u32 new_width = 0, u32 new_height = 0, float new_scale = 1.0f);
     82 
     83   // Change vsync enabled state. This may fail as it causes a swapchain recreation.
     84   bool SetPresentMode(VkPresentModeKHR present_mode);
     85 
     86 private:
     87   VulkanSwapChain(const WindowInfo& wi, VkSurfaceKHR surface, VkPresentModeKHR present_mode,
     88                   std::optional<bool> exclusive_fullscreen_control);
     89 
     90   static std::optional<VkSurfaceFormatKHR> SelectSurfaceFormat(VkSurfaceKHR surface);
     91 
     92   bool CreateSwapChain();
     93   void DestroySwapChain();
     94 
     95   void DestroySwapChainImages();
     96 
     97   void DestroySurface();
     98 
     99   struct Image
    100   {
    101     VkImage image;
    102     VkImageView view;
    103     VkFramebuffer framebuffer;
    104   };
    105 
    106   struct ImageSemaphores
    107   {
    108     VkSemaphore available_semaphore;
    109     VkSemaphore rendering_finished_semaphore;
    110   };
    111 
    112   WindowInfo m_window_info;
    113 
    114   VkSurfaceKHR m_surface = VK_NULL_HANDLE;
    115   VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE;
    116 
    117   std::vector<Image> m_images;
    118   std::array<ImageSemaphores, NUM_SEMAPHORES> m_semaphores = {};
    119 
    120   u32 m_current_image = 0;
    121   u32 m_current_semaphore = 0;
    122 
    123   VkFormat m_format = VK_FORMAT_UNDEFINED;
    124   VkPresentModeKHR m_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
    125 
    126   std::optional<VkResult> m_image_acquire_result;
    127   std::optional<bool> m_exclusive_fullscreen_control;
    128 };