HoviTron Video Pipeline
SwapchainCommon.cpp
1/* ----------------------
2* Copyright 2023 Université Libre de Bruxelles(ULB), Universidad Politécnica de Madrid(UPM), CREAL, Deutsches Zentrum für Luft - und Raumfahrt(DLR)
3
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at < http://www.apache.org/licenses/LICENSE-2.0>
7
8* Unless required by applicable law or agreed to in writing, software
9* distributed under the License is distributed on an "AS IS" BASIS,
10* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11* See the License for the specific language governing permissionsand
12* limitations under the License.
13---------------------- */
14
15
16#include "SwapchainCommon.h"
19#include "WindowAbstract.h"
20
21#include<iostream>
22
23SwapchainCommon::SwapchainCommon(VkSurfaceKHR & surface, WindowAbstract * window, VulkanWrapper * wrapper)
24{
25 assert(window != nullptr);
26 assert(surface != VK_NULL_HANDLE);
27 assert(wrapper != nullptr);
28
29 this->wraps = wrapper;
30 this->window = window;
32
33 vk::SurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
34 vk::PresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
35 vk::Extent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
36
37 uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
38 if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
39 imageCount = swapChainSupport.capabilities.maxImageCount;
40 }
41
43 uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
44
45 int queueFamilyIndexCount = 0;
46 auto imageSharingMode = vk::SharingMode::eExclusive;
47 if (indices.graphicsFamily != indices.presentFamily) {
48 imageSharingMode = vk::SharingMode::eConcurrent;
49 queueFamilyIndexCount = 2;
50 }
51#ifdef __ANDROID__
52 //composite alpha flag
53 vk::CompositeAlphaFlagBitsKHR compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eInherit;
54#else
55 vk::CompositeAlphaFlagBitsKHR compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
56#endif
57
58 auto preTransform = swapChainSupport.capabilities.currentTransform;
59#ifdef __ANDROID__
60 preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
61#endif
62
63 vk::SwapchainCreateInfoKHR swapChainCreateInfo(
64 vk::SwapchainCreateFlagsKHR(), //flags
65 static_cast<vk::SurfaceKHR>(surface), //vk::surface
66 imageCount, //numberOfImage
67 surfaceFormat.format, //format
68 surfaceFormat.colorSpace, //colorSpace
69 extent, //vk::Extend2D
70 1, //imageArrayLayers
71 vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eInputAttachment | vk::ImageUsageFlagBits::eTransferDst, //imageUsage
72 imageSharingMode, //imageSharingMode
73 queueFamilyIndexCount, //Queue family index count
74 queueFamilyIndexCount > 0 ? queueFamilyIndices : nullptr, //Queue family indices
75 preTransform, //preTransform
76 compositeAlpha, //compositeAlpha //TODO check Alpha
77 presentMode, //presentMode
78 true, //clipped
79 nullptr); //oldSwapchain
80
81
82 swapchainFormat = surfaceFormat.format;
83 swapchainExtent = extent;
84
85 //create the swapChain
86 swapChain = wraps->context.device.createSwapchainKHR(swapChainCreateInfo);
87 //create the images for the swapChain
88 swapChainImages = wraps->context.device.getSwapchainImagesKHR(swapChain);
89
90 handle = swapChain;
91
92
93 createSwapchainImageView();
94 createAcquireSemaphores();
95}
96
97std::tuple<uint32_t, std::optional<vk::Semaphore> > SwapchainCommon::acquireImage()
98{
99 uint32_t imageIndex;
100 vk::Result acquireResult;
101
102 std::tie(acquireResult, imageIndex) = wraps->context.device.acquireNextImageKHR(swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphores[currentFrame], nullptr);
103 if (acquireResult != vk::Result::eSuccess && acquireResult != vk::Result::eSuboptimalKHR) {
104 throw std::runtime_error("failed to acquire swap chain image!");
105 }
106 std::optional<vk::Semaphore> sem = imageAvailableSemaphores[currentFrame];
107 return std::tuple<uint32_t, std::optional<vk::Semaphore> >(imageIndex, sem );
108}
109
110void SwapchainCommon::presentImage(uint32_t imageIndex, vk::Semaphore & renderingFinnished)
111{
112 vk::PresentInfoKHR presentInfo{ 1,
113 &renderingFinnished,
114 1,
115 &swapChain,
116 &imageIndex,
117 nullptr };
118
119 try {
120
121 vk::Result resultPresent = wraps->context.presentQueue.presentKHR(presentInfo);
122 if (resultPresent == vk::Result::eSuboptimalKHR || wraps->framebufferResized) {
123#ifndef __ANDROID__
124 //not doing this for ANDROID for the moment TODO
125 wraps->framebufferResized = false;
127#endif
128 }
129 else if (resultPresent != vk::Result::eSuccess) {
130 throw std::runtime_error("failed to present swap chain image!");
131 }
132 }
133 catch (vk::OutOfDateKHRError) {
135 return;
136 }
137
138 currentFrame= (currentFrame + 1) % swapchainImageViews.size();
139}
140
141void SwapchainCommon::presentImage(uint32_t imageIndex, vk::Fence & fence)
142{
143 assert(fence != (vk::Fence) VK_NULL_HANDLE);
144 const uint32_t timeoutNs = 1 * 1000 * 1000 * 1000;
145 for (int i = 0; i < 5; ++i) {
146 auto res = wraps->context.device.waitForFences(1, &fence, VK_TRUE, timeoutNs);
147 if (res == vk::Result::eSuccess) {
148 // Buffer can be executed multiple times...
149 break;
150 }
151 PRINT("%s", "Waiting for CmdBuffer fence timed out, retrying...");
152 }
153
154 vk::PresentInfoKHR presentInfo{ 0,
155 nullptr,
156 1,
157 &swapChain,
158 &imageIndex,
159 nullptr };
160
161 try {
162 vk::Result resultPresent = wraps->context.presentQueue.presentKHR(presentInfo);
163 if (resultPresent == vk::Result::eSuboptimalKHR || wraps->framebufferResized) {
164#ifndef __ANDROID__
165 //not doing this for ANDROID for the moment TODO
166 wraps->framebufferResized = false;
168#endif
169 }
170 else if (resultPresent != vk::Result::eSuccess) {
171 throw std::runtime_error("failed to present swap chain image!");
172 }
173 }
174 catch (vk::OutOfDateKHRError) {
176 return;
177 }
178
179
180 currentFrame = (currentFrame + 1) % swapchainImageViews.size();
181}
182
183void SwapchainCommon::createSwapchainImageView()
184{
185 int swapSize = swapChainImages.size();
186 swapchainImageViews.resize(swapSize);
187 for (uint32_t i = 0; i < swapSize; i++) {
188 swapchainImageViews[i] = createImageView(wraps->context.device, swapChainImages[i], swapchainFormat, vk::ImageAspectFlagBits::eColor);
189
190 }
191
192}
193
194void SwapchainCommon::createAcquireSemaphores()
195{
196 imageAvailableSemaphores.resize(swapchainImageViews.size());
197 vk::SemaphoreCreateInfo semaphoreInfo;
198 for (auto& sem : imageAvailableSemaphores) {
199 sem = wraps->context.device.createSemaphore(semaphoreInfo);
200 }
201}
202
204{
205 assert(elem < swapchainImageViews.size());
206 return swapchainImageViews[elem];
207}
208
210{
211 assert(index < swapChainImages.size());
212 return swapChainImages[index];
213}
214
216{
217 PRINT("test clean");
218 for (auto & imageView : swapchainImageViews) {
219 wraps->context.device.destroyImageView(imageView);
220 }
221 swapchainImageViews.clear();
222
223 for (auto & sem : imageAvailableSemaphores) {
224 wraps->context.device.destroySemaphore(sem);
225 }
226 imageAvailableSemaphores.clear();
227
228 wraps->context.device.destroySwapchainKHR(swapChain);
229
230}
231
233{
234 return swapchainImageViews.size();
235}
236
238{
239 return swapChainImages[currentFrame];
240}
241
242/*
243#ifdef USE_OPENXR
244std::variant<XrSwapchain, vk::SwapchainKHR> SwapchainCommon::getSwapchainHandle()
245#else
246vk::SwapchainKHR SwapchainCommon::getSwapchainHandle()
247#endif
248{
249 assert(swapChain != (vk::SwapchainKHR) VK_NULL_HANDLE);
250 return swapChain;
251}*/
252
253vk::SurfaceFormatKHR SwapchainCommon::chooseSwapSurfaceFormat(const std::vector<vk::SurfaceFormatKHR>& availableFormats)
254{
255 for (const auto& availableFormat : availableFormats) {
256
257 //if (availableFormat.format == vk::Format::eB8G8R8A8Srgb && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
258 // return availableFormat;
259 //}
260
261 if (availableFormat.format == vk::Format::eB8G8R8Unorm && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
262 return availableFormat;
263 }
264 else if (availableFormat.format == vk::Format::eB8G8R8A8Unorm && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
265 return availableFormat;
266 }
267 }
268 return availableFormats[0];
269}
270
271vk::PresentModeKHR SwapchainCommon::chooseSwapPresentMode(const std::vector<vk::PresentModeKHR>& availablePresentModes)
272{
273#ifndef __ANDROID__
274 for (const auto& availablePresentMode : availablePresentModes) {
275 if (availablePresentMode == vk::PresentModeKHR::eMailbox) {
276 return availablePresentMode;
277 }
278 }
279#endif
280 return vk::PresentModeKHR::eFifo;
281}
282
283vk::Extent2D SwapchainCommon::chooseSwapExtent(const vk::SurfaceCapabilitiesKHR& capabilities)
284{
285 if (capabilities.currentExtent.width != UINT32_MAX) {
286 return capabilities.currentExtent;
287 }
288 else {
289 int width, height;
290
291
293#ifdef __ANDROID__
294 PRINT("swap size w= %d, h = %d", width, height);
295#endif
296
297 vk::Extent2D actualExtent = {
298 static_cast<uint32_t>(width),
299 static_cast<uint32_t>(height)
300 };
301
302
303 actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
304 actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
305
306 return actualExtent;
307 }
308}
Encapsulate the vkSwapchainKHR object and the operations linked to it. Inherit from SwapchainAbstract...
Class that contains helper functions for Vulkan.
file that contains the VulkanWrapper class that manages the classes related to Vulkan code and ease t...
Contain the class WindowAbstract.
std::vector< vk::ImageView > swapchainImageViews
vk::Extent2D swapchainExtent
std::variant< vk::SwapchainKHR > handle
vk::Format swapchainFormat
VulkanWrapper * wraps
WindowAbstract * window
vk::Image getSwapchainImage(int index) override
SwapchainCommon(VkSurfaceKHR &surface, WindowAbstract *window, VulkanWrapper *wrapper)
vk::Image getCurrentImage() override
void presentImage(uint32_t imageIndex, vk::Semaphore &renderingFinnished) override
int getAttachmentSize() override
std::tuple< uint32_t, std::optional< vk::Semaphore > > acquireImage() override
void cleanup() override
vk::ImageView getSwapchainImageView(int elem) override
vk::PhysicalDevice physicalDevice
Definition: VulkanContext.h:85
vk::Device device
Definition: VulkanContext.h:87
vk::Queue presentQueue
Definition: VulkanContext.h:91
QueueFamilyIndices findQueueFamilies(vk::PhysicalDevice device)
Class that manages the classes related to Vulkan code and act as a wrapper around them.
Definition: VulkanWrapper.h:66
void recreateSwapChain()
bool framebufferResized
VulkanContext context
Abstraction of the way of the result is displayed (screen or HMD).
virtual void getFrameBufferSize(int *w, int *h, vk::PhysicalDevice &pDevice)=0
virtual SwapChainSupportDetails querySwapChainSupport(vk::PhysicalDevice device)=0
Struct to encapsulate the indice of the queues families.
Definition: VulkanContext.h:38
std::optional< uint32_t > graphicsFamily
Definition: VulkanContext.h:40
std::optional< uint32_t > presentFamily
Definition: VulkanContext.h:42
Struct that contains the capability for the sapchain, the formats and the present mode supported.
Definition: commonVulkan.h:87
vk::SurfaceCapabilitiesKHR capabilities
Definition: commonVulkan.h:89
std::vector< vk::SurfaceFormatKHR > formats
Definition: commonVulkan.h:91
std::vector< vk::PresentModeKHR > presentModes
Definition: commonVulkan.h:93