2025-05-07 19:21:51 +02:00
/*
Crafter ® . Graphics
Copyright ( C ) 2025 Catcrafts ®
Catcrafts . net
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 3.0 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2025-04-19 15:46:26 +02:00
module ;
# include <cstdint>
# include <string>
# include <vulkan/vulkan.h>
# include <vulkan/vulkan_wayland.h>
# include <vector>
# include <wayland-client.h>
# include <thread>
# include <iostream>
2025-04-19 23:59:27 +02:00
# include <cassert>
# include <exception>
# include "VulkanInitializers.hpp"
# include "VulkanTransition.hpp"
2025-04-19 15:46:26 +02:00
module Crafter . Graphics ;
import Crafter . Event ;
using namespace Crafter ;
void WindowWaylandVulkan : : CreateSwapchain ( )
{
2025-04-19 23:59:27 +02:00
// Store the current swap chain handle so we can use it later on to ease up recreation
VkSwapchainKHR oldSwapchain = swapChain ;
// Get physical device surface properties and formats
VkSurfaceCapabilitiesKHR surfCaps ;
VulkanDevice : : CHECK_VK_RESULT ( vkGetPhysicalDeviceSurfaceCapabilitiesKHR ( VulkanDevice : : physDevice , vulkanSurface , & surfCaps ) ) ;
VkExtent2D swapchainExtent = { } ;
// If width (and height) equals the special value 0xFFFFFFFF, the size of the surface will be set by the swapchain
if ( surfCaps . currentExtent . width = = ( uint32_t ) - 1 )
{
// If the surface size is undefined, the size is set to the size of the images requested
swapchainExtent . width = width ;
swapchainExtent . height = height ;
}
else
{
// If the surface size is defined, the swap chain size must match
swapchainExtent = surfCaps . currentExtent ;
width = surfCaps . currentExtent . width ;
height = surfCaps . currentExtent . height ;
}
// Select a present mode for the swapchain
uint32_t presentModeCount ;
VulkanDevice : : CHECK_VK_RESULT ( vkGetPhysicalDeviceSurfacePresentModesKHR ( VulkanDevice : : physDevice , vulkanSurface , & presentModeCount , NULL ) ) ;
assert ( presentModeCount > 0 ) ;
std : : vector < VkPresentModeKHR > presentModes ( presentModeCount ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkGetPhysicalDeviceSurfacePresentModesKHR ( VulkanDevice : : physDevice , vulkanSurface , & presentModeCount , presentModes . data ( ) ) ) ;
// The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec
// This mode waits for the vertical blank ("v-sync")
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR ;
// Determine the number of images
uint32_t desiredNumberOfSwapchainImages = surfCaps . minImageCount + 1 ;
if ( ( surfCaps . maxImageCount > 0 ) & & ( desiredNumberOfSwapchainImages > surfCaps . maxImageCount ) )
{
desiredNumberOfSwapchainImages = surfCaps . maxImageCount ;
}
// Find the transformation of the surface
VkSurfaceTransformFlagsKHR preTransform ;
if ( surfCaps . supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR )
{
// We prefer a non-rotated transform
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ;
}
else
{
preTransform = surfCaps . currentTransform ;
}
// Find a supported composite alpha format (not all devices support alpha opaque)
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR ;
// Simply select the first composite alpha format available
std : : vector < VkCompositeAlphaFlagBitsKHR > compositeAlphaFlags = {
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR ,
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR ,
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR ,
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR ,
} ;
for ( auto & compositeAlphaFlag : compositeAlphaFlags ) {
if ( surfCaps . supportedCompositeAlpha & compositeAlphaFlag ) {
compositeAlpha = compositeAlphaFlag ;
break ;
} ;
}
VkSwapchainCreateInfoKHR swapchainCI = { } ;
swapchainCI . sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR ;
swapchainCI . surface = vulkanSurface ;
swapchainCI . minImageCount = desiredNumberOfSwapchainImages ;
swapchainCI . imageFormat = colorFormat ;
swapchainCI . imageColorSpace = colorSpace ;
swapchainCI . imageExtent = { swapchainExtent . width , swapchainExtent . height } ;
swapchainCI . imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ;
swapchainCI . preTransform = ( VkSurfaceTransformFlagBitsKHR ) preTransform ;
swapchainCI . imageArrayLayers = 1 ;
swapchainCI . imageSharingMode = VK_SHARING_MODE_EXCLUSIVE ;
swapchainCI . queueFamilyIndexCount = 0 ;
swapchainCI . presentMode = swapchainPresentMode ;
// Setting oldSwapChain to the saved handle of the previous swapchain aids in resource reuse and makes sure that we can still present already acquired images
swapchainCI . oldSwapchain = oldSwapchain ;
// Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the surface area
swapchainCI . clipped = VK_TRUE ;
swapchainCI . compositeAlpha = compositeAlpha ;
// Enable transfer source on swap chain images if supported
if ( surfCaps . supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT ) {
swapchainCI . imageUsage | = VK_IMAGE_USAGE_TRANSFER_SRC_BIT ;
}
// Enable transfer destination on swap chain images if supported
if ( surfCaps . supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT ) {
swapchainCI . imageUsage | = VK_IMAGE_USAGE_TRANSFER_DST_BIT ;
}
VulkanDevice : : CHECK_VK_RESULT ( vkCreateSwapchainKHR ( VulkanDevice : : device , & swapchainCI , nullptr , & swapChain ) ) ;
// If an existing swap chain is re-created, destroy the old swap chain and the ressources owned by the application (image views, images are owned by the swap chain)
if ( oldSwapchain ! = VK_NULL_HANDLE ) {
for ( auto i = 0 ; i < images . size ( ) ; i + + ) {
vkDestroyImageView ( VulkanDevice : : device , imageViews [ i ] , nullptr ) ;
}
vkDestroySwapchainKHR ( VulkanDevice : : device , oldSwapchain , nullptr ) ;
}
uint32_t imageCount { 0 } ;
VulkanDevice : : CHECK_VK_RESULT ( vkGetSwapchainImagesKHR ( VulkanDevice : : device , swapChain , & imageCount , nullptr ) ) ;
// Get the swap chain images
images . resize ( imageCount ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkGetSwapchainImagesKHR ( VulkanDevice : : device , swapChain , & imageCount , images . data ( ) ) ) ;
// Get the swap chain buffers containing the image and imageview
imageViews . resize ( imageCount ) ;
for ( auto i = 0 ; i < images . size ( ) ; i + + )
{
VkImageViewCreateInfo colorAttachmentView = { } ;
colorAttachmentView . sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO ;
colorAttachmentView . pNext = NULL ;
colorAttachmentView . format = colorFormat ;
colorAttachmentView . components = {
VK_COMPONENT_SWIZZLE_R ,
VK_COMPONENT_SWIZZLE_G ,
VK_COMPONENT_SWIZZLE_B ,
VK_COMPONENT_SWIZZLE_A
} ;
colorAttachmentView . subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
colorAttachmentView . subresourceRange . baseMipLevel = 0 ;
colorAttachmentView . subresourceRange . levelCount = 1 ;
colorAttachmentView . subresourceRange . baseArrayLayer = 0 ;
colorAttachmentView . subresourceRange . layerCount = 1 ;
colorAttachmentView . viewType = VK_IMAGE_VIEW_TYPE_2D ;
colorAttachmentView . flags = 0 ;
colorAttachmentView . image = images [ i ] ;
VulkanDevice : : CHECK_VK_RESULT ( vkCreateImageView ( VulkanDevice : : device , & colorAttachmentView , nullptr , & imageViews [ i ] ) ) ;
}
2025-04-19 15:46:26 +02:00
}
WindowWaylandVulkan : : WindowWaylandVulkan ( std : : string name , std : : uint32_t width , std : : uint32_t height ) : WindowWayland ( name , width , height ) {
VkWaylandSurfaceCreateInfoKHR createInfo = { } ;
createInfo . sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR ;
createInfo . display = display ;
createInfo . surface = surface ;
VulkanDevice : : CHECK_VK_RESULT ( vkCreateWaylandSurfaceKHR ( VulkanDevice : : instance , & createInfo , NULL , & vulkanSurface ) ) ;
2025-04-19 23:59:27 +02:00
// Get list of supported surface formats
std : : uint32_t formatCount ;
VulkanDevice : : CHECK_VK_RESULT ( vkGetPhysicalDeviceSurfaceFormatsKHR ( VulkanDevice : : physDevice , vulkanSurface , & formatCount , NULL ) ) ;
assert ( formatCount > 0 ) ;
std : : vector < VkSurfaceFormatKHR > surfaceFormats ( formatCount ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkGetPhysicalDeviceSurfaceFormatsKHR ( VulkanDevice : : physDevice , vulkanSurface , & formatCount , surfaceFormats . data ( ) ) ) ;
// We want to get a format that best suits our needs, so we try to get one from a set of preferred formats
// Initialize the format to the first one returned by the implementation in case we can't find one of the preffered formats
VkSurfaceFormatKHR selectedFormat = surfaceFormats [ 0 ] ;
std : : vector < VkFormat > preferredImageFormats = {
VK_FORMAT_R8G8B8A8_UNORM ,
} ;
for ( auto & availableFormat : surfaceFormats ) {
if ( std : : find ( preferredImageFormats . begin ( ) , preferredImageFormats . end ( ) , availableFormat . format ) ! = preferredImageFormats . end ( ) ) {
selectedFormat = availableFormat ;
break ;
}
}
colorFormat = selectedFormat . format ;
colorSpace = selectedFormat . colorSpace ;
2025-04-19 15:46:26 +02:00
CreateSwapchain ( ) ;
2025-04-19 23:59:27 +02:00
std : : array < VkAttachmentDescription , 2 > attachments = { } ;
// Color attachment
attachments [ 0 ] . format = colorFormat ;
attachments [ 0 ] . samples = VK_SAMPLE_COUNT_1_BIT ;
attachments [ 0 ] . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
attachments [ 0 ] . storeOp = VK_ATTACHMENT_STORE_OP_STORE ;
attachments [ 0 ] . stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE ;
attachments [ 0 ] . stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE ;
attachments [ 0 ] . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
attachments [ 0 ] . finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ;
// Depth attachment
attachments [ 1 ] . format = VulkanDevice : : depthFormat ;
attachments [ 1 ] . samples = VK_SAMPLE_COUNT_1_BIT ;
attachments [ 1 ] . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
attachments [ 1 ] . storeOp = VK_ATTACHMENT_STORE_OP_STORE ;
attachments [ 1 ] . stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
attachments [ 1 ] . stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE ;
attachments [ 1 ] . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
attachments [ 1 ] . finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ;
VkAttachmentReference colorReference = { } ;
colorReference . attachment = 0 ;
colorReference . layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ;
VkAttachmentReference depthReference = { } ;
depthReference . attachment = 1 ;
depthReference . layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ;
VkSubpassDescription subpassDescription = { } ;
subpassDescription . pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS ;
subpassDescription . colorAttachmentCount = 1 ;
subpassDescription . pColorAttachments = & colorReference ;
subpassDescription . pDepthStencilAttachment = & depthReference ;
subpassDescription . inputAttachmentCount = 0 ;
subpassDescription . pInputAttachments = nullptr ;
subpassDescription . preserveAttachmentCount = 0 ;
subpassDescription . pPreserveAttachments = nullptr ;
subpassDescription . pResolveAttachments = nullptr ;
// Subpass dependencies for layout transitions
std : : array < VkSubpassDependency , 2 > dependencies { } ;
dependencies [ 0 ] . srcSubpass = VK_SUBPASS_EXTERNAL ;
dependencies [ 0 ] . dstSubpass = 0 ;
dependencies [ 0 ] . srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT ;
dependencies [ 0 ] . dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT ;
dependencies [ 0 ] . srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT ;
dependencies [ 0 ] . dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT ;
dependencies [ 0 ] . dependencyFlags = 0 ;
dependencies [ 1 ] . srcSubpass = VK_SUBPASS_EXTERNAL ;
dependencies [ 1 ] . dstSubpass = 0 ;
dependencies [ 1 ] . srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ;
dependencies [ 1 ] . dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ;
dependencies [ 1 ] . srcAccessMask = 0 ;
dependencies [ 1 ] . dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT ;
dependencies [ 1 ] . dependencyFlags = 0 ;
VkRenderPassCreateInfo renderPassInfo = { } ;
renderPassInfo . sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO ;
renderPassInfo . attachmentCount = static_cast < uint32_t > ( attachments . size ( ) ) ;
renderPassInfo . pAttachments = attachments . data ( ) ;
renderPassInfo . subpassCount = 1 ;
renderPassInfo . pSubpasses = & subpassDescription ;
renderPassInfo . dependencyCount = static_cast < uint32_t > ( dependencies . size ( ) ) ;
renderPassInfo . pDependencies = dependencies . data ( ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkCreateRenderPass ( VulkanDevice : : device , & renderPassInfo , nullptr , & renderPass ) ) ;
VkImageCreateInfo imageCI { } ;
imageCI . sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO ;
imageCI . imageType = VK_IMAGE_TYPE_2D ;
imageCI . format = VulkanDevice : : depthFormat ;
imageCI . extent = { width , height , 1 } ;
imageCI . mipLevels = 1 ;
imageCI . arrayLayers = 1 ;
imageCI . samples = VK_SAMPLE_COUNT_1_BIT ;
imageCI . tiling = VK_IMAGE_TILING_OPTIMAL ;
imageCI . usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ;
VulkanDevice : : CHECK_VK_RESULT ( vkCreateImage ( VulkanDevice : : device , & imageCI , nullptr , & depthStencil . image ) ) ;
VkMemoryRequirements memReqs { } ;
vkGetImageMemoryRequirements ( VulkanDevice : : device , depthStencil . image , & memReqs ) ;
VkMemoryAllocateInfo memAllloc { } ;
memAllloc . sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO ;
memAllloc . allocationSize = memReqs . size ;
memAllloc . memoryTypeIndex = VulkanDevice : : GetMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkAllocateMemory ( VulkanDevice : : device , & memAllloc , nullptr , & depthStencil . memory ) ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkBindImageMemory ( VulkanDevice : : device , depthStencil . image , depthStencil . memory , 0 ) ) ;
VkImageViewCreateInfo imageViewCI { } ;
imageViewCI . sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO ;
imageViewCI . viewType = VK_IMAGE_VIEW_TYPE_2D ;
imageViewCI . image = depthStencil . image ;
imageViewCI . format = VulkanDevice : : depthFormat ;
imageViewCI . subresourceRange . baseMipLevel = 0 ;
imageViewCI . subresourceRange . levelCount = 1 ;
imageViewCI . subresourceRange . baseArrayLayer = 0 ;
imageViewCI . subresourceRange . layerCount = 1 ;
imageViewCI . subresourceRange . aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT ;
VulkanDevice : : CHECK_VK_RESULT ( vkCreateImageView ( VulkanDevice : : device , & imageViewCI , nullptr , & depthStencil . view ) ) ;
// Create frame buffers for every swap chain image
frameBuffers . resize ( images . size ( ) ) ;
for ( uint32_t i = 0 ; i < frameBuffers . size ( ) ; i + + )
{
const VkImageView attachments [ 2 ] = {
imageViews [ i ] ,
depthStencil . view
} ;
VkFramebufferCreateInfo frameBufferCreateInfo { } ;
frameBufferCreateInfo . sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO ;
frameBufferCreateInfo . renderPass = renderPass ;
frameBufferCreateInfo . attachmentCount = 2 ;
frameBufferCreateInfo . pAttachments = attachments ;
frameBufferCreateInfo . width = width ;
frameBufferCreateInfo . height = height ;
frameBufferCreateInfo . layers = 1 ;
VulkanDevice : : CHECK_VK_RESULT ( vkCreateFramebuffer ( VulkanDevice : : device , & frameBufferCreateInfo , nullptr , & frameBuffers [ i ] ) ) ;
}
drawCmdBuffers . resize ( images . size ( ) ) ;
VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks : : initializers : : commandBufferAllocateInfo ( VulkanDevice : : commandPool , VK_COMMAND_BUFFER_LEVEL_PRIMARY , static_cast < uint32_t > ( drawCmdBuffers . size ( ) ) ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkAllocateCommandBuffers ( VulkanDevice : : device , & cmdBufAllocateInfo , drawCmdBuffers . data ( ) ) ) ;
VkSemaphoreCreateInfo semaphoreCreateInfo = vks : : initializers : : semaphoreCreateInfo ( ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkCreateSemaphore ( VulkanDevice : : device , & semaphoreCreateInfo , nullptr , & semaphores . presentComplete ) ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkCreateSemaphore ( VulkanDevice : : device , & semaphoreCreateInfo , nullptr , & semaphores . renderComplete ) ) ;
// Set up submit info structure
// Semaphores will stay the same during application lifetime
// Command buffer submission info is set by each example
submitInfo = vks : : initializers : : submitInfo ( ) ;
submitInfo . pWaitDstStageMask = & submitPipelineStages ;
submitInfo . waitSemaphoreCount = 1 ;
submitInfo . pWaitSemaphores = & semaphores . presentComplete ;
submitInfo . signalSemaphoreCount = 1 ;
submitInfo . pSignalSemaphores = & semaphores . renderComplete ;
}
WindowWaylandVulkan : : ~ WindowWaylandVulkan ( ) {
if ( swapChain ! = VK_NULL_HANDLE ) {
for ( auto i = 0 ; i < images . size ( ) ; i + + ) {
vkDestroyImageView ( VulkanDevice : : device , imageViews [ i ] , nullptr ) ;
}
vkDestroySwapchainKHR ( VulkanDevice : : device , swapChain , nullptr ) ;
}
if ( vulkanSurface ! = VK_NULL_HANDLE ) {
vkDestroySurfaceKHR ( VulkanDevice : : instance , vulkanSurface , nullptr ) ;
}
2025-04-19 15:46:26 +02:00
}
2025-05-03 06:51:33 +02:00
VkCommandBuffer WindowWaylandVulkan : : StartInit ( ) {
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ currentBuffer ] , & cmdBufInfo ) ) ;
return drawCmdBuffers [ currentBuffer ] ;
}
void WindowWaylandVulkan : : FinishInit ( ) {
VkSubmitInfo submitInfo { } ;
submitInfo . sType = VK_STRUCTURE_TYPE_SUBMIT_INFO ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
VulkanDevice : : CHECK_VK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ currentBuffer ] ) ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkQueueSubmit ( VulkanDevice : : queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkQueueWaitIdle ( VulkanDevice : : queue ) ) ;
}
2025-04-19 15:46:26 +02:00
2025-05-03 06:51:33 +02:00
void WindowWaylandVulkan : : Start ( ) {
while ( open & & wl_display_dispatch ( display ) ! = - 1 ) {
// Acquire the next image from the swap chain
VulkanDevice : : CHECK_VK_RESULT ( vkAcquireNextImageKHR ( VulkanDevice : : device , swapChain , UINT64_MAX , semaphores . presentComplete , ( VkFence ) nullptr , & currentBuffer ) ) ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
2025-04-19 15:46:26 +02:00
2025-05-03 06:51:33 +02:00
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
2025-04-19 23:59:27 +02:00
2025-05-03 06:51:33 +02:00
VkClearValue clearValues [ 2 ] ;
clearValues [ 0 ] . color = { } ; ;
clearValues [ 1 ] . depthStencil = { 1.0f , 0 } ;
VulkanDevice : : CHECK_VK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ currentBuffer ] , & cmdBufInfo ) ) ;
2025-04-19 23:59:27 +02:00
VkImageSubresourceRange range { } ;
range . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
range . baseMipLevel = 0 ;
range . levelCount = VK_REMAINING_MIP_LEVELS ;
range . baseArrayLayer = 0 ;
range . layerCount = VK_REMAINING_ARRAY_LAYERS ;
2025-05-03 06:51:33 +02:00
2025-04-19 23:59:27 +02:00
VkImageSubresourceRange depth_range { range } ;
depth_range . aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT ;
2025-05-03 06:51:33 +02:00
image_layout_transition ( drawCmdBuffers [ currentBuffer ] ,
images [ currentBuffer ] ,
2025-04-19 23:59:27 +02:00
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ,
0 ,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT ,
VK_IMAGE_LAYOUT_UNDEFINED ,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ,
range ) ;
2025-05-03 06:51:33 +02:00
image_layout_transition ( drawCmdBuffers [ currentBuffer ] ,
2025-04-19 23:59:27 +02:00
depthStencil . image ,
VK_IMAGE_LAYOUT_UNDEFINED ,
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL ,
depth_range ) ;
2025-05-03 06:51:33 +02:00
2025-04-19 23:59:27 +02:00
VkRenderingAttachmentInfoKHR color_attachment_info = { VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR , VK_NULL_HANDLE } ;
2025-05-03 06:51:33 +02:00
color_attachment_info . imageView = imageViews [ currentBuffer ] ;
2025-04-19 23:59:27 +02:00
color_attachment_info . imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ;
color_attachment_info . resolveMode = VK_RESOLVE_MODE_NONE ;
color_attachment_info . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
color_attachment_info . storeOp = VK_ATTACHMENT_STORE_OP_STORE ;
color_attachment_info . clearValue = { 0.0f , 0.0f , 0.2f , 1.0f } ;
2025-05-03 06:51:33 +02:00
2025-04-19 23:59:27 +02:00
VkRenderingAttachmentInfoKHR depth_attachment_info = { VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR , VK_NULL_HANDLE } ;
depth_attachment_info . imageView = depthStencil . view ;
depth_attachment_info . imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL ;
depth_attachment_info . resolveMode = VK_RESOLVE_MODE_NONE ;
depth_attachment_info . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
depth_attachment_info . storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE ;
depth_attachment_info . clearValue = { 1.0f , 0 } ;
2025-05-03 06:51:33 +02:00
2025-04-19 23:59:27 +02:00
VkRenderingInfo render_info = { VK_STRUCTURE_TYPE_RENDERING_INFO_KHR , VK_NULL_HANDLE , 0 } ;
render_info . renderArea = VkRect2D { VkOffset2D { } , VkExtent2D { width , height } } ;
render_info . viewMask = 0 ;
render_info . layerCount = 1 ;
render_info . colorAttachmentCount = 1 ;
render_info . pColorAttachments = & color_attachment_info ;
render_info . pDepthAttachment = & depth_attachment_info ;
render_info . pStencilAttachment = VK_NULL_HANDLE ;
2025-05-03 06:51:33 +02:00
VulkanDevice : : vkCmdBeginRenderingKHRProc ( drawCmdBuffers [ currentBuffer ] , & render_info ) ;
VkViewport viewport = vks : : initializers : : viewport ( ( float ) width , ( float ) height , 0.0f , 1.0f ) ;
vkCmdSetViewport ( drawCmdBuffers [ currentBuffer ] , 0 , 1 , & viewport ) ;
VkRect2D scissor = vks : : initializers : : rect2D ( width , height , 0 , 0 ) ;
vkCmdSetScissor ( drawCmdBuffers [ currentBuffer ] , 0 , 1 , & scissor ) ;
onDraw . Invoke ( drawCmdBuffers [ currentBuffer ] ) ;
2025-05-05 06:00:35 +02:00
mouseDelta = { 0 , 0 } ;
2025-05-03 06:51:33 +02:00
VulkanDevice : : vkCmdEndRenderingKHRProc ( drawCmdBuffers [ currentBuffer ] ) ;
image_layout_transition ( drawCmdBuffers [ currentBuffer ] ,
images [ currentBuffer ] ,
2025-04-19 23:59:27 +02:00
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ,
range
) ;
2025-05-03 06:51:33 +02:00
VulkanDevice : : CHECK_VK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ currentBuffer ] ) ) ;
2025-04-19 23:59:27 +02:00
VulkanDevice : : CHECK_VK_RESULT ( vkQueueSubmit ( VulkanDevice : : queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
2025-04-19 15:46:26 +02:00
VkPresentInfoKHR presentInfo = { } ;
2025-04-19 23:59:27 +02:00
presentInfo . sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR ;
presentInfo . pNext = NULL ;
presentInfo . swapchainCount = 1 ;
presentInfo . pSwapchains = & swapChain ;
presentInfo . pImageIndices = & currentBuffer ;
// Check if a wait semaphore has been specified to wait for before presenting the image
if ( semaphores . renderComplete ! = VK_NULL_HANDLE )
{
presentInfo . pWaitSemaphores = & semaphores . renderComplete ;
presentInfo . waitSemaphoreCount = 1 ;
}
VulkanDevice : : CHECK_VK_RESULT ( vkQueuePresentKHR ( VulkanDevice : : queue , & presentInfo ) ) ;
VulkanDevice : : CHECK_VK_RESULT ( vkQueueWaitIdle ( VulkanDevice : : queue ) ) ;
2025-04-19 15:46:26 +02:00
}
2025-04-19 23:59:27 +02:00
}