#include #include #include #include #include #include #include #include #include #include #include #include #define KVF_IMPLEMENTATION #ifdef DEBUG #define KVF_ENABLE_VALIDATION_LAYERS #endif #define KVF_ASSERT(x) (Scop::Assert(x, "internal kvf assertion " #x)) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmissing-field-initializers" #include #pragma GCC diagnostic pop #elif defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-field-initializers" #include #pragma clang diagnostic pop #else #include #endif namespace Scop { static std::unique_ptr loader; std::optional FindMemoryType(std::uint32_t type_filter, VkMemoryPropertyFlags properties, bool error) { VkPhysicalDeviceMemoryProperties mem_properties; RenderCore::Get().vkGetPhysicalDeviceMemoryProperties(RenderCore::Get().GetPhysicalDevice(), &mem_properties); for(std::uint32_t i = 0; i < mem_properties.memoryTypeCount; i++) { if((type_filter & (1 << i)) && (mem_properties.memoryTypes[i].propertyFlags & properties) == properties) return i; } if(error) FatalError("Vulkan: failed to find suitable memory type"); return std::nullopt; } void ErrorCallback(const char* message) noexcept { Logs::Report(LogType::FatalError, 0, "", "", message); std::cout << std::endl; } void ValidationErrorCallback(const char* message) noexcept { Logs::Report(LogType::Error, 0, "", "", message); std::cout << std::endl; } void WarningCallback(const char* message) noexcept { Logs::Report(LogType::Warning, 0, "", "", message); std::cout << std::endl; } RenderCore* RenderCore::s_instance = nullptr; RenderCore::RenderCore() { if(s_instance != nullptr) return; s_instance = this; Window window("", 1, 1, true); std::vector instance_extensions = window.GetRequiredVulkanInstanceExtentions(); loader = std::make_unique(); LoadKVFGlobalVulkanFunctionPointers(); kvfSetErrorCallback(&ErrorCallback); kvfSetWarningCallback(&WarningCallback); kvfSetValidationErrorCallback(&ValidationErrorCallback); kvfSetValidationWarningCallback(&WarningCallback); //kvfAddLayer("VK_LAYER_MESA_overlay"); m_instance = kvfCreateInstance(instance_extensions.data(), instance_extensions.size()); Message("Vulkan: instance created"); loader->LoadInstance(m_instance); LoadKVFInstanceVulkanFunctionPointers(); VkSurfaceKHR surface = window.CreateVulkanSurface(m_instance); m_physical_device = kvfPickGoodDefaultPhysicalDevice(m_instance, surface); // just for style VkPhysicalDeviceProperties props; vkGetPhysicalDeviceProperties(m_physical_device, &props); Message("Vulkan: physical device picked '%'", props.deviceName); const char* device_extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; VkPhysicalDeviceFeatures features{}; vkGetPhysicalDeviceFeatures(m_physical_device, &features); m_device = kvfCreateDevice(m_physical_device, device_extensions, sizeof(device_extensions) / sizeof(device_extensions[0]), &features); Message("Vulkan: logical device created"); loader->LoadDevice(m_device); LoadKVFDeviceVulkanFunctionPointers(); vkDestroySurfaceKHR(m_instance, surface, nullptr); m_allocator.AttachToDevice(m_device, m_physical_device); p_descriptor_pool_manager = std::make_unique(); ShaderLayout vertex_shader_layout( { { 0, ShaderSetLayout({ { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER } }) } }, { ShaderPushConstantLayout({ 0, sizeof(Mat4f) * 2 }) } ); m_internal_shaders[DEFAULT_VERTEX_SHADER_ID] = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/ForwardVertex.spv", ShaderType::Vertex, std::move(vertex_shader_layout)); ShaderLayout default_fragment_shader_layout( { { 1, ShaderSetLayout({ { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER }, { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER } }) } }, {} ); m_internal_shaders[DEFAULT_FRAGMENT_SHADER_ID] = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/ForwardDefaultFragment.spv", ShaderType::Fragment, std::move(default_fragment_shader_layout)); ShaderLayout basic_fragment_shader_layout( { { 1, ShaderSetLayout({ { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER }, { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER } }) } }, {} ); m_internal_shaders[BASIC_FRAGMENT_SHADER_ID] = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/ForwardBasicFragment.spv", ShaderType::Fragment, std::move(basic_fragment_shader_layout)); } #undef SCOP_LOAD_FUNCTION #define SCOP_LOAD_FUNCTION(fn) pfns.fn = this->fn void RenderCore::LoadKVFGlobalVulkanFunctionPointers() const noexcept { KvfGlobalVulkanFunctions pfns; SCOP_LOAD_FUNCTION(vkCreateInstance); SCOP_LOAD_FUNCTION(vkEnumerateInstanceExtensionProperties); SCOP_LOAD_FUNCTION(vkEnumerateInstanceLayerProperties); SCOP_LOAD_FUNCTION(vkGetInstanceProcAddr); kvfPassGlobalVulkanFunctionPointers(&pfns); } void RenderCore::LoadKVFInstanceVulkanFunctionPointers() const noexcept { KvfInstanceVulkanFunctions pfns; SCOP_LOAD_FUNCTION(vkCreateDevice); SCOP_LOAD_FUNCTION(vkDestroyInstance); SCOP_LOAD_FUNCTION(vkEnumerateDeviceExtensionProperties); SCOP_LOAD_FUNCTION(vkEnumeratePhysicalDevices); SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceFeatures); SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceFormatProperties); SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceImageFormatProperties); SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceMemoryProperties); SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceProperties); SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties); SCOP_LOAD_FUNCTION(vkDestroySurfaceKHR); SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR); SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR); SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR); kvfPassInstanceVulkanFunctionPointers(&pfns); } void RenderCore::LoadKVFDeviceVulkanFunctionPointers() const noexcept { KvfDeviceVulkanFunctions pfns; SCOP_LOAD_FUNCTION(vkAllocateCommandBuffers); SCOP_LOAD_FUNCTION(vkAllocateDescriptorSets); SCOP_LOAD_FUNCTION(vkBeginCommandBuffer); SCOP_LOAD_FUNCTION(vkCmdBeginRenderPass); SCOP_LOAD_FUNCTION(vkCmdCopyBuffer); SCOP_LOAD_FUNCTION(vkCmdCopyBufferToImage); SCOP_LOAD_FUNCTION(vkCmdCopyImage); SCOP_LOAD_FUNCTION(vkCmdCopyImageToBuffer); SCOP_LOAD_FUNCTION(vkCmdEndRenderPass); SCOP_LOAD_FUNCTION(vkCmdPipelineBarrier); SCOP_LOAD_FUNCTION(vkCreateBuffer); SCOP_LOAD_FUNCTION(vkCreateCommandPool); SCOP_LOAD_FUNCTION(vkCreateDescriptorPool); SCOP_LOAD_FUNCTION(vkCreateDescriptorSetLayout); SCOP_LOAD_FUNCTION(vkCreateFence); SCOP_LOAD_FUNCTION(vkCreateFramebuffer); SCOP_LOAD_FUNCTION(vkCreateGraphicsPipelines); SCOP_LOAD_FUNCTION(vkCreateImage); SCOP_LOAD_FUNCTION(vkCreateImageView); SCOP_LOAD_FUNCTION(vkCreatePipelineLayout); SCOP_LOAD_FUNCTION(vkCreateRenderPass); SCOP_LOAD_FUNCTION(vkCreateSampler); SCOP_LOAD_FUNCTION(vkCreateSemaphore); SCOP_LOAD_FUNCTION(vkCreateShaderModule); SCOP_LOAD_FUNCTION(vkDestroyBuffer); SCOP_LOAD_FUNCTION(vkDestroyCommandPool); SCOP_LOAD_FUNCTION(vkDestroyDescriptorPool); SCOP_LOAD_FUNCTION(vkDestroyDescriptorSetLayout); SCOP_LOAD_FUNCTION(vkDestroyDevice); SCOP_LOAD_FUNCTION(vkDestroyFence); SCOP_LOAD_FUNCTION(vkDestroyFramebuffer); SCOP_LOAD_FUNCTION(vkDestroyImage); SCOP_LOAD_FUNCTION(vkDestroyImageView); SCOP_LOAD_FUNCTION(vkDestroyPipeline); SCOP_LOAD_FUNCTION(vkDestroyPipelineLayout); SCOP_LOAD_FUNCTION(vkDestroyRenderPass); SCOP_LOAD_FUNCTION(vkDestroySampler); SCOP_LOAD_FUNCTION(vkDestroySemaphore); SCOP_LOAD_FUNCTION(vkDestroyShaderModule); SCOP_LOAD_FUNCTION(vkDeviceWaitIdle); SCOP_LOAD_FUNCTION(vkEndCommandBuffer); SCOP_LOAD_FUNCTION(vkFreeCommandBuffers); SCOP_LOAD_FUNCTION(vkGetDeviceQueue); SCOP_LOAD_FUNCTION(vkGetImageSubresourceLayout); SCOP_LOAD_FUNCTION(vkQueueSubmit); SCOP_LOAD_FUNCTION(vkResetCommandBuffer); SCOP_LOAD_FUNCTION(vkResetDescriptorPool); SCOP_LOAD_FUNCTION(vkResetEvent); SCOP_LOAD_FUNCTION(vkResetFences); SCOP_LOAD_FUNCTION(vkUpdateDescriptorSets); SCOP_LOAD_FUNCTION(vkWaitForFences); SCOP_LOAD_FUNCTION(vkCreateSwapchainKHR); SCOP_LOAD_FUNCTION(vkDestroySwapchainKHR); SCOP_LOAD_FUNCTION(vkGetSwapchainImagesKHR); SCOP_LOAD_FUNCTION(vkQueuePresentKHR); kvfPassDeviceVulkanFunctionPointers(m_physical_device, m_device, &pfns); } #undef SCOP_LOAD_FUNCTION RenderCore::~RenderCore() { if(s_instance == nullptr) return; WaitDeviceIdle(); p_descriptor_pool_manager->Destroy(); p_descriptor_pool_manager.reset(); m_allocator.DetachFromDevice(); for(auto shader: m_internal_shaders) shader->Destroy(); kvfDestroyDevice(m_device); Message("Vulkan: logical device destroyed"); kvfDestroyInstance(m_instance); Message("Vulkan: instance destroyed"); loader.reset(); s_instance = nullptr; } }