1.vulkan_device.h
#pragma once
#include "vulkan_types.inl"
b8 vulkan_device_create(vulkan_context* context);
void vulkan_device_destroy(vulkan_context* context);
void vulkan_device_query_swapchain_support(
VkPhysicalDevice physical_device,
VkSurfaceKHR surface,
vulkan_swapchain_support_info* out_support_info
);
b8 vulkan_device_detect_depth_format(vulkan_device* device);
2.vulkan_device.c
#include "vulkan_device.h"
#include "core/logger.h"
#include "core/kstring.h"
#include "core/kmemory.h"
#include "containers/darray.h"
#include "vulkan_types.inl"
#include "vulkan_backend.h"
#include "vulkan_swapchain.h"
typedef struct vulkan_physical_device_requirements{
b8 graphics;
b8 present;
b8 compute;
b8 transfer;
//darray
const char** device_extension_names;
b8 sampler_anisotropy;
b8 discrete_gpu;
}vulkan_physical_device_requirements;
typedef struct vulkan_physical_device_queue_family_info
{
u32 graphics_family_index;
u32 present_family_index;
u32 compute_family_index;
u32 transfer_family_index;
}vulkan_physical_device_queue_family_info;
b8 select_physical_device(vulkan_context* context);
static b8 physical_device_meets_requirements(
//vulkan_context* context,
VkPhysicalDevice device,
VkSurfaceKHR surface,
const VkPhysicalDeviceProperties* properties,
const VkPhysicalDeviceFeatures* features,
const vulkan_physical_device_requirements* requirements,
vulkan_physical_device_queue_family_info* out_queue_family_info,
vulkan_swapchain_support_info* out_swapchain_support
);
b8 vulkan_device_create(vulkan_context* context)
{
if(!select_physical_device(context))
{
return false;
}
KINFO("Creating logical device...");
b8 present_shares_graphics_queue = context->device.graphics_queue_index == context->device.present_queue_index;
b8 transfer_shares_graphics_queue = context->device.graphics_queue_index == context->device.transfer_queue_index;
//b8 present_must_share_graphics = false;
u32 index_count = 1;
if(!present_shares_graphics_queue)
{
index_count++;
}
if(!transfer_shares_graphics_queue)
{
index_count++;
}
u32 indices[32];
u8 index = 0;
indices[index++] = context->device.graphics_queue_index;
if(!present_shares_graphics_queue)
{
indices[index++] = context->device.present_queue_index;
}
if(!transfer_shares_graphics_queue)
{
indices[index++] = context->device.transfer_queue_index;
}
VkDeviceQueueCreateInfo queue_create_infos[32];
for(u32 i = 0;i { queue_create_infos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_create_infos[i].queueFamilyIndex = indices[i]; queue_create_infos[i].queueCount = 1; if(indices[i] == context->device.graphics_queue_index) { queue_create_infos[i].queueCount = 2; } queue_create_infos[i].flags = 0; queue_create_infos[i].pNext = 0; f32 queue_priority = 1.0f; queue_create_infos[i].pQueuePriorities = &queue_priority; } //shoule be config driven VkPhysicalDeviceFeatures device_features = {}; device_features.samplerAnisotropy = VK_TRUE; VkDeviceCreateInfo device_create_info = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; device_create_info.queueCreateInfoCount = index_count; device_create_info.pQueueCreateInfos = queue_create_infos; device_create_info.pEnabledFeatures = &device_features; device_create_info.enabledExtensionCount = 1; const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; device_create_info.ppEnabledExtensionNames = &extension_names; device_create_info.enabledLayerCount = 0; device_create_info.ppEnabledLayerNames = 0; //没有实现 //Create the device VK_CHECK(vkCreateDevice( context->device.physical_device, &device_create_info, context->allocator, &context->device.logical_device )); KINFO("Logical device created."); vkGetDeviceQueue( context->device.logical_device, context->device.graphics_queue_index, 0, &context->device.graphics_queue ); vkGetDeviceQueue( context->device.logical_device, context->device.present_queue_index, 0, &context->device.present_queue ); vkGetDeviceQueue( context->device.logical_device, context->device.transfer_queue_index, 0, &context->device.transfer_queue); KINFO("Queues obtained."); //Create command pool for graphics queue. VkCommandPoolCreateInfo pool_create_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; pool_create_info.queueFamilyIndex = context->device.graphics_queue_index; pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; VK_CHECK(vkCreateCommandPool( context->device.logical_device, &pool_create_info, context->allocator, &context->device.graphics_command_pool )); KINFO("Graphics command pool created."); return true; } void vulkan_device_destroy(vulkan_context* context) { //Unset queues context->device.graphics_queue = 0; context->device.present_queue = 0; context->device.transfer_queue = 0; KINFO("Destroying command pools..."); vkDestroyCommandPool( context->device.logical_device, context->device.graphics_command_pool, context->allocator ); //Destroy logical device KINFO("Destroying logical device..."); if(context->device.logical_device) { vkDestroyDevice(context->device.logical_device,context->allocator); context->device.logical_device = 0; } //Physical devices are not destroyed KINFO("Releasing physical device resources..."); context->device.physical_device = 0; if(context->device.swapchain_support.formats) { kfree( context->device.swapchain_support.formats, sizeof(VkSurfaceFormatKHR)* context->device.swapchain_support.format_count, MEMORY_TAG_RENDERER ); context->device.swapchain_support.formats = 0; context->device.swapchain_support.format_count = 0; } if(context->device.swapchain_support.present_modes) { kfree( context->device.swapchain_support.present_modes, sizeof(VkSurfaceFormatKHR)* context->device.swapchain_support.present_mode_count, MEMORY_TAG_RENDERER ); context->device.swapchain_support.present_modes = 0; context->device.swapchain_support.present_mode_count = 0; } kzero_memory( &context->device.swapchain_support.capabilities, sizeof(context->device.swapchain_support.capabilities) ); context->device.graphics_queue_index = -1; context->device.present_queue_index = -1; context->device.transfer_queue_index = -1; } void vulkan_device_query_swapchain_support( VkPhysicalDevice physical_device, VkSurfaceKHR surface, vulkan_swapchain_support_info* out_support_info ){ //Surface capabilities VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR( physical_device, surface, &out_support_info->capabilities )); VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR( physical_device, surface, &out_support_info->format_count, 0 )); if(out_support_info->format_count !=0) { if(!out_support_info->formats) { out_support_info->formats = kallocate(sizeof(VkSurfaceFormatKHR)*out_support_info->format_count,MEMORY_TAG_RENDERER); } VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR( physical_device, surface, &out_support_info->format_count, out_support_info->formats )); if(out_support_info->format_count != 0) { if(!out_support_info->formats) { out_support_info->formats = kallocate(sizeof(VkSurfaceFormatKHR) * out_support_info->format_count,MEMORY_TAG_RENDERER); } VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR( physical_device, surface, &out_support_info->present_mode_count, 0 )); if(out_support_info->present_mode_count != 0) { if(!out_support_info->present_modes) { out_support_info->present_modes = kallocate(sizeof(VkPresentModeKHR)* out_support_info->present_mode_count,MEMORY_TAG_RENDERER); } VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR( physical_device, surface, &out_support_info->present_mode_count, out_support_info->present_modes )); } } } VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR( physical_device, surface, &out_support_info->present_mode_count, 0 )); } b8 vulkan_device_detect_depth_format(vulkan_device* device) { const u64 candidate_count = 3; VkFormat candidates[3] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }; u32 flags = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; for (u64 i = 0;i { VkFormatProperties properties; vkGetPhysicalDeviceFormatProperties(device->physical_device,candidates[i], &properties); if((properties.linearTilingFeatures & flags) == flags) { device->depth_format = candidates[i]; return true; }else if((properties.optimalTilingFeatures & flags) == flags) { device->depth_format = candidates[i]; return true; } } return false; } b8 select_physical_device(vulkan_context* context) { u32 physical_device_count = 0; VK_CHECK(vkEnumeratePhysicalDevices(context->instance,&physical_device_count,0)); if(physical_device_count == 0) { KFATAL("No devices which support vulkan were found."); return false; } const u32 max_device_count = 32; VkPhysicalDevice physical_devices[max_device_count]; VK_CHECK(vkEnumeratePhysicalDevices(context->instance,&physical_device_count,physical_devices)); for(u32 i = 0;i { VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(physical_devices[i],&properties); VkPhysicalDeviceFeatures features; vkGetPhysicalDeviceFeatures(physical_devices[i],&features); VkPhysicalDeviceMemoryProperties memory; vkGetPhysicalDeviceMemoryProperties(physical_devices[i],&memory); vulkan_physical_device_requirements requirements = {}; requirements.graphics = true; requirements.present = true; requirements.transfer = true; requirements.sampler_anisotropy = true; requirements.discrete_gpu = true; requirements.device_extension_names = darray_create(const char*); darray_push(requirements.device_extension_names,&VK_KHR_SWAPCHAIN_EXTENSION_NAME); vulkan_physical_device_queue_family_info queue_info = {}; b8 result = physical_device_meets_requirements( //context, physical_devices[i], context->surface, &properties, &features, &requirements, &queue_info, &context->device.swapchain_support); if(result) { KINFO("Selected device: '%s'.",properties.deviceName); //GPU type switch(properties.deviceType) { default: case VK_PHYSICAL_DEVICE_TYPE_OTHER: KINFO("GPU type is Unknown."); break; case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: KINFO("GPU type is Integrated."); break; case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: KINFO("GPU type is Descrete."); break; case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: KINFO("GPU type is Virtual."); break; case VK_PHYSICAL_DEVICE_TYPE_CPU: KINFO("GPU type is CPU."); break; } KINFO( "GPU Driver version: %d,%d,%d", VK_VERSION_MAJOR(properties.driverVersion), VK_VERSION_MINOR(properties.driverVersion), VK_VERSION_PATCH(properties.driverVersion) ); //Vulkan API version KINFO( "Vulkan API version: %d,%d,%d", VK_VERSION_MAJOR(properties.apiVersion), VK_VERSION_MINOR(properties.apiVersion), VK_VERSION_PATCH(properties.apiVersion) ); //Memory information for(u32 j = 0;j { f32 memory_size_gib = (((f32)memory.memoryHeaps[j].size)/1024.0f/1024.0f/1024.0f); if(memory.memoryHeaps[j].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { KINFO("Local GPU memory: %.2f GiB",memory_size_gib); }else { KINFO("Shared System memory: %.2f GiB",memory_size_gib); } } context->device.physical_device = physical_devices[i]; context->device.graphics_queue_index = queue_info.graphics_family_index; context->device.present_queue_index = queue_info.present_family_index; context->device.transfer_queue_index = queue_info.transfer_family_index; context->device.properties = properties; context->device.features = features; context->device.memory = memory; break; } } if(!context->device.physical_device) { KERROR("NO physical devices were found which meet the requirements."); return false; } KINFO("Physical device selected."); return true; } b8 physical_device_meets_requirements( //vulkan_context* context, VkPhysicalDevice device, VkSurfaceKHR surface, const VkPhysicalDeviceProperties* properties, const VkPhysicalDeviceFeatures* features, const vulkan_physical_device_requirements* requirements, vulkan_physical_device_queue_family_info* out_queue_info, vulkan_swapchain_support_info* out_swapchain_support ) { out_queue_info->graphics_family_index = -1; out_queue_info->present_family_index = -1; out_queue_info->compute_family_index = -1; out_queue_info->transfer_family_index = -1; if(requirements->discrete_gpu) { if(properties->deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { KINFO("Device is not a discrete GPU,and one is required.Skipping."); return false; } } u32 queue_family_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(device,&queue_family_count,0); VkQueueFamilyProperties queue_families[32]; vkGetPhysicalDeviceQueueFamilyProperties(device,&queue_family_count,queue_families); KINFO("Graphics | Present | Compute | Transfer | Name"); u8 min_transfer_score = 255; for(u32 i = 0;i { u8 current_transfer_score = 0; //Graphics queue if(queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { out_queue_info->graphics_family_index = i; ++current_transfer_score; } //Compute queue if(queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { out_queue_info->compute_family_index = i; ++current_transfer_score; } if(queue_families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { if(current_transfer_score <= min_transfer_score) { min_transfer_score = current_transfer_score; out_queue_info->transfer_family_index = i; } } VkBool32 supports_present = VK_FALSE; VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(device,i,surface,&supports_present)); if(supports_present) { out_queue_info->present_family_index = i; } } KINFO(" %d| %d| %d| %d |%s", out_queue_info->graphics_family_index != -1, out_queue_info->present_family_index != -1, out_queue_info->compute_family_index != -1, out_queue_info->transfer_family_index != -1, properties->deviceName ); if ( (!requirements->graphics || (requirements->graphics && out_queue_info->graphics_family_index != -1)) && (!requirements->present || (requirements->present && out_queue_info->present_family_index != -1)) && (!requirements->compute || (requirements->compute && out_queue_info->compute_family_index != -1)) && (!requirements->transfer || (requirements->transfer && out_queue_info->transfer_family_index != -1))) { KINFO("Device meets queue requirements."); KTRACE("Graphics Family Index: %i", out_queue_info->graphics_family_index); KTRACE("Present Family Index: %i", out_queue_info->present_family_index); KTRACE("Transfer Family Index: %i", out_queue_info->transfer_family_index); KTRACE("Compute Family Index: %i", out_queue_info->compute_family_index); //Qure swapchain support vulkan_device_query_swapchain_support( device, surface, out_swapchain_support ); if(out_swapchain_support->format_count < 1 || out_swapchain_support->present_mode_count < 1) { if(out_swapchain_support->formats) { kfree(out_swapchain_support->formats,sizeof(VkSurfaceFormatKHR) * out_swapchain_support->format_count,MEMORY_TAG_RENDERER); } if(out_swapchain_support->present_modes) { kfree(out_swapchain_support->present_modes,sizeof(VkPresentModeKHR)*out_swapchain_support->present_mode_count,MEMORY_TAG_RENDERER); } KINFO("Required swapchain support not present.skipping device"); return false; } //Device extensions if(requirements->device_extension_names) { u32 available_extension_count = 0; VkExtensionProperties* available_extensions = 0; VK_CHECK(vkEnumerateDeviceExtensionProperties( device, 0, &available_extension_count, 0 )); if(available_extension_count != 0) { available_extensions = kallocate(sizeof(VkExtensionProperties)* available_extension_count,MEMORY_TAG_RENDERER); VK_CHECK(vkEnumerateDeviceExtensionProperties( device, 0, &available_extension_count, available_extensions )); u32 required_extension_count = darray_length(requirements->device_extension_names); for(u32 i = 0;i { b8 found = false; for(u32 j = 0;j if(strings_equal(requirements->device_extension_names[i],available_extensions[j].extensionName)) { found =true; break; } } if(!found) { KINFO("Required extensions not found: '%s',skipping device.",requirements->device_extension_names[i]); kfree(available_extensions,sizeof(VkExtensionProperties) * available_extension_count,MEMORY_TAG_RENDERER); break; } } } kfree(available_extensions,sizeof(VkExtensionProperties)* available_extension_count,MEMORY_TAG_RENDERER); } // Sampler anisotropy if (requirements->sampler_anisotropy && !features->samplerAnisotropy) { KINFO("Device does not support samplerAnisotropy, skipping."); return false; } // Device meets all requirements. return true; } return false; }