]> git.tdb.fi Git - libs/gl.git/blob - source/backends/vulkan/swapchain.cpp
Initial implementation of Vulkan backend
[libs/gl.git] / source / backends / vulkan / swapchain.cpp
1 #include <vector>
2 #include <msp/core/algorithm.h>
3 #include <msp/graphics/vulkancontext_platform.h>
4 #include "device.h"
5 #include "error.h"
6 #include "pixelformat.h"
7 #include "semaphore.h"
8 #include "swapchain.h"
9 #include "vulkan.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace GL {
15
16 SwapChain::SwapChain(unsigned w, unsigned h, unsigned n_images_min):
17         device(Device::get_current()),
18         surface(handle_cast<VkSurface>(device.get_context().get_private().surface)),
19         width(w),
20         height(h)
21 {
22         const VulkanFunctions &vk = device.get_functions();
23
24         VkSwapchainCreateInfoKHR swapchain_info = { };
25         swapchain_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
26         swapchain_info.surface = handle_cast<::VkSurfaceKHR>(surface);
27         swapchain_info.minImageCount = n_images_min;
28         swapchain_info.imageExtent.width = width;
29         swapchain_info.imageExtent.height = height;
30         swapchain_info.imageArrayLayers = 1;
31         swapchain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
32         swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
33         swapchain_info.clipped = VK_TRUE;
34
35         VkSurfaceCapabilitiesKHR surface_caps;
36         vk.GetPhysicalDeviceSurfaceCapabilities(surface, surface_caps);
37         swapchain_info.preTransform = surface_caps.currentTransform;
38         swapchain_info.compositeAlpha = static_cast<VkCompositeAlphaFlagBitsKHR>(
39                 surface_caps.supportedCompositeAlpha&~(surface_caps.supportedCompositeAlpha-1));
40
41         uint32_t n_formats = 0;
42         vk.GetPhysicalDeviceSurfaceFormats(surface, n_formats, 0);
43         vector<VkSurfaceFormatKHR> surface_formats(n_formats);
44         vk.GetPhysicalDeviceSurfaceFormats(surface, n_formats, surface_formats.data());
45
46         PixelFormat image_fmt = NO_PIXELFORMAT;
47         for(const VkSurfaceFormatKHR &f: surface_formats)
48         {
49                 image_fmt = pixelformat_from_vulkan(f.format);
50                 if(!is_srgb(image_fmt))
51                 {
52                         swapchain_info.imageFormat = f.format;
53                         swapchain_info.imageColorSpace = f.colorSpace;
54                         break;
55                 }
56         }
57
58         if(!swapchain_info.imageFormat)
59                 throw runtime_error("no suitable swapchain pixelformat");
60
61         uint32_t n_present_modes = 0;
62         vk.GetPhysicalDeviceSurfacePresentModes(surface, n_present_modes, 0);
63         vector<VkPresentModeKHR> present_modes(n_present_modes);
64         vk.GetPhysicalDeviceSurfacePresentModes(surface, n_present_modes, present_modes.data());
65
66         if(find(present_modes, VK_PRESENT_MODE_FIFO_KHR)!=present_modes.end())
67                 swapchain_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
68         else
69                 swapchain_info.presentMode = present_modes.front();
70
71         vk.CreateSwapchain(swapchain_info, handle);
72
73         uint32_t n_images = 0;
74         vk.GetSwapchainImages(handle, n_images, 0);
75         vector<VkImage> image_handles(n_images);
76         vk.GetSwapchainImages(handle, n_images, image_handles.data());
77
78         images.reserve(n_images);
79         for(unsigned i=0; i<n_images; ++i)
80                 images.emplace_back(move(SwapChainTexture(image_fmt, width, height, image_handles[i])));
81 }
82
83 SwapChain::~SwapChain()
84 {
85         const VulkanFunctions &vk = device.get_functions();
86
87         vk.DestroySwapchain(handle);
88 }
89
90 unsigned SwapChain::begin_frame(Semaphore &sem)
91 {
92         if(current_index>=0)
93                 throw invalid_operation("SwapChain::begin_frame");
94
95         const VulkanFunctions &vk = device.get_functions();
96
97         uint32_t image_index;
98         vk.AcquireNextImage(handle, numeric_limits<uint64_t>::max(), sem.handle, 0, image_index);
99
100         current_index = image_index;
101
102         return image_index;
103 }
104
105 void SwapChain::present_frame(Semaphore &sem)
106 {
107         if(current_index<0)
108                 throw invalid_operation("SwapChain::present_frame");
109
110         const VulkanFunctions &vk = device.get_functions();
111         ::VkSwapchainKHR vk_handle = handle_cast<::VkSwapchainKHR>(handle);
112         ::VkSemaphore vk_sem = handle_cast<::VkSemaphore>(sem.handle);
113         uint32_t image_index = current_index;
114
115         current_index = -1;
116
117         VkPresentInfoKHR present_info = { };
118         present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
119         present_info.waitSemaphoreCount = 1;
120         present_info.pWaitSemaphores = &vk_sem;
121         present_info.swapchainCount = 1;
122         present_info.pSwapchains = &vk_handle;
123         present_info.pImageIndices = &image_index;
124         vk.QueuePresent(present_info);
125 }
126
127 } // namespace GL
128 } // namespace Msp