import vulkan as nvk
, vkTypes
, vulkan_record
, vulkan_utils
, ../utils/[lets
, etc
]
, bitops
, strutils
, vkTypes
, swapchain
, gpu
, ../wain/waindow_object
, dbg
, device
, semaphores
, buffer
import ../memory/[ utils
]
const
needed_validation_layers* = ["VK_LAYER_KHRONOS_validation"]
proc check_validation_layers(
) =
when defined windows:
vkEnumerateInstanceLayerProperties = cast[proc( pPropertyCount: ptr uint32
, pProperties: ptr VkLayerProperties
): VkResult {.stdcall.}]
(vkGetProcAddress("vkEnumerateInstanceLayerProperties"))
var layer_count: uint32 = 0
discard vkEnumerateInstanceLayerProperties( addr layer_count
, nil
)
var layers = newSeq[VkLayerProperties] (layer_count)
discard vkEnumerateInstanceLayerProperties( addr layer_count
, addr layers[0]
)
for validated_layer in needed_validation_layers:
var found = false
for layer in layers:
if cstring(unsafeAddr layer.layerName) == validated_layer:
found = true
break
if not found:
echo validated_layer & " layer is not supported"
proc create_vulkan_instance*(vulkan_record: var Vulkan_Record
) =
var
validationFeatureEnables: array[3, VkValidationFeatureEnableEXT] =
[ VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT
, VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT
, VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT
]
validationFeatures = VkValidationFeaturesEXT( sType: VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT
, pNext: nil
, enabledValidationFeatureCount: 3
, pEnabledValidationFeatures: addr validationFeatureEnables[0]
, disabledValidationFeatureCount: 0
, pDisabledValidationFeatures: nil
)
instance: VkInstance
appInfo = newVkApplicationInfo(
pApplicationName = "p0",
applicationVersion = vkMakeVersion(1, 0, 0),
pEngineName = "engine_p0",
engineVersion = vkMakeVersion(1, 0, 0),
apiVersion = vkApiVersion1_3
)
var
exts = allocCStringArray(["VK_KHR_surface"
, "VK_EXT_debug_utils"
]
)
when defined linux:
exts[2] = "VK_KHR_xcb_surface"
when defined windows:
exts[2] = "VK_KHR_win32_surface"
var
instanceCreateInfo = newVkInstanceCreateInfo( pApplicationInfo = appInfo.addr
, enabledExtensionCount = 3 #TODO make dynamic
, ppEnabledExtensionNames = exts
#, enabledLayerCount = 0
#, ppEnabledLayerNames = val
, pNext = addr validationFeatures
)
vulkan_create_instance_result = vkCreateInstance( instanceCreateInfo.addr
, nil
, addr instance
)
#echo repr vulkan_create_instance_result
vulkan_record.instance = instance
when defined windows:
vkEnumerateInstanceExtensionProperties = cast[proc(pLayerName: cstring , pPropertyCount: ptr uint32 , pProperties: ptr VkExtensionProperties ): VkResult {.stdcall.}]
(vkGetProcAddress("vkEnumerateInstanceExtensionProperties"))
var extensionCount: uint32 = 0
discard vkEnumerateInstanceExtensionProperties( nil
, extensionCount.addr
, nil
)
var extensions = newSeq[VkExtensionProperties] ( extensionCount )
discard vkEnumerateInstanceExtensionProperties( nil
, extensionCount.addr
, extensions[0].addr
)
var
debugUtilsMessenger: VkDebugUtilsMessengerEXT
debugUtilsMessengerCI: VkDebugUtilsMessengerCreateInfoEXT
debugUtilsMessengerCI.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT
debugUtilsMessengerCI.messageSeverity =
VkDebugUtilsMessageSeverityFlagsEXT bitor( VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT.int
, VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT.int
, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT.int)
debugUtilsMessengerCI.messageType =
VkDebugUtilsMessageTypeFlagsEXT bitor( VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT.int
, VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT.int
, VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT.int)
debugUtilsMessengerCI.pfnUserCallback = debugUtilsMessengerCallback
vkCreateDebugUtilsMessengerEXT = cast[proc(instance: VkInstance, pCreateInfo: ptr VkDebugUtilsMessengerCreateInfoEXT , pAllocator: ptr VkAllocationCallbacks , pMessenger: ptr VkDebugUtilsMessengerEXT ): VkResult {.stdcall.}]
(vkGetInstanceProcAddr(vulkan_record.instance, "vkCreateDebugUtilsMessengerEXT"))
discard vkCreateDebugUtilsMessengerEXT(vulkan_record.instance, addr debugUtilsMessengerCI, nil, addr debugUtilsMessenger)
proc load_vulkan_device_extensions( instance: VkInstance
, device: VkDevice
) =
vkGetDeviceProcAddr = cast[proc(device: VkDevice, pName: cstring ): PFN_vkVoidFunction {.stdcall.}]
( vkGetInstanceProcAddr( instance
, "vkGetDeviceProcAddr"
)
)
vkCreateBuffer = cast[ proc( device: VkDevice
, pCreateInfo: ptr VkBufferCreateInfo
, pAllocator: ptr VkAllocationCallbacks
, pBuffer: ptr VkBuffer
): VkResult {.stdcall.}
] (vkGetDeviceProcAddr( device
, "vkCreateBuffer"
) )
vkGetBufferMemoryRequirements =cast[ proc(device: VkDevice
, buffer: VkBuffer
, pMemoryRequirements: ptr VkMemoryRequirements
): void {.stdcall.}]
((vkGetDeviceProcAddr( device
, "vkGetBufferMemoryRequirements"
) ))
vkBindBufferMemory = cast[proc(device: VkDevice, buffer: VkBuffer, memory: VkDeviceMemory, memoryOffset: VkDeviceSize): VkResult {.stdcall.}]
(vkGetDeviceProcAddr( device
, "vkBindBufferMemory"
))
proc setup_vulkan*( wain: var Waindow
): Vulkan_Record =
result = Vulkan_Record( swapchain: Swapchain()
)
vkLoad1_0()
result.create_vulkan_instance()
echo "Created vulkan_instance!"
loadVK_KHR_surface(result.instance)
loadVK_KHR_swapchain(result.instance)
result.gpu = result.instance.get_gpu
result.gpu.handle.getSupportedDepthFormat result.swapchain.depthFormat
result.createLogicalDevice
result.vk_device = result.logical_device
load_vulkan_device_extensions(result.instance
, result.vk_device
)
#result.current_descriptor_pool = create_descriptor_pool( result.vk_device )
when defined windows:
vkGetDeviceQueue = cast[proc(device: VkDevice, queueFamilyIndex: uint32, queueIndex: uint32, pQueue: ptr VkQueue ): void {.stdcall.}]
(vkGetInstanceProcAddr(result.instance
, "vkGetDeviceQueue"
)
)
#TODO: properly check and set default(?) q index for the family
vkGetDeviceQueue( result.vk_device
, result.qfi.graphics
, 0
, addr result.queue
)
#TODO: put this in a function
when defined linux:
vkCreateXcbSurfaceKHR = cast[proc(instance: VkInstance, pCreateInfo: ptr VkXcbSurfaceCreateInfoKHR , pAllocator: ptr VkAllocationCallbacks , pSurface: ptr VkSurfaceKHR ): VkResult {.stdcall.}](vkGetProc("vkCreateXcbSurfaceKHR"))
vkGetPhysicalDeviceXcbPresentationSupportKHR = cast[proc(physicalDevice: VkPhysicalDevice, queueFamilyIndex: uint32, connection: ptr xcb_connection_t , visual_id: xcb_visualid_t): VkBool32 {.stdcall.}](vkGetProc("vkGetPhysicalDeviceXcbPresentationSupportKHR"))
var surfaceCreateInfo: VkXcbSurfaceCreateInfoKHR
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR
surfaceCreateInfo.connection = cast[ptr nvk.xcb_connection_t](wain.conn)
surfaceCreateInfo.window = cast[nvk.xcb_window_t](wain.window)
var surface_res = vkCreateXcbSurfaceKHR( result.instance
, addr surfaceCreateInfo
, nil
, addr result.swapchain.surface
)
assert surface_res == VK_SUCCESS, "surface_res failed: " & $surface_res
when defined windows:
vkCreateWin32SurfaceKHR = cast[proc(instance: VkInstance, pCreateInfo: ptr VkWin32SurfaceCreateInfoKHR , pAllocator: ptr VkAllocationCallbacks , pSurface: ptr VkSurfaceKHR ): VkResult {.stdcall.}]
(vkGetInstanceProcAddr(result.instance
, "vkCreateWin32SurfaceKHR"
)
)
vkGetPhysicalDeviceWin32PresentationSupportKHR = cast[proc(physicalDevice: VkPhysicalDevice, queueFamilyIndex: uint32): VkBool32 {.stdcall.}]
(vkGetInstanceProcAddr(result.instance
, "vkGetPhysicalDeviceWin32PresentationSupportKHR"
)
)
var surfaceCreateInfo: VkWin32SurfaceCreateInfoKHR
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR
surfaceCreateInfo.hinstance = cast[nvk.HINSTANCE] ( addr wain.h_instance )
surfaceCreateInfo.hwnd = cast[nvk.HWND] (wain.hwnd)
var surface_res = vkCreateWin32SurfaceKHR( result.instance
, addr surfaceCreateInfo
, nil
, addr result.swapchain.surface
)
assert surface_res == VK_SUCCESS, "ERROR: vkCreateWin32SurfaceKHR is: " & $surface_res
result.gpu.handle.check_surface_support( result.swapchain
, result.qni
, result.instance
)
create_swapchain( result.vk_device
, result.swapchain
, result.gpu.handle
, result.current_viewport
)
#TODO: actually properly check device extensions exist on the used GPU
result.gpu.handle.check_gpu_extensions
result.create_logical_command_pool
result.draw_command_buffers = result.vk_device.create_command_buffers( result.command_pool
)
result.master_vertex_buffer = a_vulkan_buffer( result.vk_device
, result.gpu.memory_properties
, VkBufferUsageFlags bitor( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT.ord
, VK_BUFFER_USAGE_TRANSFER_DST_BIT.ord
)
, VkMemoryPropertyFlags VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
, MiB_vkds(256)
)
result.master_index_buffer = a_vulkan_buffer( result.vk_device
, result.gpu.memory_properties
, VkBufferUsageFlags bitor( VK_BUFFER_USAGE_INDEX_BUFFER_BIT.ord
, VK_BUFFER_USAGE_TRANSFER_DST_BIT.ord
)
, VkMemoryPropertyFlags VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
, MiB_vkds(128)
)
result.master_uniform_buffer = a_vulkan_buffer( result.vk_device
, result.gpu.memory_properties
, VkBufferUsageFlags VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
, VkMemoryPropertyFlags ( VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT.ord or
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT.ord
)
, MiB_vkds(256)
)
#[ result.master_vertex_buffer = a_vulkan_buffer( result.vk_device
, result.gpu.memory_properties
, VkBufferUsageFlags bitor( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT.ord
, VK_BUFFER_USAGE_TRANSFER_DST_BIT.ord
)
, VkMemoryPropertyFlags VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
, MiB_vkds(256)
) ]#
#[ master_index_buffer = a_vulkan_buffer(
)
master_uniform_buffer = a_vulkan_buffer(
)
]#
proc suballocate_vertex_buffer*( vulkan_record: var Vulkan_Record
, vertex_data: pointer
) =
copymem( vertex_data
, addr vulkan_record.master_vertex_buffer.data[vulkan_record.master_vertex_buffer.current_data_offset]
, Natural vertex_data.sizeof
)
# memcpy( &dst[dstIdx], &src[srcIdx], numElementsToCopy * sizeof( Element ) );
vulkan_record.master_vertex_buffer.current_data_offset += vertex_data.sizeof
proc suballocate_index_buffer*( vulkan_record: var Vulkan_Record
, index_data: pointer
) =
copymem( index_data
, addr vulkan_record.master_index_buffer.data[vulkan_record.master_index_buffer.current_data_offset]
, Natural index_data.sizeof
)
# memcpy( &dst[dstIdx], &src[srcIdx], numElementsToCopy * sizeof( Element ) );
vulkan_record.master_index_buffer.current_data_offset += index_data.sizeof
proc suballocate_uniform_buffer*( vulkan_record: var Vulkan_Record
, uniform_buffer_data: pointer
) =
# memcpy( &dst[dstIdx], &src[srcIdx], numElementsToCopy * sizeof( Element ) );
copyMem( uniform_buffer_data
, addr vulkan_record.master_uniform_buffer.data[vulkan_record.master_uniform_buffer.current_data_offset]
, sizeof uniform_buffer_data
)
vulkan_record.master_uniform_buffer.current_data_offset += uniform_buffer_data.sizeof