{.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