package gpu_core import "core:log" import "base:runtime" import vk "vendor:vulkan" Gpu_Instance :: struct { instance: vk.Instance, debug_messenger: vk.DebugUtilsMessengerEXT, validation: bool, logger_data: rawptr, } VALIDATION_LAYER :: "VK_LAYER_KHRONOS_validation" create_instance :: proc(app_name: cstring, enable_validation: bool) -> (inst: Gpu_Instance, ok: bool) { // Load Vulkan library and global procedures if !load_vulkan() { return {}, false } // Application info app_info := vk.ApplicationInfo{ sType = .APPLICATION_INFO, pApplicationName = app_name, applicationVersion = vk.MAKE_VERSION(1, 0, 0), pEngineName = "GPU", engineVersion = vk.MAKE_VERSION(1, 0, 0), apiVersion = vk.API_VERSION_1_2, } // Required extensions extensions := make([dynamic]cstring, context.temp_allocator) append(&extensions, vk.KHR_SURFACE_EXTENSION_NAME) // Platform surface extensions when ODIN_OS == .Linux { append(&extensions, vk.KHR_XLIB_SURFACE_EXTENSION_NAME) append(&extensions, vk.KHR_WAYLAND_SURFACE_EXTENSION_NAME) } else when ODIN_OS == .Windows { append(&extensions, vk.KHR_WIN32_SURFACE_EXTENSION_NAME) } // Validation layers -- only enable if the layer is actually available layer_count: u32 = 0 layers: [1]cstring validation_available := false if enable_validation { validation_available = check_validation_layer_support() if validation_available { layers[0] = VALIDATION_LAYER layer_count = 1 append(&extensions, vk.EXT_DEBUG_UTILS_EXTENSION_NAME) } else { log.warn("gpu/core: validation layer not available, continuing without it") } } inst.validation = validation_available create_info := vk.InstanceCreateInfo{ sType = .INSTANCE_CREATE_INFO, pApplicationInfo = &app_info, enabledExtensionCount = u32(len(extensions)), ppEnabledExtensionNames = raw_data(extensions[:]), enabledLayerCount = layer_count, ppEnabledLayerNames = &layers[0] if layer_count > 0 else nil, } result := vk.CreateInstance(&create_info, nil, &inst.instance) if result != .SUCCESS { log.errorf("gpu/core: vkCreateInstance failed: %v", result) return {}, false } // Load instance-level procedures vk.load_proc_addresses_instance(inst.instance) // Setup debug messenger if inst.validation { // Capture the current logger so the debug callback can use it. // Vulkan callbacks use "system" calling convention (no Odin context), // so we pass the logger through pUserData. logger_ptr := new(log.Logger) logger_ptr^ = context.logger inst.logger_data = logger_ptr debug_info := vk.DebugUtilsMessengerCreateInfoEXT{ sType = .DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, messageSeverity = {.WARNING, .ERROR}, messageType = {.GENERAL, .VALIDATION, .PERFORMANCE}, pfnUserCallback = debug_callback, pUserData = logger_ptr, } result = vk.CreateDebugUtilsMessengerEXT(inst.instance, &debug_info, nil, &inst.debug_messenger) if result != .SUCCESS { log.warn("gpu/core: failed to create debug messenger") } } return inst, true } destroy_instance :: proc(inst: ^Gpu_Instance) { if inst.debug_messenger != 0 { vk.DestroyDebugUtilsMessengerEXT(inst.instance, inst.debug_messenger, nil) inst.debug_messenger = 0 } if inst.logger_data != nil { free(inst.logger_data) inst.logger_data = nil } if inst.instance != nil { vk.DestroyInstance(inst.instance, nil) inst.instance = nil } } @(private) check_validation_layer_support :: proc() -> bool { count: u32 vk.EnumerateInstanceLayerProperties(&count, nil) if count == 0 { return false } layers := make([]vk.LayerProperties, count, context.temp_allocator) vk.EnumerateInstanceLayerProperties(&count, raw_data(layers)) for &layer in layers { name := cstring(&layer.layerName[0]) if name == VALIDATION_LAYER { return true } } return false } @(private) debug_callback :: proc "system" ( severity: vk.DebugUtilsMessageSeverityFlagsEXT, msg_type: vk.DebugUtilsMessageTypeFlagsEXT, callback_data: ^vk.DebugUtilsMessengerCallbackDataEXT, user_data: rawptr, ) -> b32 { context = runtime.default_context() if user_data != nil { context.logger = (cast(^log.Logger)user_data)^ } if callback_data != nil && callback_data.pMessage != nil { if .ERROR in severity { log.errorf("gpu/vulkan: %s", callback_data.pMessage) } else if .WARNING in severity { log.warnf("gpu/vulkan: %s", callback_data.pMessage) } } return false }