]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/vulkan/swapchain.cpp
Initial implementation of Vulkan backend
[libs/gl.git] / source / backends / vulkan / swapchain.cpp
diff --git a/source/backends/vulkan/swapchain.cpp b/source/backends/vulkan/swapchain.cpp
new file mode 100644 (file)
index 0000000..49add1a
--- /dev/null
@@ -0,0 +1,128 @@
+#include <vector>
+#include <msp/core/algorithm.h>
+#include <msp/graphics/vulkancontext_platform.h>
+#include "device.h"
+#include "error.h"
+#include "pixelformat.h"
+#include "semaphore.h"
+#include "swapchain.h"
+#include "vulkan.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+SwapChain::SwapChain(unsigned w, unsigned h, unsigned n_images_min):
+       device(Device::get_current()),
+       surface(handle_cast<VkSurface>(device.get_context().get_private().surface)),
+       width(w),
+       height(h)
+{
+       const VulkanFunctions &vk = device.get_functions();
+
+       VkSwapchainCreateInfoKHR swapchain_info = { };
+       swapchain_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+       swapchain_info.surface = handle_cast<::VkSurfaceKHR>(surface);
+       swapchain_info.minImageCount = n_images_min;
+       swapchain_info.imageExtent.width = width;
+       swapchain_info.imageExtent.height = height;
+       swapchain_info.imageArrayLayers = 1;
+       swapchain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+       swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+       swapchain_info.clipped = VK_TRUE;
+
+       VkSurfaceCapabilitiesKHR surface_caps;
+       vk.GetPhysicalDeviceSurfaceCapabilities(surface, surface_caps);
+       swapchain_info.preTransform = surface_caps.currentTransform;
+       swapchain_info.compositeAlpha = static_cast<VkCompositeAlphaFlagBitsKHR>(
+               surface_caps.supportedCompositeAlpha&~(surface_caps.supportedCompositeAlpha-1));
+
+       uint32_t n_formats = 0;
+       vk.GetPhysicalDeviceSurfaceFormats(surface, n_formats, 0);
+       vector<VkSurfaceFormatKHR> surface_formats(n_formats);
+       vk.GetPhysicalDeviceSurfaceFormats(surface, n_formats, surface_formats.data());
+
+       PixelFormat image_fmt = NO_PIXELFORMAT;
+       for(const VkSurfaceFormatKHR &f: surface_formats)
+       {
+               image_fmt = pixelformat_from_vulkan(f.format);
+               if(!is_srgb(image_fmt))
+               {
+                       swapchain_info.imageFormat = f.format;
+                       swapchain_info.imageColorSpace = f.colorSpace;
+                       break;
+               }
+       }
+
+       if(!swapchain_info.imageFormat)
+               throw runtime_error("no suitable swapchain pixelformat");
+
+       uint32_t n_present_modes = 0;
+       vk.GetPhysicalDeviceSurfacePresentModes(surface, n_present_modes, 0);
+       vector<VkPresentModeKHR> present_modes(n_present_modes);
+       vk.GetPhysicalDeviceSurfacePresentModes(surface, n_present_modes, present_modes.data());
+
+       if(find(present_modes, VK_PRESENT_MODE_FIFO_KHR)!=present_modes.end())
+               swapchain_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
+       else
+               swapchain_info.presentMode = present_modes.front();
+
+       vk.CreateSwapchain(swapchain_info, handle);
+
+       uint32_t n_images = 0;
+       vk.GetSwapchainImages(handle, n_images, 0);
+       vector<VkImage> image_handles(n_images);
+       vk.GetSwapchainImages(handle, n_images, image_handles.data());
+
+       images.reserve(n_images);
+       for(unsigned i=0; i<n_images; ++i)
+               images.emplace_back(move(SwapChainTexture(image_fmt, width, height, image_handles[i])));
+}
+
+SwapChain::~SwapChain()
+{
+       const VulkanFunctions &vk = device.get_functions();
+
+       vk.DestroySwapchain(handle);
+}
+
+unsigned SwapChain::begin_frame(Semaphore &sem)
+{
+       if(current_index>=0)
+               throw invalid_operation("SwapChain::begin_frame");
+
+       const VulkanFunctions &vk = device.get_functions();
+
+       uint32_t image_index;
+       vk.AcquireNextImage(handle, numeric_limits<uint64_t>::max(), sem.handle, 0, image_index);
+
+       current_index = image_index;
+
+       return image_index;
+}
+
+void SwapChain::present_frame(Semaphore &sem)
+{
+       if(current_index<0)
+               throw invalid_operation("SwapChain::present_frame");
+
+       const VulkanFunctions &vk = device.get_functions();
+       ::VkSwapchainKHR vk_handle = handle_cast<::VkSwapchainKHR>(handle);
+       ::VkSemaphore vk_sem = handle_cast<::VkSemaphore>(sem.handle);
+       uint32_t image_index = current_index;
+
+       current_index = -1;
+
+       VkPresentInfoKHR present_info = { };
+       present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+       present_info.waitSemaphoreCount = 1;
+       present_info.pWaitSemaphores = &vk_sem;
+       present_info.swapchainCount = 1;
+       present_info.pSwapchains = &vk_handle;
+       present_info.pImageIndices = &image_index;
+       vk.QueuePresent(present_info);
+}
+
+} // namespace GL
+} // namespace Msp