{.experimental: "codeReordering".} import vulkan , vkTypes , depth_stencil #, math , bitops #, ./utils/etc , glm import ../wain/[waindow_object ] type Swapchain_Buffer* = ref object image*: VkImage image_view*: VkImageView Swapchain* = ref object handle*: VkSwapchainKHR oldSwapchain*: VkSwapchainKHR current_extent*: VkExtent2D surface*: VkSurfaceKHR images*: seq[VkImage] buffers*: seq[Swapchain_Buffer] #auxillary info image_count*: uint32 # defalut = 3 surfaceCaps*: VkSurfaceCapabilitiesKHR imageUsage*: VkImageUsageFlags preTransform*: VkSurfaceTransformFlagBitsKHR compositeAlpha*: VkCompositeAlphaFlagBitsKHR the_presentation_mode*: VkPresentModeKHR colorFormat*: VkFormat colorSpace*: VkColorSpaceKHR depth_format*: VkFormat presentModeCount*: uint32 presentModes*: seq[VkPresentModeKHR] surfaceFormat*: VkSurfaceFormatKHR arrayLayers*: uint32 formats*: seq[VkSurfaceFormatKHR] surfaceFormats*: seq[VkSurfaceFormatKHR] proc check_surface_support*( gpu: VkPhysicalDevice , sc: var SwapChain , theQni: var uint32 , instance: VkInstance ) = var queueCount : uint32 formatCount: uint32 supportsPresent: seq[VkBool32] gqni: uint32 = uint32.high pqni: uint32 = uint32.high when defined windows: vkGetPhysicalDeviceQueueFamilyProperties = cast[proc(physicalDevice: VkPhysicalDevice, pQueueFamilyPropertyCount: ptr uint32 , pQueueFamilyProperties: ptr VkQueueFamilyProperties ): void {.stdcall.}] (vkGetInstanceProcAddr( instance , "vkGetPhysicalDeviceQueueFamilyProperties" ) ) vkGetPhysicalDeviceSurfaceSupportKHR = cast[proc(physicalDevice: VkPhysicalDevice, queueFamilyIndex: uint32, surface: VkSurfaceKHR, pSupported: ptr VkBool32 ): VkResult {.stdcall.}] (vkGetInstanceProcAddr(instance , "vkGetPhysicalDeviceSurfaceSupportKHR" ) ) vkGetPhysicalDeviceSurfaceFormatsKHR = cast[proc(physicalDevice: VkPhysicalDevice, surface: VkSurfaceKHR, pSurfaceFormatCount: ptr uint32 , pSurfaceFormats: ptr VkSurfaceFormatKHR ): VkResult {.stdcall.}] (vkGetInstanceProcAddr(instance , "vkGetPhysicalDeviceSurfaceFormatsKHR" ) ) vkGetPhysicalDeviceQueueFamilyProperties(gpu, queueCount.addr, nil) var queueProperties = newSeq[VkQueueFamilyProperties](queueCount) vkGetPhysicalDeviceQueueFamilyProperties(gpu, queueCount.addr, queueProperties[0].addr) if queueCount == 0: quit "ERROR: No Queue Families were found by `vkGetPhysicalDeviceQueueFamilyProperties`. \n Which means Vulkan has no way to actually submit things to the GPU to draw." supportsPresent.setLen queueCount for q in 0 ..< queueCount: discard vkGetPhysicalDeviceSurfaceSupportKHR( gpu , q.uint32 , sc.surface , supportsPresent[q].addr ) # find a q that can present and do graphics for i in 0..<queueCount: if bitand(queueProperties[i].queueFlags.int, VK_QUEUE_GRAPHICS_BIT.int) != 0: if gqni == uint32.high: gqni = i if supportsPresent[i].bool == true: gqni = i pqni = i # no Q supports presenting and graphics # find a separate one if pqni == uint32.high: for i in 0..queueCount: if supportsPresent[i].bool == true: pqni = i if gqni == uint32.high or pqni == uint32.high: quit "ERROR: No valid Queue was found, so no GPU work can be done." if pqni != gqni: echo "WARNING: The present queue and graphics queue are not the same." echo "WARNING: The present queue and graphics queue are not the same." echo "WARNING: The present queue and graphics queue are not the same." echo "WARNING: The present queue and graphics queue are not the same." theQni = gqni #Find supported surface formats discard vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, sc.surface, formatCount.addr, nil) if formatCount == 0: quit "ERROR: No surface formats found by `vkGetPhysicalDeviceSurfaceFormatsKHR` \n Which Vulkan needs in order to organize and construct a frame for the GPU " sc.formats.setLen formatCount discard vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, sc.surface, formatCount.addr, addr sc.formats[0]) # The surface has no preferred format, so we assume VK_FORMAT_B8G8R8A8_UNORM # TODO: Something better? if formatCount == 1 and sc.formats[0].format == VK_FORMAT_UNDEFINED: sc.colorFormat = VK_FORMAT_B8G8R8A8_UNORM sc.colorSpace = sc.formats[0].colorSpace else: var found: bool for sformat in sc.formats: if sformat.format == VK_FORMAT_B8G8R8A8_UNORM: sc.colorFormat = sformat.format sc.colorSpace = sformat.colorSpace found = true break if not found: echo "WARNING: NOT FOUND: VK_FORMAT_B8G8R8A8_UNORM" echo "USING: ", $sc.formats[0].format echo "USING: ", $sc.formats[0].colorSpace sc.colorFormat = sc.formats[0].format sc.colorSpace = sc.formats[0].colorSpace proc create_swapchain*( device: VkDevice , sc: var Swapchain , gpu: VkPhysicalDevice , current_viewport: var VkViewport ) = var oldswap = sc.oldSwapchain var gpu_surface_capabilities_result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( gpu , sc.surface , sc.surfaceCaps.addr ) #echo "gpu_surface_capa result: " & $gpu_surface_capabilities_result discard gpu.vkGetPhysicalDeviceSurfacePresentModesKHR( sc.surface , addr sc.presentModeCount , nil ) assert(sc.presentModeCount > 0) sc.presentModes.setLen sc.presentModeCount discard gpu.vkGetPhysicalDeviceSurfacePresentModesKHR( sc.surface , addr sc.presentModeCount , addr sc.presentModes[0] ) sc.the_presentation_mode = VK_PRESENT_MODE_MAILBOX_KHR # vulkan special value -> the size of the surface will be set by the swapchain if sc.surfaceCaps.currentExtent.width == uint 0xFFFFFFFF: echo "0xFFFFFFFFFFFFFFFFFF" #sc.extent.width = .theWindowWidth #sc.extent.height = .theWindowHeight else: sc.current_extent = sc.surfaceCaps.currentExtent current_viewport = VkViewport( width: float32 sc.surfaceCaps.currentExtent.width , height: (float32 sc.surfaceCaps.currentExtent.height) , minDepth: 0.0f , maxDepth: 1.0f ) #rec.swapchain.current_extent.width = int sc.surfaceCaps.currentExtent.width #rec.swapchain.current_extent.height = int sc.surfaceCaps.currentExtent.height var desired_number_of_swapchain_images = sc.surfaceCaps.minImageCount + 1 #(?) 3 compositeAlpha:VkCompositeAlphaFlagBitsKHR = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR 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 ] # determine number of images if sc.surfaceCaps.maxImageCount > 0 and desired_number_of_swapchain_images > sc.surfaceCaps.maxImageCount: desired_number_of_swapchain_images = sc.surfaceCaps.maxImageCount # find transform of the surface if bitand( sc.surfaceCaps.supportedTransforms.int , VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR.int ) == 1: sc.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR else: echo "ERROR: bitand(scSupportDetails.capabilities.supportedTransforms.int, VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR.int) == 1 -> FAILED" sc.preTransform = sc.surfaceCaps.currentTransform # find alpha format for flag in compositeAlphaFlags: if bitand(sc.surfaceCaps.supportedCompositeAlpha.int, flag.int) == 1: compositeAlpha = flag break var createInfo = VkSwapchainCreateInfoKHR( sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR , surface: sc.surface , minImageCount: desired_number_of_swapchain_images , imageFormat: sc.colorFormat , imageColorSpace: sc.colorSpace , imageExtent: sc.current_extent , imageUsage: VkImageUsageFlags bitor( VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT.int , VK_IMAGE_USAGE_TRANSFER_SRC_BIT.int , VK_IMAGE_USAGE_TRANSFER_DST_BIT.int ) , preTransform: VkSurfaceTransformFlagBitsKHR sc.preTransform , imageArrayLayers: 1 , imageSharingMode: VK_SHARING_MODE_EXCLUSIVE , queueFamilyIndexCount: 0 , presentMode: VK_PRESENT_MODE_FIFO_KHR #TODO sc.the_presentation_mode # need to do this proper later , oldSwapChain: oldswap , clipped: VKBool32 VK_TRUE , compositeAlpha: compositeAlpha ) var scres = vkCreateSwapChainKHR( device , addr createInfo , nil , addr sc.handle ) if scres != VK_SUCCESS: quit $scres discard vkGetSwapchainImagesKHR( device , sc.handle , addr sc.image_count , nil ) sc.images.setLen sc.image_count discard vkGetSwapchainImagesKHR( device , sc.handle , addr sc.image_count , addr sc.images[0] ) sc.buffers.setLen sc.image_count for buffer in sc.buffers.mitems: buffer = Swapchain_Buffer() sc.colorFormat = VK_FORMAT_B8G8R8A8_UNORM sc.image_count = sc.image_count for i in 0 ..< sc.image_count: var createInfo = VkImageViewCreateInfo( sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO , viewType: VK_IMAGE_VIEW_TYPE_2D , format: sc.colorFormat , flags: VkImageViewCreateFlags 0 , components: VkComponentMapping( r: VkComponentSwizzle.VK_COMPONENT_SWIZZLE_R , g: VkComponentSwizzle.VK_COMPONENT_SWIZZLE_G , b: VkComponentSwizzle.VK_COMPONENT_SWIZZLE_B , a: VkComponentSwizzle.VK_COMPONENT_SWIZZLE_A ) , image: sc.images[i] , subresourceRange: VkImageSubresourceRange( aspectMask: VkImageAspectFlags(VK_IMAGE_ASPECT_COLOR_BIT) , baseMipLevel: 0 , levelCount: 1 , baseArrayLayer: 0 , layerCount: 1 ) ) sc.buffers[i].image = sc.images[i] create_info.image = sc.buffers[i].image var image_view_result = vkCreateImageView( device , createInfo.addr , nil , addr sc.buffers[i].image_view ) assert image_view_result == VK_SUCCESS, "vkCreateImageView failed" if (sc.oldSwapchain.int != VkSwapchainKHR(0).int): for i in 0 ..< sc.image_count: vkDestroyImageView( device , sc.buffers[i].image_view , nil ) vkDestroySwapchainKHR( device , sc.oldSwapchain , nil ) #[ proc anImageView*( device: VkDevice , sc: var SwapChain , rebuilding: bool = false ) = if rebuilding: sc.images.setLen 0 discard vkGetSwapchainImagesKHR(device, sc.handle, addr sc.image_count, nil) sc.images.setLen sc.image_count discard vkGetSwapchainImagesKHR(device, sc.handle, sc.image_count.addr, addr sc.images[0]) sc.buffers.setLen sc.image_count for b in 0..<sc.buffers.len: sc.buffers[b] = SwapChain_Buffer() sc.colorFormat = VK_FORMAT_B8G8R8A8_UNORM sc.image_count = sc.image_count for i in 0 ..< sc.image_count: var createInfo = VkImageViewCreateInfo( sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO , viewType: VK_IMAGE_VIEW_TYPE_2D , format: sc.colorFormat , flags: VkImageViewCreateFlags 0 , components: VkComponentMapping( r: VK_COMPONENT_SWIZZLE_IDENTITY , g: VK_COMPONENT_SWIZZLE_IDENTITY , b: VK_COMPONENT_SWIZZLE_IDENTITY , a: VK_COMPONENT_SWIZZLE_IDENTITY ) , subresourceRange: VkImageSubresourceRange( aspectMask: VkImageAspectFlags(VK_IMAGE_ASPECT_COLOR_BIT) , baseMipLevel: 0 , levelCount: 1 , baseArrayLayer: 0 , layerCount: 1 ) ) sc.buffers[i].image = sc.images[i] createInfo.image = sc.buffers[i].image if vkCreateImageView( device , createInfo.addr , nil , sc.buffers[i].view.addr ) != VK_SUCCESS: quit("failed to create image view") ]# proc create_frame_buffers*( vk_device: VkDevice , frame_buffers: var seq[VkFramebuffer] , render_pass: var VkRenderPass , swapchain: var Swapchain , depth_stencil: var Depth_Stencil , rebuilding = false ) = if rebuilding: frame_buffers.setLen 0 frame_buffers.setLen swapchain.image_count #echo frame_buffers.len for i in 0 ..< frame_buffers.len: var attachments: array[2, VkImageView] # Depth/Stencil attachment is the same for all frame buffers attachments[0] = swapchain.buffers[i].image_view attachments[1] = depth_stencil.view var frameBufferCreateInfo = VkFramebufferCreateInfo( sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO , pNext: nil , render_pass: render_pass , attachmentCount: uint32 attachments.len , pAttachments: addr attachments[0] , width: uint32 swapchain.current_extent.width , height: uint32 swapchain.current_extent.height , layers: 1 ) assert vkCreateFramebuffer( vk_device , addr frameBufferCreateInfo , nil , addr frame_buffers[i] ) == VK_SUCCESS #echo repr frame_buffers #TODO: we need to somehow get Scene in this without recursive dep errors # so we can rebuild render_Pass_Begin_info toooo proc rebuild*( vk_device: VkDevice , frame_buffers: var seq[VkFramebuffer] , render_pass: var VkRenderPass , swapchain: var Swapchain , depth_stencil: var Depth_Stencil , gpu_memory_properties: VkPhysicalDeviceMemoryProperties ) = vk_device.destroyDepthStencil depth_stencil #[ depth_stencil = create_depth_stencil( vk_device , swapchain.color_format , swapchain.current_extent , gpu_memory_properties ) ]# frame_buffers.setLen 0 frame_buffers.setLen swapchain.image_count for i in 0 ..< frame_buffers.len: var attachments: array[2, VkImageView] # Depth/Stencil attachment is the same for all frame buffers attachments[0] = swapchain.buffers[i].image_view attachments[1] = depth_stencil.view var frameBufferCreateInfo = VkFramebufferCreateInfo( sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO , pNext: nil , render_pass: render_pass , attachmentCount: 2 , pAttachments: addr attachments[0] , width: swapchain.current_extent.width , height: swapchain.current_extent.height , layers: 1 ) if vkCreateFramebuffer( vk_device , addr frameBufferCreateInfo , nil , addr frame_buffers[i] ) != VK_SUCCESS: quit "bad framebiuffer create" #[ for shape in scene.shapes.mitems: #rec.setupDescrSetLayout shape shapes.prepPipeline( rec , scene.render_pass , shape.graphicsPipeline , shape.hollow , shape.kind ) for text in scene.texts.mitems: rec.setupDescrSetLayout text textM.prepPipeline( rec , render_pass , text.graphicsPipeline ) ]# #rec.build scene