/* * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "core.hpp" namespace { #ifdef DEBUG VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type, const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* _obj) { // Set level. Log::Level log_level; switch(message_severity) { case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: log_level = Log::Level::Trace; break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: log_level = Log::Level::Information; break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: log_level = Log::Level::Warning; break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: default: log_level = Log::Level::Error; break; } // Log message. BluCat::core.log.message(log_level, callback_data->pMessage); return VK_FALSE; } #endif void load_threads(void *obj) { auto num_threads{std::thread::hardware_concurrency() - 1}; for(auto i{0}; i < num_threads; i++) BluCat::core.threads.emplace_back( BluCat::core.workers.emplace_back(&BluCat::core.job_queue)); } void unload_threads(void *obj) { BluCat::core.job_queue.stop(); for(auto &t: BluCat::core.threads) t.join(); } void load_fps(void *obj) { using namespace std::chrono; BluCat::core.max_frame_duration = duration(1000 / BluCat::core.fps); // FIXME: actually calculates the real delta time. BluCat::core.delta_time = 1.0f / BluCat::core.fps; } void load_font_library(void *obj) { FT_Error error{FT_Init_FreeType(&BluCat::core.font_library)}; if(error) throw CommandError{"Failed to open the FreeType library."}; } void unload_font_library(void *obj) { FT_Done_FreeType(BluCat::core.font_library); } #ifdef DEBUG void load_vk_debug_callback(void *obj) { PFN_vkCreateDebugUtilsMessengerEXT debug_messenger; // A Vulkan instance extension named VK_EXT_debug_utils and a Vulkan instance // layer named VK_LAYER_LUNARG_standard_validation are required to enable // this callback. These instance extension and instance layer are loaded at // Instance::load_blucat_instance. VkDebugUtilsMessengerCreateInfoEXT create_info; create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; create_info.pNext = nullptr; create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; create_info.pfnUserCallback = vk_debug_callback; create_info.pUserData = nullptr; create_info.flags = 0; debug_messenger = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(BluCat::core.vk_instance, "vkCreateDebugUtilsMessengerEXT"); if(debug_messenger(BluCat::core.vk_instance, &create_info, nullptr, &BluCat::core.vk_callback) != VK_SUCCESS) CommandError{"Failed to setup debug callback for Vulkan."}; } void unload_vk_debug_callback(void *obj) { PFN_vkDestroyDebugUtilsMessengerEXT debug_messenger; debug_messenger = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(BluCat::core.vk_instance, "vkDestroyDebugUtilsMessengerEXT"); debug_messenger(BluCat::core.vk_instance, BluCat::core.vk_callback, nullptr); } #endif void load_devices(void *obj) { uint32_t devices_count; std::vector vk_physical_devices; // Enumerate physical devices { vkEnumeratePhysicalDevices( BluCat::core.vk_instance, &devices_count, nullptr); if(devices_count < 1) CommandError{"Failed to find GPUs with Vulkan support."}; vk_physical_devices.resize(devices_count); vkEnumeratePhysicalDevices( BluCat::core.vk_instance, &devices_count, vk_physical_devices.data()); } #ifdef DEBUG BluCat::core.log.message(Log::Level::Trace, "Physical devices properties"); #endif BluCat::core.vk_devices.reserve(devices_count); for(auto i = 0; i < devices_count; i++) { // Use swapchain on first device. if(i == 0) { BluCat::core.vk_devices.emplace_back(vk_physical_devices[i], true); BluCat::core.vk_device_with_swapchain = &BluCat::core.vk_devices[i]; } else BluCat::core.vk_devices.emplace_back(vk_physical_devices[i], false); } } void unload_devices(void *obj) { BluCat::core.vk_devices.clear(); } static void load_swapchain(void *obj) { try { BluCat::core.vk_swapchain = new BluCat::Swapchain(); } catch(const CommandError &error) { std::string error_message{"Failed to create swapchain → "}; error_message += error.what(); throw CommandError{error_message}; } } void unload_swapchain(void *obj) { delete BluCat::core.vk_swapchain; } void load_framebuffer(void *obj) { try { BluCat::core.vk_framebuffer = new BluCat::Framebuffer(); } catch(const CommandError &e) { throw CommandError{"Failed to create framebuffer."}; } } void unload_framebuffer(void *obj) { delete BluCat::core.vk_framebuffer; } void load_render_pass(void *obj) { try { BluCat::core.vk_render_pass = new BluCat::RenderPass(); } catch(const CommandError &e) { throw CommandError{"Failed to create render pass."}; } } void unload_render_pass(void *obj) { delete BluCat::core.vk_render_pass; } void load_descriptor_set_layout(void *obj) { try { BluCat::core.vk_descriptor_set_layout = new BluCat::DescriptorSetLayout(); } catch(const CommandError &e) { throw CommandError{"Failed to create descriptor set layouts."}; } } void unload_descriptor_set_layout(void *obj) { delete BluCat::core.vk_descriptor_set_layout; } void load_graphics_pipeline_3d_layout(void *obj) { try { BluCat::core.vk_graphics_pipeline_3d_layout = new BluCat::GraphicsPipeline3DLayout(); } catch(const CommandError &e) { throw CommandError{"Failed to create 3d graphics pipeline."}; } } void unload_graphics_pipeline_3d_layout(void *obj) { delete BluCat::core.vk_graphics_pipeline_3d_layout; } void load_graphics_pipeline_2d_solid_layout(void *obj) { try { BluCat::core.vk_graphics_pipeline_2d_solid_layout = new BluCat::GraphicsPipeline2DSolidLayout(); } catch(const CommandError &e) { throw CommandError{"Failed to create 2d graphics pipeline."}; } } void unload_graphics_pipeline_2d_solid_layout(void *obj) { delete BluCat::core.vk_graphics_pipeline_2d_solid_layout; } void load_graphics_pipeline_2d_wired_layout(void *obj) { try { BluCat::core.vk_graphics_pipeline_2d_wired_layout = new BluCat::GraphicsPipeline2DWiredLayout(); } catch(const CommandError &e) { throw CommandError{"Failed to create 2d graphics pipeline."}; } } void unload_graphics_pipeline_2d_wired_layout(void *obj) { delete BluCat::core.vk_graphics_pipeline_2d_wired_layout; } void load_light(void *obj) { try { BluCat::core.vk_light = new BluCat::Light(); } catch(const CommandError &e) { throw CommandError{"Failed to descriptor sets for light."}; } } void unload_light(void *obj) { delete BluCat::core.vk_light; } void load_graphics_pipeline_3d(void *obj) { try { BluCat::core.vk_graphics_pipeline_3d = std::make_unique(); } catch(const CommandError &e) { throw CommandError{"Failed to create 3d graphics pipeline."}; } } void unload_graphics_pipeline_3d(void *obj) { BluCat::core.vk_graphics_pipeline_3d = nullptr; } void load_graphics_pipeline_3d_skeletal(void *obj) { try { BluCat::core.vk_graphics_pipeline_3d_skeletal = std::make_unique(); } catch(const CommandError &e) { throw CommandError{"Failed to create 3d skeletal graphics pipeline."}; } } void unload_graphics_pipeline_3d_skeletal(void *obj) { BluCat::core.vk_graphics_pipeline_3d_skeletal = nullptr; } void load_graphics_pipeline_sprite_3d(void *obj) { try { BluCat::core.vk_graphics_pipeline_sprite_3d = std::make_unique(); } catch(const CommandError &e) { throw CommandError{"Failed to create sprite 3d graphics pipeline."}; } } void unload_graphics_pipeline_sprite_3d(void *obj) { BluCat::core.vk_graphics_pipeline_sprite_3d = nullptr; } void load_graphics_pipeline_2d_solid(void *obj) { try { BluCat::core.vk_graphics_pipeline_2d_solid = std::make_unique(); } catch(const CommandError &e) { throw CommandError{"Failed to create 2d graphics pipeline."}; } } void unload_graphics_pipeline_2d_solid(void *obj) { BluCat::core.vk_graphics_pipeline_2d_solid = nullptr; } void load_graphics_pipeline_2d_wired(void *obj) { try { BluCat::core.vk_graphics_pipeline_2d_wired = std::make_unique(); } catch(const CommandError &e) { throw CommandError{"Failed to create 2d graphics pipeline."}; } } void unload_graphics_pipeline_2d_wired(void *obj) { BluCat::core.vk_graphics_pipeline_2d_wired = nullptr; } void load_renderer(void *obj) { try { glm::vec4 region( 0.f, 0.f, static_cast(BluCat::core.display_width), static_cast(BluCat::core.display_height)); BluCat::core.vk_renderer = new BluCat::Renderer( {}, {std::make_shared(region, region.z, region.w)}); } catch(const CommandError &e) { throw CommandError{"Failed to create renderer."}; } } void unload_renderer(void *obj) { delete BluCat::core.vk_renderer; } } namespace BluCat { std::random_device random_seed; std::mt19937 random_number_generator; const CommandChain Core::loader{ {&load_threads, &unload_threads}, {&load_fps, nullptr}, {&load_font_library, &unload_font_library}, #ifdef DEBUG {&load_vk_debug_callback, &unload_vk_debug_callback}, #endif {&load_devices, &unload_devices}, {&load_swapchain, &unload_swapchain}, {&load_render_pass, &unload_render_pass}, {&load_framebuffer, &unload_framebuffer}, {&load_descriptor_set_layout, &unload_descriptor_set_layout}, {&load_graphics_pipeline_3d_layout, &unload_graphics_pipeline_3d_layout}, {&load_graphics_pipeline_2d_solid_layout, &unload_graphics_pipeline_2d_solid_layout}, {&load_graphics_pipeline_2d_wired_layout, &unload_graphics_pipeline_2d_wired_layout}, {&load_light, &unload_light}, {&load_graphics_pipeline_3d_skeletal, &unload_graphics_pipeline_3d_skeletal}, {&load_graphics_pipeline_3d, &unload_graphics_pipeline_3d}, {&load_graphics_pipeline_sprite_3d, &unload_graphics_pipeline_sprite_3d}, {&load_graphics_pipeline_2d_solid, &unload_graphics_pipeline_2d_solid}, {&load_graphics_pipeline_2d_wired, &unload_graphics_pipeline_2d_wired}, {&load_renderer, &unload_renderer}, }; Core core; }