/minimal_modern_vulkan.odin Secret
Last active
July 29, 2024 21:03
Revisions
-
jockus revised this gist
Jun 27, 2024 . 1 changed file with 6 additions and 14 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -1,10 +1,7 @@ package vulkan_tutorial import "core:fmt" import "core:dynlib" import "core:mem" import "vendor:glfw" import vk "vendor:vulkan" @@ -130,14 +127,14 @@ instance_create :: proc() -> (instance: Instance) { defer delete(supported_layers) vkok(vk.EnumerateInstanceLayerProperties(&supported_layer_count, raw_data(supported_layers))) for required_layer in required_layers { layer_found : bool for &supported_layer in supported_layers { if required_layer == cstring(&supported_layer.layerName[0]) { layer_found = true break } } if !layer_found { fmt.println(ERROR, "A required layer:", required_layer, "is missing!") assert(false) } @@ -155,14 +152,14 @@ instance_create :: proc() -> (instance: Instance) { defer delete(supported_extensions) vkok(vk.EnumerateInstanceExtensionProperties(nil, &supported_extension_count, raw_data(supported_extensions))) for required_extension in required_extensions { extension_found : bool for &supported_extension in supported_extensions { if required_extension == cstring(&supported_extension.extensionName[0]) { extension_found = true break } } if !extension_found { fmt.println(ERROR, "A required extension:", required_extension, "is missing!") assert(false) } @@ -231,12 +228,8 @@ device_create :: proc(instance : Instance, surface : Surface) -> (device: Device at_least_one_pdevice_okay : bool okay_pdevice : vk.PhysicalDevice graphics_family_queue_index : u32 for pdevice in physical_devices { pdevice_supported_extensions_count : u32 vkok(vk.EnumerateDeviceExtensionProperties(pdevice, nil, &pdevice_supported_extensions_count, nil)) pdevice_supported_extensions := make([]vk.ExtensionProperties, pdevice_supported_extensions_count) @@ -279,7 +272,6 @@ device_create :: proc(instance : Instance, surface : Surface) -> (device: Device if has_required_extensions && has_required_queue_family { at_least_one_pdevice_okay = true okay_pdevice = pdevice } } -
jockus revised this gist
Jun 27, 2024 . 1 changed file with 8 additions and 17 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -75,7 +75,6 @@ main :: proc() { glfw.WindowHint(glfw.CLIENT_API, glfw.NO_API) glfw.WindowHint(glfw.RESIZABLE, glfw.TRUE) glfw.WindowHint(glfw.VISIBLE, glfw.FALSE); window_handle := glfw.CreateWindow(1000, 1000, "Vulkan Window", nil, nil) assert(window_handle != nil) defer glfw.DestroyWindow(window_handle) @@ -117,15 +116,6 @@ instance_create :: proc() -> (instance: Instance) { vk.load_proc_addresses_global(vkGetInstanceProcAddr) required_layers : [dynamic] cstring defer delete(required_layers) when ODIN_DEBUG { @@ -178,6 +168,14 @@ instance_create :: proc() -> (instance: Instance) { } } appinfo := vk.ApplicationInfo { sType = vk.StructureType.APPLICATION_INFO, pApplicationName = "Minimal Modern Vulkan", applicationVersion = vk.MAKE_VERSION(1,0,0), pEngineName = "Minimal Modern Vulkan", engineVersion = vk.MAKE_VERSION(1,0,0), apiVersion = vk.API_VERSION_1_3, } icreateinfo := vk.InstanceCreateInfo { sType = vk.StructureType.INSTANCE_CREATE_INFO, pApplicationInfo = &appinfo, @@ -186,7 +184,6 @@ instance_create :: proc() -> (instance: Instance) { enabledExtensionCount = u32(len(required_extensions)), ppEnabledExtensionNames = raw_data(required_extensions), } vkok(vk.CreateInstance(&icreateinfo, nil, &instance.instance)) vk.load_proc_addresses(instance.instance) @@ -300,7 +297,6 @@ device_create :: proc(instance : Instance, surface : Surface) -> (device: Device queueCount = 1.0, pQueuePriorities = &queue_priority_graphics, } enabledShaderObjectFeaturesEXT := vk.PhysicalDeviceShaderObjectFeaturesEXT{ sType = vk.StructureType.PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT, shaderObject = true, @@ -311,7 +307,6 @@ device_create :: proc(instance : Instance, surface : Surface) -> (device: Device pNext = &enabledShaderObjectFeaturesEXT } device_features : vk.PhysicalDeviceFeatures dci := vk.DeviceCreateInfo { sType = vk.StructureType.DEVICE_CREATE_INFO, queueCreateInfoCount = 1, @@ -321,7 +316,6 @@ device_create :: proc(instance : Instance, surface : Surface) -> (device: Device ppEnabledExtensionNames = raw_data(pdevice_required_extensions), pNext = &dynamic_rendering_feature, } vkok(vk.CreateDevice(device.physical_device, &dci, nil, &device.device)) vk.GetDeviceQueue(device.device, device.graphics_family_queue_index, 0, &device.graphics_queue) @@ -566,7 +560,6 @@ record_command_buffer :: proc(swapchain : Swapchain, rendering : ^Rendering, ima cbbi := vk.CommandBufferBeginInfo { sType = .COMMAND_BUFFER_BEGIN_INFO } vkok(vk.BeginCommandBuffer(rendering.command_buffer, &cbbi)) swapchain_barrier(rendering.command_buffer, swapchain.images[image_index], true) @@ -582,7 +575,6 @@ record_command_buffer :: proc(swapchain : Swapchain, rendering : ^Rendering, ima storeOp = vk.AttachmentStoreOp.STORE, clearValue = clear_color, } rendering_info := vk.RenderingInfoKHR{ sType = vk.StructureType.RENDERING_INFO_KHR, renderArea = { @@ -593,7 +585,6 @@ record_command_buffer :: proc(swapchain : Swapchain, rendering : ^Rendering, ima colorAttachmentCount = 1, pColorAttachments = &color_attachment_info, } vk.CmdBeginRenderingKHR(rendering.command_buffer, &rendering_info) // Set pipeline state -
jockus revised this gist
Jun 27, 2024 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -201,6 +201,7 @@ instance_destroy :: proc(instance : ^Instance) { Surface :: struct { surface : vk.SurfaceKHR } surface_create :: proc(instance : Instance, window_handle : glfw.WindowHandle) -> (surface: Surface) { vkok(glfw.CreateWindowSurface(instance.instance, window_handle, nil, &surface.surface)) return -
jockus revised this gist
Jun 27, 2024 . 1 changed file with 65 additions and 54 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -17,38 +17,6 @@ WARNING :: "WARNING:" vertex_shader_bytecode :: #load("./shaders/vertex.spv") fragment_shader_bytecode :: #load("./shaders/fragment.spv") vkok :: proc(result : vk.Result, loc := #caller_location) { #partial switch result { case .SUCCESS: @@ -112,16 +80,16 @@ main :: proc() { assert(window_handle != nil) defer glfw.DestroyWindow(window_handle) instance := instance_create() defer instance_destroy(&instance) surface := surface_create(instance, window_handle) defer surface_destroy(instance, &surface) device := device_create(instance, surface) defer device_destroy(&device) swapchain := swapchain_create(device, surface) defer swapchain_destroy(device, &swapchain) rendering := rendering_create(device) defer rendering_destroy(device, &rendering) defer vk.DeviceWaitIdle(device.device) first_present := true @@ -136,7 +104,11 @@ main :: proc() { } Instance :: struct { instance : vk.Instance } instance_create :: proc() -> (instance: Instance) { vulkan_lib, loaded := dynlib.load_library("vulkan-1.dll") assert(loaded) @@ -222,12 +194,30 @@ init_vulkan_instance :: proc() -> (instance: Instance) { return } instance_destroy :: proc(instance : ^Instance) { vk.DestroyInstance(instance.instance, nil) } Surface :: struct { surface : vk.SurfaceKHR } surface_create :: proc(instance : Instance, window_handle : glfw.WindowHandle) -> (surface: Surface) { vkok(glfw.CreateWindowSurface(instance.instance, window_handle, nil, &surface.surface)) return } surface_destroy :: proc(instance : Instance, surface : ^Surface) { vk.DestroySurfaceKHR(instance.instance, surface.surface, nil) } Device :: struct { physical_device : vk.PhysicalDevice, device : vk.Device, graphics_queue : vk.Queue, graphics_family_queue_index : u32, } device_create :: proc(instance : Instance, surface : Surface) -> (device: Device) { pds_count : u32 vkok(vk.EnumeratePhysicalDevices(instance.instance, &pds_count, nil)) physical_devices := make([]vk.PhysicalDevice, pds_count) @@ -338,7 +328,19 @@ init_vulkan_device :: proc(instance : Instance, surface : Surface) -> (device: D return } device_destroy :: proc(device : ^Device) { vk.DestroyDevice(device.device, nil) } Swapchain :: struct { swapchain : vk.SwapchainKHR, images : []vk.Image, image_views : []vk.ImageView, extent : vk.Extent2D, format : vk.Format, } swapchain_create :: proc(device : Device, surface : Surface) -> (swapchain: Swapchain) { supported_surface_formats_count : u32 vkok(vk.GetPhysicalDeviceSurfaceFormatsKHR(device.physical_device, surface.surface, &supported_surface_formats_count, nil)) supported_surface_formats := make([]vk.SurfaceFormatKHR, supported_surface_formats_count) @@ -428,7 +430,7 @@ init_vulkan_swapchain :: proc(device : Device, surface : Surface) -> (swapchain: return } swapchain_destroy :: proc(device : Device, swapchain : ^Swapchain) { for image_view in swapchain.image_views { vk.DestroyImageView(device.device, image_view, nil); } @@ -437,13 +439,22 @@ destroy_swapchain :: proc(device : Device, swapchain : ^Swapchain) { vk.DestroySwapchainKHR(device.device, swapchain.swapchain, nil); } swapchain_recreate :: proc(device : Device, surface : Surface, swapchain : ^Swapchain) { vk.DeviceWaitIdle(device.device) swapchain_destroy(device, swapchain) swapchain^ = swapchain_create(device, surface) } Rendering :: struct { shaders : [2]vk.ShaderEXT, command_pool : vk.CommandPool, command_buffer : vk.CommandBuffer, image_available_semaphore : vk.Semaphore, render_finished_semaphore : vk.Semaphore, in_flight_fence : vk.Fence, } rendering_create :: proc(device : Device) -> (rendering: Rendering) { // Ensure source is 4 bytes aligned vertex, _ := mem.alloc_bytes(len(vertex_shader_bytecode), 4) mem.copy(raw_data(vertex), raw_data(vertex_shader_bytecode), len(vertex_shader_bytecode)) @@ -509,7 +520,7 @@ init_rendering :: proc(device : Device) -> (rendering: Rendering) { return } rendering_destroy :: proc(device : Device, rendering : ^Rendering) { vk.DestroyShaderEXT(device.device, rendering.shaders[0], nil) vk.DestroyShaderEXT(device.device, rendering.shaders[1], nil) vk.FreeCommandBuffers(device.device, rendering.command_pool, 1, &rendering.command_buffer) @@ -638,7 +649,7 @@ render_frame :: proc(device : Device, surface : Surface, swapchain : ^Swapchain, image_index : u32 acquire_result := vk.AcquireNextImageKHR(device.device, swapchain.swapchain, max(u64), rendering.image_available_semaphore, 0, &image_index) if acquire_result == vk.Result.ERROR_OUT_OF_DATE_KHR || acquire_result == vk.Result.SUBOPTIMAL_KHR { swapchain_recreate(device, surface, swapchain) return } else { @@ -672,7 +683,7 @@ render_frame :: proc(device : Device, surface : Surface, swapchain : ^Swapchain, } present_result := vk.QueuePresentKHR(device.graphics_queue, &present_info) if present_result == vk.Result.ERROR_OUT_OF_DATE_KHR || present_result == vk.Result.SUBOPTIMAL_KHR { swapchain_recreate(device, surface, swapchain) } else { vkok(present_result) -
jockus revised this gist
Jun 27, 2024 . 1 changed file with 50 additions and 60 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -136,7 +136,7 @@ main :: proc() { } init_vulkan_instance :: proc() -> (instance: Instance) { vulkan_lib, loaded := dynlib.load_library("vulkan-1.dll") assert(loaded) @@ -215,22 +215,20 @@ init_vulkan_instance :: proc() -> Instance { ppEnabledExtensionNames = raw_data(required_extensions), } vkok(vk.CreateInstance(&icreateinfo, nil, &instance.instance)) vk.load_proc_addresses(instance.instance) return } init_vulkan_surface :: proc(instance : Instance, window_handle : glfw.WindowHandle) -> (surface: Surface) { vkok(glfw.CreateWindowSurface(instance.instance, window_handle, nil, &surface.surface)) return } init_vulkan_device :: proc(instance : Instance, surface : Surface) -> (device: Device) { pds_count : u32 vkok(vk.EnumeratePhysicalDevices(instance.instance, &pds_count, nil)) physical_devices := make([]vk.PhysicalDevice, pds_count) defer delete(physical_devices) @@ -301,8 +299,8 @@ init_vulkan_device :: proc(instance : Instance, surface : Surface) -> Device { fmt.eprintln("No physical devices have all the required extensions") assert(false) } device.physical_device = okay_pdevice device.graphics_family_queue_index = graphics_family_queue_index queue_priority_graphics : f32 = 1 qci_graphics := vk.DeviceQueueCreateInfo { @@ -333,16 +331,14 @@ init_vulkan_device :: proc(instance : Instance, surface : Surface) -> Device { pNext = &dynamic_rendering_feature, } vkok(vk.CreateDevice(device.physical_device, &dci, nil, &device.device)) vk.GetDeviceQueue(device.device, device.graphics_family_queue_index, 0, &device.graphics_queue) return } init_vulkan_swapchain :: proc(device : Device, surface : Surface) -> (swapchain: Swapchain) { supported_surface_formats_count : u32 vkok(vk.GetPhysicalDeviceSurfaceFormatsKHR(device.physical_device, surface.surface, &supported_surface_formats_count, nil)) supported_surface_formats := make([]vk.SurfaceFormatKHR, supported_surface_formats_count) @@ -378,9 +374,9 @@ init_vulkan_swapchain :: proc(device : Device, surface : Surface) -> Swapchain { vk.GetPhysicalDeviceSurfaceCapabilitiesKHR(device.physical_device, surface.surface, &surface_capabilities) surface_image_count := min(surface_capabilities.minImageCount + 1, surface_capabilities.maxImageCount) extent_special_value := vk.Extent2D{max(u32), max(u32)} swapchain.extent = surface_capabilities.currentExtent if swapchain.extent == extent_special_value { swapchain.extent = surface_capabilities.minImageExtent } swpcnci := vk.SwapchainCreateInfoKHR { @@ -389,7 +385,7 @@ init_vulkan_swapchain :: proc(device : Device, surface : Surface) -> Swapchain { minImageCount = surface_image_count, imageFormat = surface_format.format, imageColorSpace = surface_format.colorSpace, imageExtent = swapchain.extent, imageArrayLayers = 1, imageUsage = { vk.ImageUsageFlag.COLOR_ATTACHMENT }, imageSharingMode = .EXCLUSIVE, @@ -399,19 +395,18 @@ init_vulkan_swapchain :: proc(device : Device, surface : Surface) -> Swapchain { clipped = true, } vkok(vk.CreateSwapchainKHR(device.device, &swpcnci, nil, &swapchain.swapchain)) device_image_count : u32 vkok(vk.GetSwapchainImagesKHR(device.device, swapchain.swapchain, &device_image_count, nil)) swapchain.images = make([]vk.Image, device_image_count) vkok(vk.GetSwapchainImagesKHR(device.device, swapchain.swapchain, &device_image_count, raw_data(swapchain.images))) swapchain.image_views = make([]vk.ImageView, device_image_count) for i in 0..<device_image_count { imvci := vk.ImageViewCreateInfo { sType = .IMAGE_VIEW_CREATE_INFO, image = swapchain.images[i], viewType = vk.ImageViewType.D2, format = surface_format.format, components = { @@ -421,16 +416,16 @@ init_vulkan_swapchain :: proc(device : Device, surface : Surface) -> Swapchain { a = .IDENTITY, }, subresourceRange = { aspectMask = { .COLOR }, baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1, }, } vkok(vk.CreateImageView(device.device, &imvci, nil, &swapchain.image_views[i])) } return } destroy_swapchain :: proc(device : Device, swapchain : ^Swapchain) { @@ -448,7 +443,7 @@ recreate_swapchain :: proc(device : Device, surface : Surface, swapchain : ^Swap swapchain^ = init_vulkan_swapchain(device, surface) } init_rendering :: proc(device : Device) -> (rendering: Rendering) { // Ensure source is 4 bytes aligned vertex, _ := mem.alloc_bytes(len(vertex_shader_bytecode), 4) mem.copy(raw_data(vertex), raw_data(vertex_shader_bytecode), len(vertex_shader_bytecode)) @@ -483,41 +478,35 @@ init_rendering :: proc(device : Device) -> Rendering { // pSetLayouts = &descriptorSetLayout, } } vkok(vk.CreateShadersEXT(device.device, 2, &shaderCreateInfos[0], nil, &rendering.shaders[0])) cpci := vk.CommandPoolCreateInfo { sType = .COMMAND_POOL_CREATE_INFO, flags = { vk.CommandPoolCreateFlags.RESET_COMMAND_BUFFER }, queueFamilyIndex = device.graphics_family_queue_index, } vkok(vk.CreateCommandPool(device.device, &cpci, nil, &rendering.command_pool)) cbai := vk.CommandBufferAllocateInfo { sType = .COMMAND_BUFFER_ALLOCATE_INFO, commandPool = rendering.command_pool, level = .PRIMARY, commandBufferCount = 1, } vkok(vk.AllocateCommandBuffers(device.device, &cbai, &rendering.command_buffer)) sci := vk.SemaphoreCreateInfo { sType = .SEMAPHORE_CREATE_INFO } vkok(vk.CreateSemaphore(device.device, &sci, nil, &rendering.image_available_semaphore)) vkok(vk.CreateSemaphore(device.device, &sci, nil, &rendering.render_finished_semaphore)) fci := vk.FenceCreateInfo { sType = .FENCE_CREATE_INFO, flags = { .SIGNALED }, } vkok(vk.CreateFence(device.device, &fci, nil, &rendering.in_flight_fence)) return } destroy_rendering :: proc(device : Device, rendering : ^Rendering) { @@ -562,15 +551,16 @@ swapchain_barrier :: proc(command_buffer : vk.CommandBuffer, image : vk.Image, t } record_command_buffer :: proc(swapchain : Swapchain, rendering : ^Rendering, image_index : u32) { cbbi := vk.CommandBufferBeginInfo { sType = .COMMAND_BUFFER_BEGIN_INFO } vkok(vk.BeginCommandBuffer(rendering.command_buffer, &cbbi)) swapchain_barrier(rendering.command_buffer, swapchain.images[image_index], true) clear_color := vk.ClearValue{ color = {float32 = {0,0,0,1}} } color_attachment_info := vk.RenderingAttachmentInfoKHR{ sType = vk.StructureType.RENDERING_ATTACHMENT_INFO_KHR, @@ -621,10 +611,10 @@ record_command_buffer :: proc(swapchain : Swapchain, rendering : ^Rendering, ima colorBlendEquations := vk.ColorBlendEquationEXT{ srcColorBlendFactor = vk.BlendFactor.SRC_ALPHA, dstColorBlendFactor = .ONE_MINUS_SRC_ALPHA, colorBlendOp = .ADD, srcAlphaBlendFactor = .ONE, dstAlphaBlendFactor = .ZERO, alphaBlendOp = .ADD, } vk.CmdSetColorBlendEquationEXT(rendering.command_buffer, 0, 1, &colorBlendEquations) -
jockus revised this gist
Jun 27, 2024 . 1 changed file with 28 additions and 0 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -77,6 +77,30 @@ vkok :: proc(result : vk.Result, loc := #caller_location) { } main :: proc() { when ODIN_DEBUG { track: mem.Tracking_Allocator mem.tracking_allocator_init(&track, context.allocator) context.allocator = mem.tracking_allocator(&track) defer { if len(track.allocation_map) > 0 { fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map)) for _, entry in track.allocation_map { fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location) } } if len(track.bad_free_array) > 0 { fmt.eprintf("=== %v incorrect frees: ===\n", len(track.bad_free_array)) for entry in track.bad_free_array { fmt.eprintf("- %p @ %v\n", entry.memory, entry.location) } } mem.tracking_allocator_destroy(&track) } } glfw.Init() defer glfw.Terminate() @@ -159,6 +183,7 @@ init_vulkan_instance :: proc() -> Instance { // Ensure extensions required_extensions : [dynamic]cstring defer delete(required_extensions) for ext in glfw.GetRequiredInstanceExtensions() { append(&required_extensions, ext) } @@ -229,6 +254,7 @@ init_vulkan_device :: proc(instance : Instance, surface : Surface) -> Device { pdevice_supported_extensions_count : u32 vkok(vk.EnumerateDeviceExtensionProperties(pdevice, nil, &pdevice_supported_extensions_count, nil)) pdevice_supported_extensions := make([]vk.ExtensionProperties, pdevice_supported_extensions_count) defer delete(pdevice_supported_extensions) vkok(vk.EnumerateDeviceExtensionProperties(pdevice, nil, &pdevice_supported_extensions_count, raw_data(pdevice_supported_extensions))) has_required_extensions := true @@ -411,6 +437,8 @@ destroy_swapchain :: proc(device : Device, swapchain : ^Swapchain) { for image_view in swapchain.image_views { vk.DestroyImageView(device.device, image_view, nil); } delete(swapchain.image_views) delete(swapchain.images) vk.DestroySwapchainKHR(device.device, swapchain.swapchain, nil); } -
jockus revised this gist
Jun 27, 2024 . 1 changed file with 159 additions and 160 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -50,65 +50,65 @@ Rendering :: struct { } vkok :: proc(result : vk.Result, loc := #caller_location) { #partial switch result { case .SUCCESS: case .ERROR_OUT_OF_HOST_MEMORY: fmt.eprintln(ERROR, "Out of host memory.") case .ERROR_OUT_OF_DEVICE_MEMORY: fmt.eprintln(ERROR, "Out of device memory.") case .ERROR_INITIALIZATION_FAILED: fmt.eprintln(ERROR, "Initialization failed.") case .ERROR_LAYER_NOT_PRESENT: fmt.eprintln(ERROR, "Layer not present.") case .ERROR_EXTENSION_NOT_PRESENT: fmt.eprintln(ERROR, "Extension not present.") case .ERROR_INCOMPATIBLE_DRIVER: fmt.eprintln(ERROR, "Incompatible driver.") case: fmt.eprintln(ERROR, "Other Spec 1.3 Error!") } if result != .SUCCESS { fmt.println(ERROR, "vk function result was not .SUCCESS") fmt.println( "Result was instead:", result) fmt.println(" Error at:") fmt.println(" ", loc) assert(false) } } main :: proc() { glfw.Init() defer glfw.Terminate() glfw.WindowHint(glfw.CLIENT_API, glfw.NO_API) glfw.WindowHint(glfw.RESIZABLE, glfw.TRUE) glfw.WindowHint(glfw.VISIBLE, glfw.FALSE); window_handle := glfw.CreateWindow(1000, 1000, "Vulkan Window", nil, nil) assert(window_handle != nil) defer glfw.DestroyWindow(window_handle) instance := init_vulkan_instance() defer vk.DestroyInstance(instance.instance, nil) surface := init_vulkan_surface(instance, window_handle) defer vk.DestroySurfaceKHR(instance.instance, surface.surface, nil) device := init_vulkan_device(instance, surface) defer vk.DestroyDevice(device.device, nil) swapchain := init_vulkan_swapchain(device, surface) defer destroy_swapchain(device, &swapchain) rendering := init_rendering(device) defer destroy_rendering(device, &rendering) defer vk.DeviceWaitIdle(device.device) first_present := true for !glfw.WindowShouldClose(window_handle) { glfw.PollEvents() render_frame(device, surface, &swapchain, &rendering) if first_present { first_present = false glfw.ShowWindow(window_handle) } } } @@ -409,7 +409,7 @@ init_vulkan_swapchain :: proc(device : Device, surface : Surface) -> Swapchain { destroy_swapchain :: proc(device : Device, swapchain : ^Swapchain) { for image_view in swapchain.image_views { vk.DestroyImageView(device.device, image_view, nil); } vk.DestroySwapchainKHR(device.device, swapchain.swapchain, nil); } @@ -428,7 +428,7 @@ init_rendering :: proc(device : Device) -> Rendering { frag, _ := mem.alloc_bytes(len(fragment_shader_bytecode), 4) mem.copy(raw_data(frag), raw_data(fragment_shader_bytecode), len(fragment_shader_bytecode)) defer delete(frag) shaderCreateInfos := [2]vk.ShaderCreateInfoEXT { { sType = vk.StructureType.SHADER_CREATE_INFO_EXT, @@ -493,126 +493,125 @@ init_rendering :: proc(device : Device) -> Rendering { } destroy_rendering :: proc(device : Device, rendering : ^Rendering) { vk.DestroyShaderEXT(device.device, rendering.shaders[0], nil) vk.DestroyShaderEXT(device.device, rendering.shaders[1], nil) vk.FreeCommandBuffers(device.device, rendering.command_pool, 1, &rendering.command_buffer) vk.DestroyCommandPool(device.device, rendering.command_pool, nil) vk.DestroySemaphore(device.device, rendering.image_available_semaphore, nil) vk.DestroySemaphore(device.device, rendering.render_finished_semaphore, nil) vk.DestroyFence(device.device, rendering.in_flight_fence, nil) } swapchain_barrier :: proc(command_buffer : vk.CommandBuffer, image : vk.Image, top : bool) { image_memory_barrier := vk.ImageMemoryBarrier{ sType = vk.StructureType.IMAGE_MEMORY_BARRIER, dstAccessMask = top ? {vk.AccessFlag.COLOR_ATTACHMENT_WRITE} : {}, srcAccessMask = top ? {} : {vk.AccessFlag.COLOR_ATTACHMENT_WRITE}, oldLayout = top ? vk.ImageLayout.UNDEFINED : vk.ImageLayout.COLOR_ATTACHMENT_OPTIMAL, newLayout = top ? vk.ImageLayout.COLOR_ATTACHMENT_OPTIMAL : vk.ImageLayout.PRESENT_SRC_KHR, image = image, subresourceRange = { aspectMask = {vk.ImageAspectFlag.COLOR}, baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1, } } vk.CmdPipelineBarrier( command_buffer, top ? {vk.PipelineStageFlag.TOP_OF_PIPE} : {vk.PipelineStageFlag.COLOR_ATTACHMENT_OUTPUT}, // srcStageMask top ? {vk.PipelineStageFlag.COLOR_ATTACHMENT_OUTPUT} : {vk.PipelineStageFlag.BOTTOM_OF_PIPE}, // dstStageMask {}, {}, nil, {}, nil, 1, // imageMemoryBarrierCount &image_memory_barrier // pImageMemoryBarriers ) } record_command_buffer :: proc(swapchain : Swapchain, rendering : ^Rendering, image_index : u32) { cbbi : vk.CommandBufferBeginInfo cbbi.sType = .COMMAND_BUFFER_BEGIN_INFO vkok(vk.BeginCommandBuffer(rendering.command_buffer, &cbbi)) swapchain_barrier(rendering.command_buffer, swapchain.images[image_index], true) clear_color := vk.ClearValue{ color = { float32 = {0,0,0,1}} } color_attachment_info := vk.RenderingAttachmentInfoKHR{ sType = vk.StructureType.RENDERING_ATTACHMENT_INFO_KHR, imageView = swapchain.image_views[image_index], imageLayout = vk.ImageLayout.ATTACHMENT_OPTIMAL, loadOp = vk.AttachmentLoadOp.CLEAR, storeOp = vk.AttachmentStoreOp.STORE, clearValue = clear_color, } rendering_info := vk.RenderingInfoKHR{ sType = vk.StructureType.RENDERING_INFO_KHR, renderArea = { offset = {0, 0}, extent = swapchain.extent, }, layerCount = 1, colorAttachmentCount = 1, pColorAttachments = &color_attachment_info, } vk.CmdBeginRenderingKHR(rendering.command_buffer, &rendering_info) // Set pipeline state viewport := vk.Viewport{0, 0, f32(swapchain.extent.width), f32(swapchain.extent.height), 0, 1} scissor := vk.Rect2D{{0,0}, swapchain.extent} vk.CmdSetViewportWithCountEXT(rendering.command_buffer, 1, &viewport) vk.CmdSetScissorWithCountEXT(rendering.command_buffer, 1, &scissor) vk.CmdSetCullModeEXT(rendering.command_buffer, {vk.CullModeFlag.BACK}) vk.CmdSetFrontFaceEXT(rendering.command_buffer, vk.FrontFace.CLOCKWISE) vk.CmdSetDepthTestEnableEXT(rendering.command_buffer, true) vk.CmdSetDepthWriteEnableEXT(rendering.command_buffer, true) vk.CmdSetDepthCompareOpEXT(rendering.command_buffer, vk.CompareOp.LESS_OR_EQUAL) vk.CmdSetPrimitiveTopologyEXT(rendering.command_buffer, vk.PrimitiveTopology.TRIANGLE_LIST) vk.CmdSetRasterizerDiscardEnableEXT(rendering.command_buffer, false) vk.CmdSetPolygonModeEXT(rendering.command_buffer, vk.PolygonMode.FILL) vk.CmdSetRasterizationSamplesEXT(rendering.command_buffer, {vk.SampleCountFlag._1}) vk.CmdSetAlphaToCoverageEnableEXT(rendering.command_buffer, false) vk.CmdSetDepthBiasEnableEXT(rendering.command_buffer, false) vk.CmdSetStencilTestEnableEXT(rendering.command_buffer, false) vk.CmdSetPrimitiveRestartEnableEXT(rendering.command_buffer, false) sampleMask := vk.SampleMask(0xFF) vk.CmdSetSampleMaskEXT(rendering.command_buffer, {vk.SampleCountFlag._1}, &sampleMask) colorBlendEnables := b32(false) vk.CmdSetColorBlendEnableEXT(rendering.command_buffer, 0, 1, &colorBlendEnables) colorBlendComponentFlags := vk.ColorComponentFlags{.R, .G, .B, .A} vk.CmdSetColorWriteMaskEXT(rendering.command_buffer, 0, 1, &colorBlendComponentFlags) colorBlendEquations := vk.ColorBlendEquationEXT{ srcColorBlendFactor = vk.BlendFactor.SRC_ALPHA, dstColorBlendFactor = .ONE_MINUS_SRC_ALPHA, colorBlendOp = .ADD, srcAlphaBlendFactor = .ONE, dstAlphaBlendFactor = .ZERO, alphaBlendOp = .ADD, } vk.CmdSetColorBlendEquationEXT(rendering.command_buffer, 0, 1, &colorBlendEquations) // Bind shaders stages := [2]vk.ShaderStageFlags{{.VERTEX}, {.FRAGMENT}} vk.CmdBindShadersEXT(rendering.command_buffer, 2, &stages[0], &rendering.shaders[0]) // Submit draw vk.CmdDraw(rendering.command_buffer, 3, 1, 0, 0) vk.CmdEndRenderingKHR(rendering.command_buffer) swapchain_barrier(rendering.command_buffer, swapchain.images[image_index], false) vkok(vk.EndCommandBuffer(rendering.command_buffer)) } render_frame :: proc(device : Device, surface : Surface, swapchain : ^Swapchain, rendering : ^Rendering) { -
jockus created this gist
Jun 26, 2024 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,663 @@ package vulkan_tutorial import "base:runtime" import "core:fmt" import "core:c" import "core:dynlib" import "core:strings" import "core:mem" import "vendor:glfw" import vk "vendor:vulkan" DB :: "DEBUG:" DBVB :: "DEBUG (VERBOSE):" ERROR :: "ERROR:" WARNING :: "WARNING:" vertex_shader_bytecode :: #load("./shaders/vertex.spv") fragment_shader_bytecode :: #load("./shaders/fragment.spv") Instance :: struct { instance : vk.Instance } Surface :: struct { surface : vk.SurfaceKHR } Device :: struct { physical_device : vk.PhysicalDevice, device : vk.Device, graphics_queue : vk.Queue, graphics_family_queue_index : u32, } Swapchain :: struct { swapchain : vk.SwapchainKHR, images : []vk.Image, image_views : []vk.ImageView, extent : vk.Extent2D, format : vk.Format, } Rendering :: struct { shaders : [2]vk.ShaderEXT, command_pool : vk.CommandPool, command_buffer : vk.CommandBuffer, image_available_semaphore : vk.Semaphore, render_finished_semaphore : vk.Semaphore, in_flight_fence : vk.Fence, } vkok :: proc(result : vk.Result, loc := #caller_location) { #partial switch result { case .SUCCESS: case .ERROR_OUT_OF_HOST_MEMORY: fmt.eprintln(ERROR, "Out of host memory.") case .ERROR_OUT_OF_DEVICE_MEMORY: fmt.eprintln(ERROR, "Out of device memory.") case .ERROR_INITIALIZATION_FAILED: fmt.eprintln(ERROR, "Initialization failed.") case .ERROR_LAYER_NOT_PRESENT: fmt.eprintln(ERROR, "Layer not present.") case .ERROR_EXTENSION_NOT_PRESENT: fmt.eprintln(ERROR, "Extension not present.") case .ERROR_INCOMPATIBLE_DRIVER: fmt.eprintln(ERROR, "Incompatible driver.") case: fmt.eprintln(ERROR, "Other Spec 1.3 Error!") } if result != .SUCCESS { fmt.println(ERROR, "vk function result was not .SUCCESS") fmt.println( "Result was instead:", result) fmt.println(" Error at:") fmt.println(" ", loc) assert(false) } } main :: proc() { glfw.Init() defer glfw.Terminate() glfw.WindowHint(glfw.CLIENT_API, glfw.NO_API) glfw.WindowHint(glfw.RESIZABLE, glfw.TRUE) glfw.WindowHint(glfw.VISIBLE, glfw.FALSE); window_handle := glfw.CreateWindow(1000, 1000, "Vulkan Window", nil, nil) assert(window_handle != nil) defer glfw.DestroyWindow(window_handle) instance := init_vulkan_instance() defer vk.DestroyInstance(instance.instance, nil) surface := init_vulkan_surface(instance, window_handle) defer vk.DestroySurfaceKHR(instance.instance, surface.surface, nil) device := init_vulkan_device(instance, surface) defer vk.DestroyDevice(device.device, nil) swapchain := init_vulkan_swapchain(device, surface) defer destroy_swapchain(device, &swapchain) rendering := init_rendering(device) defer destroy_rendering(device, &rendering) defer vk.DeviceWaitIdle(device.device) first_present := true for !glfw.WindowShouldClose(window_handle) { glfw.PollEvents() render_frame(device, surface, &swapchain, &rendering) if first_present { first_present = false glfw.ShowWindow(window_handle) } } } init_vulkan_instance :: proc() -> Instance { vulkan_lib, loaded := dynlib.load_library("vulkan-1.dll") assert(loaded) vkGetInstanceProcAddr, found := dynlib.symbol_address(vulkan_lib, "vkGetInstanceProcAddr") assert(found) vk.load_proc_addresses_global(vkGetInstanceProcAddr) appinfo := vk.ApplicationInfo { sType = vk.StructureType.APPLICATION_INFO, pApplicationName = "Minimal Modern Vulkan", applicationVersion = vk.MAKE_VERSION(1,0,0), pEngineName = "Minimal Modern Vulkan", engineVersion = vk.MAKE_VERSION(1,0,0), apiVersion = vk.API_VERSION_1_3, } required_layers : [dynamic] cstring defer delete(required_layers) when ODIN_DEBUG { append(&required_layers, "VK_LAYER_KHRONOS_validation") // append(&required_layers, "VK_LAYER_KHRONOS_shader_object") } // Ensure layers supported_layer_count : u32 vkok(vk.EnumerateInstanceLayerProperties(&supported_layer_count, nil)) supported_layers := make([] vk.LayerProperties, supported_layer_count) defer delete(supported_layers) vkok(vk.EnumerateInstanceLayerProperties(&supported_layer_count, raw_data(supported_layers))) for required_layer in required_layers { found : bool for &supported_layer in supported_layers { if required_layer == cstring(&supported_layer.layerName[0]) { found = true break } } if !found { fmt.println(ERROR, "A required layer:", required_layer, "is missing!") assert(false) } } // Ensure extensions required_extensions : [dynamic]cstring for ext in glfw.GetRequiredInstanceExtensions() { append(&required_extensions, ext) } supported_extension_count : u32 vkok(vk.EnumerateInstanceExtensionProperties(nil, &supported_extension_count, nil)) supported_extensions := make([]vk.ExtensionProperties, supported_extension_count) defer delete(supported_extensions) vkok(vk.EnumerateInstanceExtensionProperties(nil, &supported_extension_count, raw_data(supported_extensions))) for required_extension in required_extensions { found : bool for &supported_extension in supported_extensions { if required_extension == cstring(&supported_extension.extensionName[0]) { found = true break } } if !found { fmt.println(ERROR, "A required extension:", required_extension, "is missing!") assert(false) } } icreateinfo := vk.InstanceCreateInfo { sType = vk.StructureType.INSTANCE_CREATE_INFO, pApplicationInfo = &appinfo, enabledLayerCount = u32(len(required_layers)), ppEnabledLayerNames = raw_data(required_layers), enabledExtensionCount = u32(len(required_extensions)), ppEnabledExtensionNames = raw_data(required_extensions), } instance : vk.Instance vkok(vk.CreateInstance(&icreateinfo, nil, &instance)) vk.load_proc_addresses(instance) return Instance{instance} } init_vulkan_surface :: proc(instance : Instance, window_handle : glfw.WindowHandle) -> Surface { surface : vk.SurfaceKHR vkok(glfw.CreateWindowSurface(instance.instance, window_handle, nil, &surface)) return Surface{surface} } init_vulkan_device :: proc(instance : Instance, surface : Surface) -> Device { pds_count : u32 vkok(vk.EnumeratePhysicalDevices(instance.instance, &pds_count, nil)) physical_devices := make([]vk.PhysicalDevice, pds_count) defer delete(physical_devices) vkok(vk.EnumeratePhysicalDevices(instance.instance, &pds_count, raw_data(physical_devices))) pdevice_required_extensions := []cstring{ vk.KHR_SWAPCHAIN_EXTENSION_NAME, vk.KHR_DYNAMIC_RENDERING_EXTENSION_NAME, vk.EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, vk.EXT_SHADER_OBJECT_EXTENSION_NAME, } at_least_one_pdevice_okay : bool okay_pdevice : vk.PhysicalDevice pdevice_properties : vk.PhysicalDeviceProperties graphics_family_queue_index : u32 for pdevice in physical_devices { pd_properties : vk.PhysicalDeviceProperties vk.GetPhysicalDeviceProperties(pdevice, &pd_properties) pdevice_supported_extensions_count : u32 vkok(vk.EnumerateDeviceExtensionProperties(pdevice, nil, &pdevice_supported_extensions_count, nil)) pdevice_supported_extensions := make([]vk.ExtensionProperties, pdevice_supported_extensions_count) vkok(vk.EnumerateDeviceExtensionProperties(pdevice, nil, &pdevice_supported_extensions_count, raw_data(pdevice_supported_extensions))) has_required_extensions := true for required_extension in pdevice_required_extensions { found : bool for &supported_extension in pdevice_supported_extensions { if required_extension == cstring(&supported_extension.extensionName[0]) { found = true break } } if !found { has_required_extensions = false break } } has_required_queue_family : bool queue_count : u32 vk.GetPhysicalDeviceQueueFamilyProperties(pdevice, &queue_count, nil) qf_properties := make([]vk.QueueFamilyProperties, queue_count) defer delete(qf_properties) vk.GetPhysicalDeviceQueueFamilyProperties(pdevice, &queue_count, raw_data(qf_properties)) for queue_family, queue_family_index in qf_properties { supports_present : b32 vkok(vk.GetPhysicalDeviceSurfaceSupportKHR(pdevice, u32(queue_family_index), surface.surface, &supports_present)) if vk.QueueFlag.GRAPHICS in queue_family.queueFlags && supports_present { graphics_family_queue_index = u32(queue_family_index) has_required_queue_family = true break } } // TODO: Ensure wanted surface format is available? if has_required_extensions && has_required_queue_family { at_least_one_pdevice_okay = true okay_pdevice = pdevice pdevice_properties = pd_properties } } if !at_least_one_pdevice_okay { fmt.eprintln("No physical devices have all the required extensions") assert(false) } pdevice : vk.PhysicalDevice pdevice = okay_pdevice queue_priority_graphics : f32 = 1 qci_graphics := vk.DeviceQueueCreateInfo { sType = vk.StructureType.DEVICE_QUEUE_CREATE_INFO, queueFamilyIndex = graphics_family_queue_index, queueCount = 1.0, pQueuePriorities = &queue_priority_graphics, } enabledShaderObjectFeaturesEXT := vk.PhysicalDeviceShaderObjectFeaturesEXT{ sType = vk.StructureType.PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT, shaderObject = true, } dynamic_rendering_feature := vk.PhysicalDeviceDynamicRenderingFeaturesKHR{ sType = vk.StructureType.PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR, dynamicRendering = true, pNext = &enabledShaderObjectFeaturesEXT } device_features : vk.PhysicalDeviceFeatures dci := vk.DeviceCreateInfo { sType = vk.StructureType.DEVICE_CREATE_INFO, queueCreateInfoCount = 1, pQueueCreateInfos = &qci_graphics, pEnabledFeatures = &device_features, enabledExtensionCount = u32(len(pdevice_required_extensions)), ppEnabledExtensionNames = raw_data(pdevice_required_extensions), pNext = &dynamic_rendering_feature, } device : vk.Device vkok(vk.CreateDevice(pdevice, &dci, nil, &device)) graphics_queue : vk.Queue vk.GetDeviceQueue(device, graphics_family_queue_index, 0, &graphics_queue) return Device{pdevice, device, graphics_queue, graphics_family_queue_index} } init_vulkan_swapchain :: proc(device : Device, surface : Surface) -> Swapchain { supported_surface_formats_count : u32 vkok(vk.GetPhysicalDeviceSurfaceFormatsKHR(device.physical_device, surface.surface, &supported_surface_formats_count, nil)) supported_surface_formats := make([]vk.SurfaceFormatKHR, supported_surface_formats_count) defer delete(supported_surface_formats) vkok(vk.GetPhysicalDeviceSurfaceFormatsKHR(device.physical_device, surface.surface, &supported_surface_formats_count, raw_data(supported_surface_formats))) surface_format := supported_surface_formats[0] desired_surface_format := vk.SurfaceFormatKHR{ format = .B8G8R8A8_SRGB, colorSpace = .SRGB_NONLINEAR, } for sf in supported_surface_formats { if sf == desired_surface_format { surface_format = desired_surface_format break } } supported_present_modes_count : u32 vkok(vk.GetPhysicalDeviceSurfacePresentModesKHR(device.physical_device, surface.surface, &supported_present_modes_count, nil)) supported_present_modes := make([]vk.PresentModeKHR, supported_present_modes_count) defer delete(supported_present_modes) vkok(vk.GetPhysicalDeviceSurfacePresentModesKHR(device.physical_device, surface.surface, &supported_present_modes_count, raw_data(supported_present_modes))) present_mode := vk.PresentModeKHR.FIFO desired_present_mode := vk.PresentModeKHR.MAILBOX for pm in supported_present_modes { if pm == desired_present_mode { present_mode = desired_present_mode } } // TODO: Just handle double/triple buffer surface_capabilities : vk.SurfaceCapabilitiesKHR vk.GetPhysicalDeviceSurfaceCapabilitiesKHR(device.physical_device, surface.surface, &surface_capabilities) surface_image_count := min(surface_capabilities.minImageCount + 1, surface_capabilities.maxImageCount) extent_special_value := vk.Extent2D{max(u32), max(u32)} extent := surface_capabilities.currentExtent if extent == extent_special_value { extent = surface_capabilities.minImageExtent } swpcnci := vk.SwapchainCreateInfoKHR { sType = .SWAPCHAIN_CREATE_INFO_KHR, surface = surface.surface, minImageCount = surface_image_count, imageFormat = surface_format.format, imageColorSpace = surface_format.colorSpace, imageExtent = extent, imageArrayLayers = 1, imageUsage = { vk.ImageUsageFlag.COLOR_ATTACHMENT }, imageSharingMode = .EXCLUSIVE, preTransform = surface_capabilities.currentTransform, compositeAlpha = { vk.CompositeAlphaFlagKHR.OPAQUE }, presentMode = present_mode, clipped = true, } swapchain : vk.SwapchainKHR vkok(vk.CreateSwapchainKHR(device.device, &swpcnci, nil, &swapchain)) device_image_count : u32 vkok(vk.GetSwapchainImagesKHR(device.device, swapchain, &device_image_count, nil)) swapchain_images := make([]vk.Image, device_image_count) vkok(vk.GetSwapchainImagesKHR(device.device, swapchain, &device_image_count, raw_data(swapchain_images))) swapchain_imageviews := make([]vk.ImageView, device_image_count) for i in 0..<device_image_count { imvci := vk.ImageViewCreateInfo { sType = .IMAGE_VIEW_CREATE_INFO, image = swapchain_images[i], viewType = vk.ImageViewType.D2, format = surface_format.format, components = { r = .IDENTITY, g = .IDENTITY, b = .IDENTITY, a = .IDENTITY, }, subresourceRange = { aspectMask = { .COLOR }, baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1, }, } vkok(vk.CreateImageView(device.device, &imvci, nil, &swapchain_imageviews[i])) } return Swapchain{swapchain, swapchain_images, swapchain_imageviews, extent, surface_format.format} } destroy_swapchain :: proc(device : Device, swapchain : ^Swapchain) { for image_view in swapchain.image_views { vk.DestroyImageView(device.device, image_view, nil); } vk.DestroySwapchainKHR(device.device, swapchain.swapchain, nil); } recreate_swapchain :: proc(device : Device, surface : Surface, swapchain : ^Swapchain) { vk.DeviceWaitIdle(device.device) destroy_swapchain(device, swapchain) swapchain^ = init_vulkan_swapchain(device, surface) } init_rendering :: proc(device : Device) -> Rendering { // Ensure source is 4 bytes aligned vertex, _ := mem.alloc_bytes(len(vertex_shader_bytecode), 4) mem.copy(raw_data(vertex), raw_data(vertex_shader_bytecode), len(vertex_shader_bytecode)) defer delete(vertex) frag, _ := mem.alloc_bytes(len(fragment_shader_bytecode), 4) mem.copy(raw_data(frag), raw_data(fragment_shader_bytecode), len(fragment_shader_bytecode)) defer delete(frag) shaderCreateInfos := [2]vk.ShaderCreateInfoEXT { { sType = vk.StructureType.SHADER_CREATE_INFO_EXT, flags = {vk.ShaderCreateFlagEXT.LINK_STAGE}, stage = {vk.ShaderStageFlag.VERTEX}, nextStage = {vk.ShaderStageFlag.FRAGMENT}, codeType = vk.ShaderCodeTypeEXT.SPIRV, pCode = raw_data(vertex), codeSize = len(vertex), pName = "main", setLayoutCount = 0, // pSetLayouts = &descriptorSetLayout, }, { sType = vk.StructureType.SHADER_CREATE_INFO_EXT, flags = {vk.ShaderCreateFlagEXT.LINK_STAGE}, stage = {vk.ShaderStageFlag.FRAGMENT}, nextStage = {}, codeType = vk.ShaderCodeTypeEXT.SPIRV, pCode = raw_data(frag), codeSize = len(frag), pName = "main", setLayoutCount = 0, // pSetLayouts = &descriptorSetLayout, } } shaders : [2]vk.ShaderEXT vkok(vk.CreateShadersEXT(device.device, 2, &shaderCreateInfos[0], nil, &shaders[0])) cpci := vk.CommandPoolCreateInfo { sType = .COMMAND_POOL_CREATE_INFO, flags = { vk.CommandPoolCreateFlags.RESET_COMMAND_BUFFER }, queueFamilyIndex = device.graphics_family_queue_index, } command_pool : vk.CommandPool vkok(vk.CreateCommandPool(device.device, &cpci, nil, &command_pool)) cbai := vk.CommandBufferAllocateInfo { sType = .COMMAND_BUFFER_ALLOCATE_INFO, commandPool = command_pool, level = .PRIMARY, commandBufferCount = 1, } command_buffer : vk.CommandBuffer vkok(vk.AllocateCommandBuffers(device.device, &cbai, &command_buffer)) sci := vk.SemaphoreCreateInfo { sType = .SEMAPHORE_CREATE_INFO } image_available_semaphore : vk.Semaphore vkok(vk.CreateSemaphore(device.device, &sci, nil, &image_available_semaphore)) render_finished_semaphore : vk.Semaphore vkok(vk.CreateSemaphore(device.device, &sci, nil, &render_finished_semaphore)) fci := vk.FenceCreateInfo { sType = .FENCE_CREATE_INFO, flags = { .SIGNALED }, } in_flight_fence : vk.Fence vkok(vk.CreateFence(device.device, &fci, nil, &in_flight_fence)) return Rendering{shaders, command_pool, command_buffer, image_available_semaphore, render_finished_semaphore, in_flight_fence} } destroy_rendering :: proc(device : Device, rendering : ^Rendering) { vk.DestroyShaderEXT(device.device, rendering.shaders[0], nil) vk.DestroyShaderEXT(device.device, rendering.shaders[1], nil) vk.FreeCommandBuffers(device.device, rendering.command_pool, 1, &rendering.command_buffer) vk.DestroyCommandPool(device.device, rendering.command_pool, nil) vk.DestroySemaphore(device.device, rendering.image_available_semaphore, nil) vk.DestroySemaphore(device.device, rendering.render_finished_semaphore, nil) vk.DestroyFence(device.device, rendering.in_flight_fence, nil) } swapchain_barrier :: proc(command_buffer : vk.CommandBuffer, image : vk.Image, top : bool) { image_memory_barrier := vk.ImageMemoryBarrier{ sType = vk.StructureType.IMAGE_MEMORY_BARRIER, dstAccessMask = top ? {vk.AccessFlag.COLOR_ATTACHMENT_WRITE} : {}, srcAccessMask = top ? {} : {vk.AccessFlag.COLOR_ATTACHMENT_WRITE}, oldLayout = top ? vk.ImageLayout.UNDEFINED : vk.ImageLayout.COLOR_ATTACHMENT_OPTIMAL, newLayout = top ? vk.ImageLayout.COLOR_ATTACHMENT_OPTIMAL : vk.ImageLayout.PRESENT_SRC_KHR, image = image, subresourceRange = { aspectMask = {vk.ImageAspectFlag.COLOR}, baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1, } } vk.CmdPipelineBarrier( command_buffer, top ? {vk.PipelineStageFlag.TOP_OF_PIPE} : {vk.PipelineStageFlag.COLOR_ATTACHMENT_OUTPUT}, // srcStageMask top ? {vk.PipelineStageFlag.COLOR_ATTACHMENT_OUTPUT} : {vk.PipelineStageFlag.BOTTOM_OF_PIPE}, // dstStageMask {}, {}, nil, {}, nil, 1, // imageMemoryBarrierCount &image_memory_barrier // pImageMemoryBarriers ) } record_command_buffer :: proc(swapchain : Swapchain, rendering : ^Rendering, image_index : u32) { cbbi : vk.CommandBufferBeginInfo cbbi.sType = .COMMAND_BUFFER_BEGIN_INFO vkok(vk.BeginCommandBuffer(rendering.command_buffer, &cbbi)) clear_color := vk.ClearValue{ color = { float32 = {0,0,0,1}} } swapchain_barrier(rendering.command_buffer, swapchain.images[image_index], true) color_attachment_info := vk.RenderingAttachmentInfoKHR{ sType = vk.StructureType.RENDERING_ATTACHMENT_INFO_KHR, imageView = swapchain.image_views[image_index], imageLayout = vk.ImageLayout.ATTACHMENT_OPTIMAL, loadOp = vk.AttachmentLoadOp.CLEAR, storeOp = vk.AttachmentStoreOp.STORE, clearValue = clear_color, } rendering_info := vk.RenderingInfoKHR{ sType = vk.StructureType.RENDERING_INFO_KHR, renderArea = { offset = {0, 0}, extent = swapchain.extent, }, layerCount = 1, colorAttachmentCount = 1, pColorAttachments = &color_attachment_info, } vk.CmdBeginRenderingKHR(rendering.command_buffer, &rendering_info) // Set pipeline state viewport := vk.Viewport{0, 0, f32(swapchain.extent.width), f32(swapchain.extent.height), 0, 1} scissor := vk.Rect2D{{0,0}, swapchain.extent} vk.CmdSetViewportWithCountEXT(rendering.command_buffer, 1, &viewport) vk.CmdSetScissorWithCountEXT(rendering.command_buffer, 1, &scissor) vk.CmdSetCullModeEXT(rendering.command_buffer, {vk.CullModeFlag.BACK}) vk.CmdSetFrontFaceEXT(rendering.command_buffer, vk.FrontFace.CLOCKWISE) vk.CmdSetDepthTestEnableEXT(rendering.command_buffer, true) vk.CmdSetDepthWriteEnableEXT(rendering.command_buffer, true) vk.CmdSetDepthCompareOpEXT(rendering.command_buffer, vk.CompareOp.LESS_OR_EQUAL) vk.CmdSetPrimitiveTopologyEXT(rendering.command_buffer, vk.PrimitiveTopology.TRIANGLE_LIST) vk.CmdSetRasterizerDiscardEnableEXT(rendering.command_buffer, false) vk.CmdSetPolygonModeEXT(rendering.command_buffer, vk.PolygonMode.FILL) vk.CmdSetRasterizationSamplesEXT(rendering.command_buffer, {vk.SampleCountFlag._1}) vk.CmdSetAlphaToCoverageEnableEXT(rendering.command_buffer, false) vk.CmdSetDepthBiasEnableEXT(rendering.command_buffer, false) vk.CmdSetStencilTestEnableEXT(rendering.command_buffer, false) vk.CmdSetPrimitiveRestartEnableEXT(rendering.command_buffer, false) sampleMask := vk.SampleMask(0xFF) vk.CmdSetSampleMaskEXT(rendering.command_buffer, {vk.SampleCountFlag._1}, &sampleMask) colorBlendEnables := b32(false) vk.CmdSetColorBlendEnableEXT(rendering.command_buffer, 0, 1, &colorBlendEnables) colorBlendComponentFlags := vk.ColorComponentFlags{.R, .G, .B, .A} vk.CmdSetColorWriteMaskEXT(rendering.command_buffer, 0, 1, &colorBlendComponentFlags) colorBlendEquations := vk.ColorBlendEquationEXT{ srcColorBlendFactor = vk.BlendFactor.SRC_ALPHA, dstColorBlendFactor = .ONE_MINUS_SRC_ALPHA, colorBlendOp = .ADD, srcAlphaBlendFactor = .ONE, dstAlphaBlendFactor = .ZERO, alphaBlendOp = .ADD, } vk.CmdSetColorBlendEquationEXT(rendering.command_buffer, 0, 1, &colorBlendEquations) // Bind shaders stages := [2]vk.ShaderStageFlags{{.VERTEX}, {.FRAGMENT}} vk.CmdBindShadersEXT(rendering.command_buffer, 2, &stages[0], &rendering.shaders[0]) // Submit draw vk.CmdDraw(rendering.command_buffer, 3, 1, 0, 0) vk.CmdEndRenderingKHR(rendering.command_buffer) swapchain_barrier(rendering.command_buffer, swapchain.images[image_index], false) vkok(vk.EndCommandBuffer(rendering.command_buffer)) } render_frame :: proc(device : Device, surface : Surface, swapchain : ^Swapchain, rendering : ^Rendering) { vkok(vk.WaitForFences(device.device, 1, &rendering.in_flight_fence, true, max(u64))) image_index : u32 acquire_result := vk.AcquireNextImageKHR(device.device, swapchain.swapchain, max(u64), rendering.image_available_semaphore, 0, &image_index) if acquire_result == vk.Result.ERROR_OUT_OF_DATE_KHR || acquire_result == vk.Result.SUBOPTIMAL_KHR { recreate_swapchain(device, surface, swapchain) return } else { vkok(acquire_result) } vkok(vk.ResetFences(device.device, 1, &rendering.in_flight_fence)) vkok(vk.ResetCommandBuffer(rendering.command_buffer, {})) record_command_buffer(swapchain^, rendering, image_index) submit_info := vk.SubmitInfo{ sType = .SUBMIT_INFO, waitSemaphoreCount = 1, pWaitSemaphores = &rendering.image_available_semaphore, pWaitDstStageMask = &vk.PipelineStageFlags{ .COLOR_ATTACHMENT_OUTPUT }, commandBufferCount = 1, pCommandBuffers = &rendering.command_buffer, signalSemaphoreCount = 1, pSignalSemaphores = &rendering.render_finished_semaphore, } vkok(vk.QueueSubmit(device.graphics_queue, 1, &submit_info, rendering.in_flight_fence)) present_info := vk.PresentInfoKHR{ sType = .PRESENT_INFO_KHR, waitSemaphoreCount = 1, pWaitSemaphores = &rendering.render_finished_semaphore, swapchainCount = 1, pSwapchains = &swapchain.swapchain, pImageIndices = &image_index, } present_result := vk.QueuePresentKHR(device.graphics_queue, &present_info) if present_result == vk.Result.ERROR_OUT_OF_DATE_KHR || present_result == vk.Result.SUBOPTIMAL_KHR { recreate_swapchain(device, surface, swapchain) } else { vkok(present_result) } }