-
-
Save zacharycarter/b1ebd711765c676e4af824f00e57afef to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import intsets, sequtils, deques, | |
../lib/glfw, ../lib/volk, ../lib/vma | |
type | |
Format* = enum | |
FORMAT_UNKNOWN, FORMAT_R32G32B32A32_FLOAT, FORMAT_R32G32B32A32_UINT, | |
FORMAT_R32G32B32A32_SINT, FORMAT_R32G32B32_FLOAT, FORMAT_R32G32B32_UINT, | |
FORMAT_R32G32B32_SINT, FORMAT_R16G16B16A16_FLOAT, FORMAT_R16G16B16A16_UNORM, | |
FORMAT_R16G16B16A16_UINT, FORMAT_R16G16B16A16_SNORM, FORMAT_R16G16B16A16_SINT, | |
FORMAT_R32G32_FLOAT, FORMAT_R32G32_UINT, FORMAT_R32G32_SINT, FORMAT_R32G8X24_TYPELESS, ## depth + stencil (alias) | |
FORMAT_D32_FLOAT_S8X24_UINT, ## depth + stencil | |
FORMAT_R10G10B10A2_UNORM, FORMAT_R10G10B10A2_UINT, FORMAT_R11G11B10_FLOAT, | |
FORMAT_R8G8B8A8_UNORM, FORMAT_R8G8B8A8_UNORM_SRGB, FORMAT_R8G8B8A8_UINT, | |
FORMAT_R8G8B8A8_SNORM, FORMAT_R8G8B8A8_SINT, FORMAT_B8G8R8A8_UNORM, | |
FORMAT_B8G8R8A8_UNORM_SRGB, FORMAT_R16G16_FLOAT, FORMAT_R16G16_UNORM, | |
FORMAT_R16G16_UINT, FORMAT_R16G16_SNORM, FORMAT_R16G16_SINT, FORMAT_R32_TYPELESS, ## depth (alias) | |
FORMAT_D32_FLOAT, ## depth | |
FORMAT_R32_FLOAT, FORMAT_R32_UINT, FORMAT_R32_SINT, FORMAT_R24G8_TYPELESS, ## depth + stencil (alias) | |
FORMAT_D24_UNORM_S8_UINT, ## depth + stencil | |
FORMAT_R8G8_UNORM, FORMAT_R8G8_UINT, FORMAT_R8G8_SNORM, FORMAT_R8G8_SINT, FORMAT_R16_TYPELESS, ## depth (alias) | |
FORMAT_R16_FLOAT, FORMAT_D16_UNORM, ## depth | |
FORMAT_R16_UNORM, FORMAT_R16_UINT, FORMAT_R16_SNORM, FORMAT_R16_SINT, | |
FORMAT_R8_UNORM, FORMAT_R8_UINT, FORMAT_R8_SNORM, FORMAT_R8_SINT, | |
FORMAT_BC1_UNORM, FORMAT_BC1_UNORM_SRGB, FORMAT_BC2_UNORM, | |
FORMAT_BC2_UNORM_SRGB, FORMAT_BC3_UNORM, FORMAT_BC3_UNORM_SRGB, | |
FORMAT_BC4_UNORM, FORMAT_BC4_SNORM, FORMAT_BC5_UNORM, FORMAT_BC5_SNORM, | |
FORMAT_BC6H_UF16, FORMAT_BC6H_SF16, FORMAT_BC7_UNORM, FORMAT_BC7_UNORM_SRGB | |
QueueFamilyIndices = object | |
graphicsFamily: int32 | |
presentFamily: int32 | |
copyFamily: int32 | |
SwapChainSupportDetails = object | |
capabilities: VkSurfaceCapabilitiesKHR | |
formats: seq[VkSurfaceFormatKHR] | |
presentModes: seq[VkPresentModeKHR] | |
AllocationHandler = ref object | |
allocator: VmaAllocator | |
device: VkDevice | |
instance: VkInstance | |
frameCount: uint64 | |
destroyerImageViews: Deque[tuple[imageView: VkImageView; frameCount: uint64]] | |
destroyerRenderpasses: Deque[tuple[renderPass: VkRenderPass; frameCount: uint64]] | |
destroyerFramebuffers: Deque[tuple[framebuffer: VkFramebuffer; frameCount: uint64]] | |
GraphicsDeviceState = object | |
vSync: bool | |
resolutionWidth: int32 | |
resolutionHeight: int32 | |
tessellationSupport: bool | |
backBufferFormat: Format | |
uavLoadFormatCommonSupport: bool | |
renderTargetAndViewportArrayIndexWithoutGSSupport: bool | |
uavLoadFormatR11G11B10Float: bool | |
instance: VkInstance | |
callback: VkDebugReportCallbackEXT | |
surface: VkSurfaceKHR | |
physicalDevice: VkPhysicalDevice | |
device: VkDevice | |
queueIndices: QueueFamilyIndices | |
graphicsQueue: VkQueue | |
presentQueue: VkQueue | |
deviceProperties: VkPhysicalDeviceProperties | |
deviceProperties2: VkPhysicalDeviceProperties2 | |
deviceProperties11: VkPhysicalDeviceVulkan11Properties | |
deviceProperties12: VkPhysicalDeviceVulkan12Properties | |
deviceFeatures2: VkPhysicalDeviceFeatures2 | |
deviceFeatures11: VkPhysicalDeviceVulkan11Features | |
deviceFeatures12: VkPhysicalDeviceVulkan12Features | |
swapChain: VkSwapchainKHR | |
swapChainImageFormat: VkFormat | |
swapChainExtent: VkExtent2D | |
swapChainImageIndex: uint32 | |
swapChainImages: seq[VkImage] | |
swapChainImageViews: seq[VkImageView] | |
swapChainFramebuffers: seq[VkFramebuffer] | |
allocationHandler: AllocationHandler | |
defaultRenderPass: VkRenderPass | |
const | |
BackBufferCount = 2'u32 | |
requiredDebugExtensions = [VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME] | |
requiredInstanceExtensions = [VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME] | |
requiredDeviceExtensions = @[VK_KHR_SWAPCHAIN_EXTENSION_NAME] | |
var | |
state: GraphicsDeviceState | |
validationLayers = ["VK_LAYER_KHRONOS_validation"] | |
proc convertFormat(value: Format): VkFormat = | |
case value | |
of FORMAT_UNKNOWN: | |
return VK_FORMAT_UNDEFINED | |
of FORMAT_R32G32B32A32_FLOAT: | |
return VK_FORMAT_R32G32B32A32_SFLOAT | |
of FORMAT_R32G32B32A32_UINT: | |
return VK_FORMAT_R32G32B32A32_UINT | |
of FORMAT_R32G32B32A32_SINT: | |
return VK_FORMAT_R32G32B32A32_SINT | |
of FORMAT_R32G32B32_FLOAT: | |
return VK_FORMAT_R32G32B32_SFLOAT | |
of FORMAT_R32G32B32_UINT: | |
return VK_FORMAT_R32G32B32_UINT | |
of FORMAT_R32G32B32_SINT: | |
return VK_FORMAT_R32G32B32_SINT | |
of FORMAT_R16G16B16A16_FLOAT: | |
return VK_FORMAT_R16G16B16A16_SFLOAT | |
of FORMAT_R16G16B16A16_UNORM: | |
return VK_FORMAT_R16G16B16A16_UNORM | |
of FORMAT_R16G16B16A16_UINT: | |
return VK_FORMAT_R16G16B16A16_UINT | |
of FORMAT_R16G16B16A16_SNORM: | |
return VK_FORMAT_R16G16B16A16_SNORM | |
of FORMAT_R16G16B16A16_SINT: | |
return VK_FORMAT_R16G16B16A16_SINT | |
of FORMAT_R32G32_FLOAT: | |
return VK_FORMAT_R32G32_SFLOAT | |
of FORMAT_R32G32_UINT: | |
return VK_FORMAT_R32G32_UINT | |
of FORMAT_R32G32_SINT: | |
return VK_FORMAT_R32G32_SINT | |
of FORMAT_R32G8X24_TYPELESS: | |
return VK_FORMAT_D32_SFLOAT_S8_UINT | |
of FORMAT_D32_FLOAT_S8X24_UINT: | |
return VK_FORMAT_D32_SFLOAT_S8_UINT | |
of FORMAT_R10G10B10A2_UNORM: | |
return VK_FORMAT_A2B10G10R10_UNORM_PACK32 | |
of FORMAT_R10G10B10A2_UINT: | |
return VK_FORMAT_A2B10G10R10_UINT_PACK32 | |
of FORMAT_R11G11B10_FLOAT: | |
return VK_FORMAT_B10G11R11_UFLOAT_PACK32 | |
of FORMAT_R8G8B8A8_UNORM: | |
return VK_FORMAT_R8G8B8A8_UNORM | |
of FORMAT_R8G8B8A8_UNORM_SRGB: | |
return VK_FORMAT_R8G8B8A8_SRGB | |
of FORMAT_R8G8B8A8_UINT: | |
return VK_FORMAT_R8G8B8A8_UINT | |
of FORMAT_R8G8B8A8_SNORM: | |
return VK_FORMAT_R8G8B8A8_SNORM | |
of FORMAT_R8G8B8A8_SINT: | |
return VK_FORMAT_R8G8B8A8_SINT | |
of FORMAT_R16G16_FLOAT: | |
return VK_FORMAT_R16G16_SFLOAT | |
of FORMAT_R16G16_UNORM: | |
return VK_FORMAT_R16G16_UNORM | |
of FORMAT_R16G16_UINT: | |
return VK_FORMAT_R16G16_UINT | |
of FORMAT_R16G16_SNORM: | |
return VK_FORMAT_R16G16_SNORM | |
of FORMAT_R16G16_SINT: | |
return VK_FORMAT_R16G16_SINT | |
of FORMAT_R32_TYPELESS: | |
return VK_FORMAT_D32_SFLOAT | |
of FORMAT_D32_FLOAT: | |
return VK_FORMAT_D32_SFLOAT | |
of FORMAT_R32_FLOAT: | |
return VK_FORMAT_R32_SFLOAT | |
of FORMAT_R32_UINT: | |
return VK_FORMAT_R32_UINT | |
of FORMAT_R32_SINT: | |
return VK_FORMAT_R32_SINT | |
of FORMAT_R24G8_TYPELESS: | |
return VK_FORMAT_D24_UNORM_S8_UINT | |
of FORMAT_D24_UNORM_S8_UINT: | |
return VK_FORMAT_D24_UNORM_S8_UINT | |
of FORMAT_R8G8_UNORM: | |
return VK_FORMAT_R8G8_UNORM | |
of FORMAT_R8G8_UINT: | |
return VK_FORMAT_R8G8_UINT | |
of FORMAT_R8G8_SNORM: | |
return VK_FORMAT_R8G8_SNORM | |
of FORMAT_R8G8_SINT: | |
return VK_FORMAT_R8G8_SINT | |
of FORMAT_R16_TYPELESS: | |
return VK_FORMAT_D16_UNORM | |
of FORMAT_R16_FLOAT: | |
return VK_FORMAT_R16_SFLOAT | |
of FORMAT_D16_UNORM: | |
return VK_FORMAT_D16_UNORM | |
of FORMAT_R16_UNORM: | |
return VK_FORMAT_R16_UNORM | |
of FORMAT_R16_UINT: | |
return VK_FORMAT_R16_UINT | |
of FORMAT_R16_SNORM: | |
return VK_FORMAT_R16_SNORM | |
of FORMAT_R16_SINT: | |
return VK_FORMAT_R16_SINT | |
of FORMAT_R8_UNORM: | |
return VK_FORMAT_R8_UNORM | |
of FORMAT_R8_UINT: | |
return VK_FORMAT_R8_UINT | |
of FORMAT_R8_SNORM: | |
return VK_FORMAT_R8_SNORM | |
of FORMAT_R8_SINT: | |
return VK_FORMAT_R8_SINT | |
of FORMAT_BC1_UNORM: | |
return VK_FORMAT_BC1_RGBA_UNORM_BLOCK | |
of FORMAT_BC1_UNORM_SRGB: | |
return VK_FORMAT_BC1_RGBA_SRGB_BLOCK | |
of FORMAT_BC2_UNORM: | |
return VK_FORMAT_BC2_UNORM_BLOCK | |
of FORMAT_BC2_UNORM_SRGB: | |
return VK_FORMAT_BC2_SRGB_BLOCK | |
of FORMAT_BC3_UNORM: | |
return VK_FORMAT_BC3_UNORM_BLOCK | |
of FORMAT_BC3_UNORM_SRGB: | |
return VK_FORMAT_BC3_SRGB_BLOCK | |
of FORMAT_BC4_UNORM: | |
return VK_FORMAT_BC4_UNORM_BLOCK | |
of FORMAT_BC4_SNORM: | |
return VK_FORMAT_BC4_SNORM_BLOCK | |
of FORMAT_BC5_UNORM: | |
return VK_FORMAT_BC5_UNORM_BLOCK | |
of FORMAT_BC5_SNORM: | |
return VK_FORMAT_BC5_SNORM_BLOCK | |
of FORMAT_B8G8R8A8_UNORM: | |
return VK_FORMAT_B8G8R8A8_UNORM | |
of FORMAT_B8G8R8A8_UNORM_SRGB: | |
return VK_FORMAT_B8G8R8A8_SRGB | |
of FORMAT_BC6H_UF16: | |
return VK_FORMAT_BC6H_UFLOAT_BLOCK | |
of FORMAT_BC6H_SF16: | |
return VK_FORMAT_BC6H_SFLOAT_BLOCK | |
of FORMAT_BC7_UNORM: | |
return VK_FORMAT_BC7_UNORM_BLOCK | |
of FORMAT_BC7_UNORM_SRGB: | |
return VK_FORMAT_BC7_SRGB_BLOCK | |
return VK_FORMAT_UNDEFINED | |
proc toString(chars: openArray[char]): string = | |
result = "" | |
for c in chars: | |
if c != '\0': | |
result.add(c) | |
proc debugCallback(flags: VkDebugReportFlagsEXT; objType: VkDebugReportObjectTypeEXT; obj: uint64; | |
location: csize_t; code: int32; layerPrefix: cstring; msg: cstring; userData: pointer): VkBool32 {.cdecl.} = | |
echo "INSIDE DEBUG CALLBACK!" | |
proc init(qfi: var QueueFamilyIndices) = | |
qfi.graphicsFamily = -1 | |
qfi.presentFamily = -1 | |
qfi.copyFamily = -1 | |
proc isComplete(qfi: QueueFamilyIndices): bool = | |
result = qfi.graphicsFamily >= 0 and qfi.presentFamily >= 0 and qfi.copyFamily >= 0 | |
proc querySwapChainSupport(device: VkPhysicalDevice; surface: VkSurfaceKHR): SwapChainSupportDetails = | |
var | |
formatCount: uint32 | |
presentModeCount: uint32 | |
discard device.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, result.capabilities.addr) | |
discard device.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, formatCount.addr, nil) | |
if formatCount != 0'u32: | |
result.formats.setLen(formatCount) | |
discard device.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, formatCount.addr, result.formats[0].addr) | |
discard device.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, presentModeCOunt.addr, nil) | |
if presentModeCount != 0'u32: | |
result.presentModes.setLen(presentModeCount) | |
discard device.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, presentModeCount.addr, result.presentModes[0].addr) | |
proc checkDeviceExtensionSupport(checkExtension: cstring; availableDeviceExtensions: seq[VkExtensionProperties]): bool = | |
for x in availableDeviceExtensions: | |
if cast[cstring](x.extensionName[0].unsafeAddr) == checkExtension: | |
return true | |
proc findQueueFamilies(device: VkPhysicalDevice; surface: VkSurfaceKHR): QueueFamilyIndices = | |
result.init() | |
var queueFamilyCount = 0'u32 | |
device.vkGetPhysicalDeviceQueueFamilyProperties(queueFamilyCount.addr, nil) | |
var queueFamilies = newSeq[VkQueueFamilyProperties](queueFamilyCount) | |
device.vkGetPhysicalDeviceQueueFamilyProperties(queueFamilyCount.addr, queueFamilies[0].addr) | |
var i = 0'u32 | |
for queueFamily in queueFamilies: | |
var presentSupport = false.VkBool32 | |
discard device.vkGetPhysicalDeviceSurfaceSupportKHR(i, surface, presentSupport.addr) | |
if result.presentFamily < 0 and queueFamily.queueCount > 0 and presentSupport.bool: | |
result.presentFamily = i.int32 | |
if result.graphicsFamily < 0 and queueFamily.queueCount > 0 and (queueFamily.queueFlags.uint32 and VK_QUEUE_GRAPHICS_BIT.uint32) != 0'u32: | |
result.graphicsFamily = i.int32 | |
if queueFamily.queueCount > 0 and (queueFamily.queueFlags.uint32 and VK_QUEUE_TRANSFER_BIT.uint32) != 0'u32: | |
result.copyFamily = i.int32 | |
inc i | |
proc isSuitable(device: VkPhysicalDevice; surface: VkSurfaceKHR): bool = | |
var | |
extensionCount: uint32 | |
available: seq[VkExtensionProperties] | |
swapChainSupport: SwapChainSupportDetails | |
let indices = device.findQueueFamilies(surface) | |
if not indices.isComplete(): | |
echo "indices not complete!" | |
return false | |
discard device.vkEnumerateDeviceExtensionProperties(nil, extensionCount.addr, nil) | |
available.setLen(extensionCount) | |
discard device.vkEnumerateDeviceExtensionProperties(nil, extensionCount.addr, available[0].addr) | |
for x in requiredDeviceExtensions: | |
if not x.checkDeviceExtensionSupport(available): | |
echo "device extension unsupported" | |
return false | |
swapChainSupport = device.querySwapChainSupport(surface) | |
result = swapChainSupport.formats.len != 0 and swapChainSupport.presentModes.len != 0 | |
proc checkValidationLayerSupport(): bool = | |
var | |
layerCount: uint32 = 0 | |
layers: seq[VkLayerProperties] | |
discard vkEnumerateInstanceLayerProperties(layerCount.addr, nil) | |
layers.setLen(layerCount) | |
discard vkEnumerateInstanceLayerProperties(layerCount.addr, layers[0].addr) | |
for validate in validationLayers: | |
var found = false | |
for layer in layers: | |
if layer.layerName.toString() == validate: | |
found = true | |
break | |
if not found: | |
return false | |
result = true | |
proc createBackBufferResources() = | |
var | |
valid: bool | |
imageCount: uint32 | |
res: VkResult | |
queueFamilyIndices: array[2, uint32] | |
swapChainSupport: SwapChainSupportDetails | |
surfaceFormat: VkSurfaceFormatKHR | |
createInfo: VkSwapchainCreateInfoKHR | |
info: VkDebugUtilsObjectNameInfoEXT | |
colorAttachment: VkAttachmentDescription | |
colorAttachmentRef: VkAttachmentReference | |
subpass: VkSubpassDescription | |
renderPassInfo: VkRenderPassCreateInfo | |
dependency: VkSubpassDependency | |
attachments: array[1, VkImageView] | |
swapChainSupport = state.physicalDevice.querySwapChainSupport(state.surface) | |
surfaceFormat.format = convertFormat(state.backBufferFormat) | |
for format in swapChainSupport.formats: | |
if format.format == surfaceFormat.format: | |
surfaceFormat = format | |
valid = true | |
break | |
if not valid: | |
surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM | |
surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR | |
state.backBufferFormat = FORMAT_B8G8R8A8_UNORM | |
state.swapChainExtent.width = state.resolutionWidth.uint32 | |
state.swapChainExtent.height = state.resolutionHeight.uint32 | |
state.swapChainExtent.width = max(swapChainSupport.capabilities.minImageExtent.width, | |
min(swapChainSupport.capabilities.maxImageExtent.width, state.swapChainExtent.width)) | |
state.swapChainExtent.height = max(swapChainSupport.capabilities.minImageExtent.height, | |
min(swapChainSupport.capabilities.maxImageExtent.height, state.swapChainExtent.height)) | |
imageCount = BackBufferCount | |
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR | |
createInfo.surface = state.surface | |
createInfo.minImageCount = imageCount | |
createInfo.imageFormat = surfaceFormat.format | |
createInfo.imageColorSpace = surfaceFormat.colorSpace | |
createInfo.imageExtent = state.swapChainExtent | |
createInfo.imageArrayLayers = 1 | |
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT.uint32 or VK_IMAGE_USAGE_TRANSFER_SRC_BIT.uint32 | |
queueFamilyIndices = [state.queueIndices.graphicsFamily.uint32, state.queueIndices.presentFamily.uint32] | |
if state.queueIndices.graphicsFamily != state.queueIndices.presentFamily: | |
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT | |
createInfo.queueFamilyIndexCount = 2 | |
createInfo.pQueueFamilyIndices = queueFamilyIndices[0].addr | |
else: | |
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE | |
createInfo.queueFamilyIndexCount = 0 | |
createInfo.pQueueFamilyIndices = nil | |
createInfo.preTransform = swapChainSupport.capabilities.currentTransform | |
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | |
createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR | |
if not state.vSync: | |
for presentMode in swapChainSupport.presentModes: | |
if presentMode == VK_PRESENT_MODE_IMMEDIATE_KHR: | |
createInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR | |
break | |
createInfo.clipped = VK_TRUE | |
createInfo.oldSwapchain = state.swapChain | |
res = state.device.vkCreateSwapchainKHR(createInfo.addr, nil, state.swapChain.addr) | |
assert(res == VK_SUCCESS) | |
if createInfo.oldSwapchain != nil: | |
state.device.vkDestroySwapchainKHR(createInfo.oldSwapchain, nil) | |
discard state.device.vkGetSwapchainImagesKHR(state.swapChain, imageCount.addr, nil) | |
assert(BackbufferCount <= imageCount) | |
state.swapChainImages.setLen(imageCount) | |
discard state.device.vkGetSwapchainImagesKHR(state.swapChain, imageCount.addr, state.swapChainImages[0].addr) | |
state.swapChainImageFormat = surfaceFormat.format | |
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT | |
info.pObjectName = "SWAPCHAIN" | |
info.objectType = VK_OBJECT_TYPE_IMAGE | |
for x in state.swapChainImages: | |
info.objectHandle = cast[uint64](x) | |
res = state.device.vkSetDebugUtilsObjectNameEXT(info.addr) | |
assert(res == VK_SUCCESS) | |
block: | |
colorAttachment.format = state.swapChainImageFormat | |
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT | |
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR | |
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE | |
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE | |
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE | |
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED | |
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR | |
colorAttachmentRef.attachment = 0 | |
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL | |
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS | |
subpass.colorAttachmentCount = 1 | |
subpass.pColorAttachments = colorAttachmentRef.addr | |
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO | |
renderPassInfo.attachmentCount = 1 | |
renderPassInfo.pAttachments = colorAttachment.addr | |
renderPassInfo.subpassCount = 1 | |
renderPassInfo.pSubpasses = subpass.addr | |
dependency.srcSubpass = VK_SUBPASS_EXTERNAL | |
dependency.dstSubpass = 0 | |
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT.uint32 | |
dependency.srcAccessMask = 0 | |
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT.uint32 | |
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT.uint32 or VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT.uint32 | |
renderPassInfo.dependencyCount = 1 | |
renderPassInfo.pDependencies = dependency.addr | |
if state.defaultRenderPass != nil: | |
state.allocationHandler.destroyerRenderpasses.addLast((renderPass: state.defaultRenderPass, frameCount: state.allocationHandler.frameCount)) | |
res = state.device.vkCreateRenderPass(renderPassInfo.addr, nil, state.defaultRenderPass.addr) | |
assert(res == VK_SUCCESS) | |
state.swapChainImageViews.setLen(state.swapChainImages.len) | |
state.swapChainFramebuffers.setLen(state.swapChainImages.len) | |
for i in 0 ..< state.swapChainImages.len: | |
var createInfo: VkImageViewCreateInfo | |
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO | |
createInfo.image = state.swapChainImages[i] | |
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D | |
createInfo.format = state.swapChainImageFormat | |
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY | |
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY | |
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY | |
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY | |
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT.uint32 | |
createInfo.subresourceRange.baseMipLevel = 0 | |
createInfo.subresourceRange.levelCount = 1 | |
createInfo.subresourceRange.baseArrayLayer = 0 | |
createInfo.subresourceRange.layerCount = 1 | |
if state.swapChainImageViews[i] != nil: | |
state.allocationHandler.destroyerImageViews.addLast((imageView: state.swapChainImageViews[i], frameCount: state.allocationHandler.frameCount)) | |
res = state.device.vkCreateImageView(createInfo.addr, nil, state.swapChainImageViews[i].addr) | |
var | |
attachments = [state.swapChainImageViews[i]] | |
framebufferInfo: VkFramebufferCreateInfo | |
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO | |
framebufferInfo.renderPass = state.defaultRenderPass | |
framebufferInfo.attachmentCount = 1 | |
framebufferInfo.pAttachments = attachments[0].addr | |
framebufferInfo.width = state.swapChainExtent.width | |
framebufferInfo.height = state.swapChainExtent.height | |
framebufferInfo.layers = 1 | |
if state.swapChainFramebuffers[i] != nil: | |
state.allocationHandler.destroyerFramebuffers.addLast((framebuffer: state.swapChainFramebuffers[i], frameCount: state.allocationHandler.frameCount)) | |
res = state.device.vkCreateFramebuffer(framebufferInfo.addr, nil, state.swapChainFramebuffers[i].addr) | |
assert(res == VK_SUCCESS) | |
proc createVulkanGraphicsDevice*(window: ptr GLFWWindow) = | |
assert(volkInitialize() == VK_SUCCESS) | |
var | |
res: VkResult | |
extensionCount: uint32 | |
glfwExtensionCount: uint32 | |
deviceCount: uint32 | |
requiredExtensions: seq[string] | |
extensionNames: cstringArray | |
glfwRequiredExtensions: cstringArray | |
enabledLayerNames: cstringArray | |
extensionProperties: seq[VkExtensionProperties] | |
devices: seq[VkPhysicalDevice] | |
discrete: bool | |
queueCreateInfos: seq[VkDeviceQueueCreateInfo] | |
enabledDeviceExtensions: seq[cstring] | |
availableDeviceExtensions: seq[VkExtensionProperties] | |
formatProperties: VkFormatProperties | |
allocatorInfo: VmaAllocatorCreateInfo | |
queueFamilyIndices: QueueFamilyIndices | |
uniqueQueueFamilies = initIntSet() | |
queuePriority = 1.0'f32 | |
appInfo = VkApplicationInfo( | |
sType: VK_STRUCTURE_TYPE_APPLICATION_INFO, | |
pApplicationName: "Frag Application", | |
applicationVersion: vkMakeVersion(1, 0, 0), | |
pEngineName: "Frag", | |
engineVersion: vkMakeVersion(1, 0, 0), | |
apiVersion: vkApiVersion1_2, | |
) | |
state.vSync = true | |
state.backBufferFormat = FORMAT_R10G10B10A2_UNORM | |
discard vkEnumerateInstanceExtensionProperties(nil, extensionCount.addr, nil) | |
extensionProperties.setLen(extensionCount) | |
discard vkEnumerateInstanceExtensionProperties(nil, extensionCount.addr, extensionProperties[0].addr) | |
glfwRequiredExtensions = cast[cstringArray](glfwGetRequiredInstanceExtensions(glfwExtensionCount.addr)) | |
requiredExtensions = cstringArrayToSeq(glfwRequiredExtensions, glfwExtensionCount) | |
requiredExtensions.add(requiredInstanceExtensions) | |
if not checkValidationLayerSupport(): | |
echo "vulkan validation layer not available" | |
else: | |
requiredExtensions.add(requiredDebugExtensions) | |
extensionNames = requiredExtensions.allocCStringArray() | |
enabledLayerNames = validationLayers.allocCStringArray() | |
defer: | |
extensionNames.deallocCStringArray() | |
enabledLayerNames.deallocCStringArray() | |
block: | |
var createInfo = VkInstanceCreateInfo( | |
sType: VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | |
pApplicationInfo: appInfo.addr, | |
enabledExtensionCount: requiredExtensions.len.uint32, | |
ppEnabledExtensionNames: cast[ptr cstring](extensionNames), | |
enabledLayerCount: 0, | |
) | |
createInfo.enabledLayerCount = validationLayers.len.uint32 | |
createInfo.ppEnabledLayerNames = cast[ptr cstring](enabledLayerNames) | |
res = createInfo.addr.vkCreateInstance(nil, state.instance.addr) | |
assert(res == VK_SUCCESS) | |
state.instance.volkLoadInstance() | |
block: | |
var createInfo = VkDebugReportCallbackCreateInfoEXT( | |
sType: VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, | |
flags: VK_DEBUG_REPORT_ERROR_BIT_EXT.uint32 or VK_DEBUG_REPORT_WARNING_BIT_EXT.uint32, | |
pfnCallback: debugCallback, | |
) | |
res = state.instance.vkCreateDebugReportCallbackEXT(createInfo.addr, nil, state.callback.addr) | |
assert(res == VK_SUCCESS) | |
block: | |
res = state.instance.glfwCreateWindowSurface(window, nil, state.surface.addr) | |
assert(res == VK_SUCCESS) | |
block: | |
discard state.instance.vkEnumeratePhysicalDevices(deviceCount.addr, nil) | |
if deviceCount == 0: | |
assert(false) | |
devices.setLen(deviceCount) | |
discard state.instance.vkEnumeratePhysicalDevices(deviceCount.addr, devices[0].addr) | |
state.deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 | |
state.deviceProperties11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES | |
state.deviceProperties12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES | |
state.deviceProperties2.pNext = state.deviceProperties11.addr | |
state.deviceProperties11.pNext = state.deviceProperties12.addr | |
var props: VkPhysicalDeviceProperties | |
for device in devices: | |
if device.isSuitable(state.surface): | |
device.vkGetPhysicalDeviceProperties(state.deviceProperties.addr) | |
if state.deviceProperties.apiVersion >= vkApiVersion1_1 and volkGetInstanceVersion() >= vkApiVersion1_1: | |
device.vkGetPhysicalDeviceProperties2(state.deviceProperties2.addr) | |
else: | |
device.vkGetPhysicalDeviceProperties2KHR(state.deviceProperties2.addr) | |
discrete = state.deviceProperties2.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU | |
if discrete or state.physicalDevice == nil: | |
state.physicalDevice = device | |
if discrete: | |
break # if this is discrete GPU, look no further (prioritize discrete GPU) | |
if state.physicalDevice == nil: | |
assert(false) | |
state.queueIndices.init() | |
state.queueIndices = state.physicalDevice.findQueueFamilies(state.surface) | |
uniqueQueueFamilies.incl(state.queueIndices.graphicsFamily) | |
uniqueQueueFamilies.incl(state.queueIndices.presentFamily) | |
uniqueQueueFamilies.incl(state.queueIndices.copyFamily) | |
for queueFamily in uniqueQueueFamilies: | |
var queueCreateInfo: VkDeviceQueueCreateInfo | |
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO | |
queueCreateInfo.queueFamilyIndex = queueFamily.uint32 | |
queueCreateInfo.queueCount = 1 | |
queueCreateInfo.pQueuePriorities = queuePriority.addr | |
queueCreateInfos.add(queueCreateInfo) | |
assert(state.deviceProperties2.properties.limits.timestampComputeAndGraphics == VK_TRUE) | |
enabledDeviceExtensions = requiredDeviceExtensions.mapIt(it.cstring) | |
discard state.physicalDevice.vkEnumerateDeviceExtensionProperties(nil, extensionCount.addr, nil) | |
availableDeviceExtensions.setLen(extensionCount) | |
discard state.physicalDevice.vkEnumerateDeviceExtensionProperties(nil, extensionCount.addr, availableDeviceExtensions[0].addr) | |
if checkDeviceExtensionSupport(VK_KHR_SPIRV_1_4_EXTENSION_NAME, availableDeviceExtensions): | |
enabledDeviceExtensions.add(VK_KHR_SPIRV_1_4_EXTENSION_NAME.cstring) | |
state.deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 | |
state.deviceFeatures11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES | |
state.deviceFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES | |
state.deviceFeatures2.pNext = state.deviceFeatures11.addr | |
state.deviceFeatures11.pNext = state.deviceFeatures12.addr | |
state.physicalDevice.vkGetPhysicalDeviceFeatures2(state.deviceFeatures2.addr) | |
assert(state.deviceFeatures2.features.imageCubeArray == VK_TRUE) | |
assert(state.deviceFeatures2.features.independentBlend == VK_TRUE) | |
assert(state.deviceFeatures2.features.samplerAnisotropy == VK_TRUE) | |
assert(state.deviceFeatures2.features.shaderClipDistance == VK_TRUE) | |
assert(state.deviceFeatures2.features.textureCompressionBC == VK_TRUE) | |
assert(state.deviceFeatures2.features.occlusionQueryPrecise == VK_TRUE) | |
state.tessellationSupport = state.deviceFeatures2.features.tessellationShader == VK_TRUE | |
state.uavLoadFormatCommonSupport = state.deviceFeatures2.features.shaderStorageImageExtendedFormats == VK_TRUE | |
state.renderTargetAndViewportArrayIndexWithoutGSSupport = true # let's hope for the best... | |
state.physicalDevice.vkGetPhysicalDeviceFormatProperties(convertFormat(FORMAT_R11G11B10_FLOAT), formatProperties.addr) | |
state.uavLoadFormatR11G11B10Float = (formatProperties.optimalTilingFeatures.uint32 and VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT.uint32) != 0 | |
var createInfo: VkDeviceCreateInfo | |
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO | |
createInfo.queueCreateInfoCount = queueCreateInfos.len.uint32 | |
createInfo.pQueueCreateInfos = queueCreateInfos[0].addr | |
createInfo.pEnabledFeatures = nil | |
createInfo.pNext = state.deviceFeatures2.addr | |
createInfo.enabledExtensionCount = enabledDeviceExtensions.len.uint32 | |
createInfo.ppEnabledExtensionNames = enabledDeviceExtensions[0].addr | |
createInfo.enabledLayerCount = validationLayers.len.uint32 | |
createInfo.ppEnabledLayerNames = cast[ptr cstring](enabledLayerNames) | |
res = state.physicalDevice.vkCreateDevice(createInfo.addr, nil, state.device.addr) | |
assert(res == VK_SUCCESS) | |
state.device.volkLoadDevice() | |
state.device.vkGetDeviceQueue(state.queueIndices.graphicsFamily.uint32, 0'u32, state.graphicsQueue.addr) | |
state.device.vkGetDeviceQueue(state.queueIndices.presentFamily.uint32, 0'u32, state.presentQueue.addr) | |
state.allocationHandler = new AllocationHandler | |
state.allocationHandler.device = state.device | |
state.allocationHandler.instance = state.instance | |
allocatorInfo.physicalDevice = state.physicalDevice | |
allocatorInfo.device = state.device | |
allocatorInfo.instance = state.instance | |
if state.deviceFeatures12.bufferDeviceAddress.bool: | |
allocatorInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT.uint32 | |
res = allocatorInfo.addr.vmaCreateAllocator(state.allocationHandler.allocator.addr) | |
assert(res == VK_SUCCESS) | |
createBackBufferResources() | |
queueFamilyIndices.init() | |
queueFamilyIndices = findQueueFamilies(state |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment