106 if ( glfwGetWindowAttrib(
window, GLFW_ICONIFIED ) )
134 VkSemaphore imageAvailableSemaphore =
renderer->getCurrentMirrorViewSemaphore();
138 VkResult swapchainAcquireResult = vkAcquireNextImageKHR(
142 imageAvailableSemaphore,
146 if ( swapchainAcquireResult == VK_ERROR_OUT_OF_DATE_KHR )
151 else if ( swapchainAcquireResult == VK_NOT_READY || swapchainAcquireResult == VK_TIMEOUT )
156 else if ( swapchainAcquireResult != VK_SUBOPTIMAL_KHR && swapchainAcquireResult != VK_SUCCESS )
163 VkCommandBuffer currentCommandBuffer =
renderer->getCurrentRenderingCommandBuffer();
164 VkImage sourceImage =
headset->getRenderTarget( swapchainImageIndex )->image;
166 VkExtent2D eyeResolution =
headset->getEyeResolution( mirrorEyeIndex );
168 VkImageMemoryBarrier2 sourceToTransferBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
169 sourceToTransferBarrier.pNext =
nullptr;
172 sourceToTransferBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
173 sourceToTransferBarrier.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
174 sourceToTransferBarrier.dstStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT | VK_PIPELINE_STAGE_2_COPY_BIT;
175 sourceToTransferBarrier.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT;
176 sourceToTransferBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
177 sourceToTransferBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
178 sourceToTransferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
179 sourceToTransferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
180 sourceToTransferBarrier.image = sourceImage;
184 sourceToTransferBarrier.subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
187 .baseArrayLayer = 0u,
190 VkImageMemoryBarrier2 targetToTransferBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
191 targetToTransferBarrier.pNext =
nullptr;
192 targetToTransferBarrier.srcStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT;
193 targetToTransferBarrier.srcAccessMask = 0;
194 targetToTransferBarrier.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
195 targetToTransferBarrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
198 targetToTransferBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
199 targetToTransferBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
200 targetToTransferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
201 targetToTransferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
202 targetToTransferBarrier.image = targetImage;
203 targetToTransferBarrier.subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
206 .baseArrayLayer = 0u,
209 std::vector<VkImageMemoryBarrier2> preBlitBarriers = { sourceToTransferBarrier,
210 targetToTransferBarrier };
211 VkDependencyInfo dependencyInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
212 dependencyInfo.pNext =
nullptr;
214 dependencyInfo.dependencyFlags = 0;
215 dependencyInfo.imageMemoryBarrierCount = 2u;
216 dependencyInfo.pImageMemoryBarriers = preBlitBarriers.data();
217 vkCmdPipelineBarrier2( currentCommandBuffer, &dependencyInfo );
219 const glm::vec2 sourceResolution = {
static_cast<float>( eyeResolution.width ),
220 static_cast<float>( eyeResolution.height ) };
224 const float sourceAspectRatio = sourceResolution.x / sourceResolution.y;
225 const float targetAspectRatio = targetResolution.x / targetResolution.y;
227 glm::vec2 cropResolution = sourceResolution;
228 glm::vec2 cropOffset = { 0.0f, 0.0f };
229 if ( sourceAspectRatio < targetAspectRatio )
231 cropResolution.y = sourceResolution.x / targetAspectRatio;
232 cropOffset.y = ( sourceResolution.y - cropResolution.y ) / 2.0f;
234 else if ( sourceAspectRatio > targetAspectRatio )
236 cropResolution.x = sourceResolution.y * targetAspectRatio;
237 cropOffset.x = ( sourceResolution.x - cropResolution.x ) / 2.0f;
241 VkImageBlit imageBlit{};
242 imageBlit.srcOffsets[0] = {
static_cast<int32_t
>( cropOffset.x ),
static_cast<int32_t
>( cropOffset.y ), 0 };
243 imageBlit.srcOffsets[1] = {
static_cast<int32_t
>( cropOffset.x + cropResolution.x ),
static_cast<int32_t
>( cropOffset.y + cropResolution.y ), 1 };
244 imageBlit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
245 imageBlit.srcSubresource.mipLevel = 0u;
246 imageBlit.srcSubresource.baseArrayLayer = mirrorEyeIndex;
247 imageBlit.srcSubresource.layerCount = 1u;
249 imageBlit.dstOffsets[0] = { 0, 0, 0 };
250 imageBlit.dstOffsets[1] = {
static_cast<int32_t
>( targetResolution.x ),
static_cast<int32_t
>( targetResolution.y ), 1 };
251 imageBlit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
252 imageBlit.dstSubresource.layerCount = 1u;
253 imageBlit.dstSubresource.baseArrayLayer = 0u;
254 imageBlit.dstSubresource.mipLevel = 0u;
257 currentCommandBuffer,
259 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
261 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
275 VkImageMemoryBarrier2 sourceBackBarrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
276 sourceBackBarrier.pNext =
nullptr;
278 sourceBackBarrier.srcStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT;
279 sourceBackBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT;
282 sourceBackBarrier.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT |
283 VK_PIPELINE_STAGE_2_COPY_BIT;
284 sourceBackBarrier.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT |
285 VK_ACCESS_2_TRANSFER_READ_BIT;
286 sourceBackBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
287 sourceBackBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
288 sourceBackBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
289 sourceBackBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
290 sourceBackBarrier.image = sourceImage;
293 sourceBackBarrier.subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
296 .baseArrayLayer = 0u,
299 VkImageMemoryBarrier2 targetToPresentBarrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
300 targetToPresentBarrier.pNext =
nullptr;
301 targetToPresentBarrier.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
302 targetToPresentBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
303 targetToPresentBarrier.dstStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT;
304 targetToPresentBarrier.dstAccessMask = 0;
305 targetToPresentBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
306 targetToPresentBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
307 targetToPresentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
308 targetToPresentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
309 targetToPresentBarrier.image = targetImage;
310 targetToPresentBarrier.subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
313 .baseArrayLayer = 0u,
317 std::vector<VkImageMemoryBarrier2> postBlitBarriers = { sourceBackBarrier, targetToPresentBarrier };
318 VkDependencyInfo postBlitDependency{
319 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
322 .dependencyFlags = 0,
323 .imageMemoryBarrierCount =
static_cast<uint32_t
>( postBlitBarriers.size() ),
324 .pImageMemoryBarriers = postBlitBarriers.data(),
327 vkCmdPipelineBarrier2( currentCommandBuffer, &postBlitDependency );
397 vkDeviceWaitIdle(
context->getVkDevice() );
399 VkSurfaceCapabilities2KHR surfaceCapabilities{ VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR };
401 VkPhysicalDeviceSurfaceInfo2KHR physicalDeviceSurfaceInfo{
402 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR
405 physicalDeviceSurfaceInfo.pNext =
nullptr;
407 PLOG_THROW_FN_VK( vkGetPhysicalDeviceSurfaceCapabilities2KHR(
408 context->getVkPhysicalDevice(), &physicalDeviceSurfaceInfo, &surfaceCapabilities
410 if ( !( surfaceCapabilities.surfaceCapabilities.supportedUsageFlags &
411 VK_IMAGE_USAGE_TRANSFER_DST_BIT ) )
414 "Cannot transfer the final image to mirror plane as the feature is not supported!"
418 if ( surfaceCapabilities.surfaceCapabilities.currentExtent.width !=
419 std::numeric_limits<uint32_t>::max() &&
420 surfaceCapabilities.surfaceCapabilities.currentExtent.height !=
421 std::numeric_limits<uint32_t>::max() )
428 glfwGetFramebufferSize(
window, &width, &height );
431 static_cast<int>( surfaceCapabilities.surfaceCapabilities.minImageExtent.width ),
432 static_cast<int>( surfaceCapabilities.surfaceCapabilities.maxImageExtent.width )
436 static_cast<int>( surfaceCapabilities.surfaceCapabilities.minImageExtent.height ),
437 static_cast<int>( surfaceCapabilities.surfaceCapabilities.maxImageExtent.height )
448 VkSurfaceFormat2KHR surfaceFormat{ VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR };
450 VkPhysicalDeviceSurfaceInfo2KHR physicalDeviceSurfaceInfo{
451 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR
454 physicalDeviceSurfaceInfo.pNext =
nullptr;
456 uint32_t surfaceFormatCount = 0u;
457 PLOG_THROW_FN_VK( vkGetPhysicalDeviceSurfaceFormats2KHR(
458 context->getVkPhysicalDevice(), &physicalDeviceSurfaceInfo, &surfaceFormatCount,
nullptr
461 std::vector<VkSurfaceFormat2KHR> surfaceFormats( surfaceFormatCount );
462 for ( VkSurfaceFormat2KHR & format : surfaceFormats )
464 format.sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
466 PLOG_THROW_FN_VK( vkGetPhysicalDeviceSurfaceFormats2KHR(
467 context->getVkPhysicalDevice(),
468 &physicalDeviceSurfaceInfo,
470 surfaceFormats.data()
473 bool surfaceFormatFound =
false;
474 for (
const VkSurfaceFormat2KHR & surfaceFormatCandidate : surfaceFormats )
476 PLOGI <<
"Checking color format: " << surfaceFormatCandidate.surfaceFormat.format;
477 if ( preferredFormats.contains( surfaceFormatCandidate.surfaceFormat.format ) )
479 surfaceFormat = surfaceFormatCandidate;
480 surfaceFormatFound =
true;
485 if ( !surfaceFormatFound )
487 THROW_ERROR(
"Could not find mirror surface format" );
492 VkPresentModeKHR presentMode =
493 VK_PRESENT_MODE_FIFO_KHR;
495 uint32_t presentModeCount = 0u;
496 PLOG_THROW_FN_VK( vkGetPhysicalDeviceSurfacePresentModesKHR(
500 std::vector<VkPresentModeKHR> presentModes( presentModeCount );
501 PLOG_THROW_FN_VK( vkGetPhysicalDeviceSurfacePresentModesKHR(
506 for ( VkPresentModeKHR availableMode : presentModes )
508 if ( availableMode == VK_PRESENT_MODE_MAILBOX_KHR )
510 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
511 PLOGI <<
"Mirror view using MAILBOX present mode (triple buffering with vsync)";
516 if ( presentMode == VK_PRESENT_MODE_FIFO_KHR )
518 PLOGI <<
"Mirror view using FIFO present mode (double buffering with vsync)";
527 VkSwapchainCreateInfoKHR swapchainCreateInfo{
528 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
532 .minImageCount = surfaceCapabilities.surfaceCapabilities.minImageCount + 1u,
533 .imageFormat = surfaceFormat.surfaceFormat.format,
534 .imageColorSpace = surfaceFormat.surfaceFormat.colorSpace,
536 .imageArrayLayers = 1u,
537 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
538 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
539 .preTransform = surfaceCapabilities.surfaceCapabilities.currentTransform,
540 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
541 .presentMode = presentMode,
545 vkCreateSwapchainKHR(
context->getVkDevice(), &swapchainCreateInfo,
nullptr, &
swapchain )
548 uint32_t swapchainImageCount;
550 vkGetSwapchainImagesKHR(
context->getVkDevice(),
swapchain, &swapchainImageCount,
nullptr )
554 PLOG_THROW_FN_VK( vkGetSwapchainImagesKHR(