// Copyright (c) 2018-2024 Jean-Philippe Bruyère // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) #include "vkh.h" #include "vkengine.h" #include "vkvg.h" #include #define TRY_LOAD_DEVICE_EXT(ext) \ { \ if (vkh_phyinfo_try_get_extension_properties(pi, #ext, NULL)) \ enabledExts[enabledExtsCount++] = #ext; \ } static void glfw_error_callback(int error, const char* description) { fprintf(stderr, "vkengine: GLFW error %d: %s\n", error, description); } VkSampleCountFlagBits getMaxUsableSampleCount(VkSampleCountFlags counts) { VkSampleCountFlags mask = VK_SAMPLE_COUNT_64_BIT; while (mask > VK_SAMPLE_COUNT_1_BIT) { if (counts >= mask) { return (VkSampleCountFlagBits)(counts & mask); } mask >>= 1; } return VK_SAMPLE_COUNT_1_BIT; } void vkengine_dump_Infos(VkEngine e) { printf("max samples = %d\n", getMaxUsableSampleCount(e->gpu_props.limits.framebufferColorSampleCounts)); printf("max tex2d size = %d\n", e->gpu_props.limits.maxImageDimension2D); printf("max tex array layers = %d\n", e->gpu_props.limits.maxImageArrayLayers); printf("max mem alloc count = %d\n", e->gpu_props.limits.maxMemoryAllocationCount); for (uint32_t i = 0; i < e->memory_properties.memoryHeapCount; i++) { printf("Mem Heap %d\n", i); printf("\tflags= %d\n", e->memory_properties.memoryHeaps[i].flags); printf("\tsize = %lu Mo\n", (unsigned long)e->memory_properties.memoryHeaps[i].size / (uint32_t)(1024 * 1024)); } for (uint32_t i = 0; i < e->memory_properties.memoryTypeCount; i++) { printf("Mem type %d\n", i); printf("\theap %d: ", e->memory_properties.memoryTypes[i].heapIndex); if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) printf("VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT|"); if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) printf("VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|"); if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) printf("VK_MEMORY_PROPERTY_HOST_COHERENT_BIT|"); if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) printf("VK_MEMORY_PROPERTY_HOST_CACHED_BIT|"); if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) printf("VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT|"); printf("\n"); } } void vkengine_dump_available_layers() { uint32_t layerCount; vkEnumerateInstanceLayerProperties(&layerCount, NULL); VkLayerProperties* availableLayers = (VkLayerProperties*)malloc(layerCount * sizeof(VkLayerProperties)); vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); printf("Available Layers:\n"); printf("-----------------\n"); for (uint32_t i = 0; i < layerCount; i++) { printf("\t - %s\n", availableLayers[i].layerName); } printf("-----------------\n\n"); free(availableLayers); } bool vkengine_try_get_phyinfo(VkhPhyInfo* phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo* phy) { for (uint32_t i = 0; i < phyCount; i++) { if (vkh_phyinfo_get_properties(phys[i]).deviceType == gpuType) { *phy = phys[i]; return true; } } return false; } bool instance_extension_supported(VkExtensionProperties* instanceExtProps, uint32_t extCount, const char* instanceName) { for (uint32_t i = 0; i < extCount; i++) { if (!strcmp(instanceExtProps[i].extensionName, instanceName)) return true; } return false; } vk_engine_t* vkengine_create(VkPhysicalDeviceType preferedGPU, VkPresentModeKHR presentMode, uint32_t width, uint32_t height) { glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) { perror("glfwInit failed"); exit(-1); } if (!glfwVulkanSupported()) { perror("glfwVulkanSupported return false."); exit(-1); } const char* enabledLayers[10]; const char* enabledExts[10]; uint32_t enabledExtsCount = 0, enabledLayersCount = 0, phyCount = 0; vkh_layers_check_init(); #ifdef VKVG_USE_VALIDATION if (vkh_layer_is_present("VK_LAYER_KHRONOS_validation")) enabledLayers[enabledLayersCount++] = "VK_LAYER_KHRONOS_validation"; #endif #ifdef VKVG_USE_MESA_OVERLAY if (vkh_layer_is_present("VK_LAYER_MESA_overlay")) enabledLayers[enabledLayersCount++] = "VK_LAYER_MESA_overlay"; #endif #ifdef VKVG_USE_RENDERDOC if (vkh_layer_is_present("VK_LAYER_RENDERDOC_Capture")) enabledLayers[enabledLayersCount++] = "VK_LAYER_RENDERDOC_Capture"; #endif vkh_layers_check_release(); uint32_t glfwReqExtsCount = 0; const char** gflwExts = glfwGetRequiredInstanceExtensions(&glfwReqExtsCount); vkvg_get_required_instance_extensions(enabledExts, &enabledExtsCount); for (uint32_t i = 0; i < glfwReqExtsCount; i++) enabledExts[i + enabledExtsCount] = gflwExts[i]; enabledExtsCount += glfwReqExtsCount; vk_engine_t* e = (vk_engine_t*)calloc(1, sizeof(vk_engine_t)); #ifdef VK_VERSION_1_2 e->app = vkh_app_create(1, 2, "vkvg", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); #else e->app = vkh_app_create(1, 1, "vkvg", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); #endif #if defined(DEBUG) && defined(VKVG_DBG_UTILS) vkh_app_enable_debug_messenger( e->app, VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, NULL); #endif glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); glfwWindowHint(GLFW_FLOATING, GLFW_FALSE); glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); e->window = glfwCreateWindow((int)width, (int)height, "Window Title", NULL, NULL); glfwCreateWindowSurface(vkh_app_get_inst(e->app), e->window, NULL, &e->surface); VkhPhyInfo* phys = vkh_app_get_phyinfos(e->app, &phyCount, e->surface); VkhPhyInfo pi = 0; if (!vkengine_try_get_phyinfo(phys, phyCount, preferedGPU, &pi) && !vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, &pi) && !vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, &pi)) pi = phys[0]; assert(pi && "No vulkan physical device found."); e->memory_properties = vkh_phyinfo_get_memory_properties(pi); e->gpu_props = vkh_phyinfo_get_properties(pi); uint32_t qCount = 0; float qPriorities[] = {0.0}; VkDeviceQueueCreateInfo pQueueInfos[] = {{0}, {0}, {0}}; if (vkh_phyinfo_create_presentable_queues(pi, 1, qPriorities, &pQueueInfos[qCount])) qCount++; /*if (vkh_phyinfo_create_compute_queues (pi, 1, qPriorities, &pQueueInfos[qCount])) qCount++; if (vkh_phyinfo_create_transfer_queues (pi, 1, qPriorities, &pQueueInfos[qCount])) qCount++;*/ enabledExtsCount = 0; VkPhysicalDevice* ptrPhy = (VkPhysicalDevice*)pi; if (vkvg_get_required_device_extensions(*ptrPhy, enabledExts, &enabledExtsCount) != VKVG_STATUS_SUCCESS) { perror("vkvg_get_required_device_extensions failed, enable log for details.\n"); exit(-1); } TRY_LOAD_DEVICE_EXT(VK_KHR_swapchain) VkPhysicalDeviceFeatures enabledFeatures = {0}; const void* pNext = vkvg_get_device_requirements(&enabledFeatures); VkDeviceCreateInfo device_info = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = qCount, .pQueueCreateInfos = (VkDeviceQueueCreateInfo*)&pQueueInfos, .enabledExtensionCount = enabledExtsCount, .ppEnabledExtensionNames = enabledExts, .pEnabledFeatures = &enabledFeatures, .pNext = pNext}; e->dev = vkh_device_create(e->app, pi, &device_info); vkh_phyinfo_get_queue_fam_indices(pi, &e->gQFamIdx, NULL, NULL, NULL); e->renderer = vkh_presenter_create(e->dev, (uint32_t)e->gQFamIdx, e->surface, width, height, VK_FORMAT_B8G8R8A8_UNORM, presentMode); vkh_app_free_phyinfos(phyCount, phys); return e; } void vkengine_destroy(VkEngine e) { // vkDeviceWaitIdle(e->dev->dev); VkSurfaceKHR surf = e->surface; vkh_presenter_destroy(e->renderer); vkDestroySurfaceKHR(vkh_app_get_inst(e->app), surf, NULL); vkh_device_destroy(e->dev); glfwDestroyWindow(e->window); vkh_app_destroy(e->app); glfwTerminate(); free(e); } void vkengine_close(VkEngine e) { glfwSetWindowShouldClose(e->window, GLFW_TRUE); } void vkengine_blitter_run(VkEngine e, VkImage img, uint32_t width, uint32_t height) { VkhPresenter p = e->renderer; vkh_presenter_build_blit_cmd(p, img, width, height); while (!vkengine_should_close(e)) { glfwPollEvents(); if (!vkh_presenter_draw(p)) vkh_presenter_build_blit_cmd(p, img, width, height); } } bool vkengine_should_close(VkEngine e) { return glfwWindowShouldClose(e->window); } void vkengine_set_title(VkEngine e, const char* title) { glfwSetWindowTitle(e->window, title); } VkDevice vkengine_get_device(VkEngine e) { return vkh_device_get_vkdev(e->dev); } VkPhysicalDevice vkengine_get_physical_device(VkEngine e) { return vkh_device_get_phy(e->dev); } //VkQueue vkengine_get_queue(VkEngine e) { return e->renderer->queue; } uint32_t vkengine_get_queue_fam_idx(VkEngine e) { return e->gQFamIdx; } void vkengine_wait_idle(VkEngine e) { vkDeviceWaitIdle(vkh_device_get_vkdev(e->dev)); } void vkengine_set_key_callback(VkEngine e, GLFWkeyfun key_callback) { glfwSetKeyCallback(e->window, key_callback); } void vkengine_set_mouse_but_callback(VkEngine e, GLFWmousebuttonfun onMouseBut) { glfwSetMouseButtonCallback(e->window, onMouseBut); } void vkengine_set_cursor_pos_callback(VkEngine e, GLFWcursorposfun onMouseMove) { glfwSetCursorPosCallback(e->window, onMouseMove); } void vkengine_set_scroll_callback(VkEngine e, GLFWscrollfun onScroll) { glfwSetScrollCallback(e->window, onScroll); } void vkengine_set_char_callback(VkEngine e, GLFWcharfun onChar) { glfwSetCharCallback(e->window, onChar); }