summaryrefslogtreecommitdiff
path: root/src/device.c
diff options
context:
space:
mode:
authorkartofen <mladenovnasko0@gmail.com>2023-10-18 21:00:52 +0300
committerkartofen <mladenovnasko0@gmail.com>2023-10-18 21:00:52 +0300
commit22128c747e0817f09c11b004016e6d7c518c1523 (patch)
tree315ad3ee75967504d318909e17c6f10091721d74 /src/device.c
parent9990c8d617d84e0d86ad680c39f648b0fab0906c (diff)
swap chain support and minor reorganization
Diffstat (limited to 'src/device.c')
-rw-r--r--src/device.c385
1 files changed, 287 insertions, 98 deletions
diff --git a/src/device.c b/src/device.c
index 9836db1..75a727d 100644
--- a/src/device.c
+++ b/src/device.c
@@ -8,48 +8,71 @@
// TODO: add error checking
// TODO: add log output
+#define CLAMP(val, min, max) (((val) < (min)) ? (min) : ((val) > (max) ? (max) : (val)))
+
#ifdef DEBUG
char *validation_layers[] = {
"VK_LAYER_KHRONOS_validation"
};
#endif
-enum {
- QUEUE_FAMILY_COUNT = 2,
-
- QUEUE_FAMILY_GRAPHICS_FAMILY = 1 << 0,
- QUEUE_FAMILY_PRESENT_FAMILY = 1 << 1,
-
- QUEUE_FAMILY_ALL = QUEUE_FAMILY_GRAPHICS_FAMILY |
- QUEUE_FAMILY_PRESENT_FAMILY,
+char *device_extensions[] = {
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
struct queue_family_idx {
- uint32_t graphics_family;
- uint32_t present_family;
+ u32 graphics_family;
+ bool has_graphics_family;
+
+ u32 present_family;
+ bool has_present_family;
+};
+
+struct swap_chain_support_details {
+ VkSurfaceCapabilitiesKHR capabilities;
+
+ VkSurfaceFormatKHR *formats;
+ u32 nformats;
+
+ VkPresentModeKHR *present_modes;
+ u32 npresent_modes;
};
// most function that return an int follow this scheme:
// 0 - success; 1 - error; (sometimes -1 - fatal error)
-// if the function has 'has' or 'is', then
-// 0 - fail; 1 - success (sometimes -1 - fatal error)
-
+// -- Major Functions ---
static int create_instance(device_t device, struct device_info *info);
static int create_surface(device_t device, struct device_info *info);
static int create_physical_device(device_t device, struct device_info *info);
static int create_logical_device(device_t device, struct device_info *info);
+static int create_swap_chain(device_t device, struct device_info *info);
-static int is_device_suitable(VkPhysicalDevice phy_device, VkSurfaceKHR surface);
+// --- Helper Function ---
+static bool device_is_suitable(VkPhysicalDevice phy_device, VkSurfaceKHR surface);
+static bool device_has_extension_support(VkPhysicalDevice phy_device);
+static int device_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family);
-// does not follow the general scheme, see implementation for details
-static int find_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family);
+static int swap_chain_support(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct swap_chain_support_details *details);
+static void swap_chain_free_support_details(struct swap_chain_support_details *details);
+static int swap_chain_choose_format(VkSurfaceFormatKHR* formats, u32 nformats, VkSurfaceFormatKHR *format);
+static int swap_chain_choose_present_mode(VkPresentModeKHR *modes, u32 nmodes, VkPresentModeKHR *mode);
+static int swap_chain_get_extent(VkSurfaceCapabilitiesKHR capabilities, VkExtent2D *extent);
+// --- Debug Functions ---
#ifdef DEBUG
+static bool instance_has_validation_layers(const char * const *layers, u32 nlayers);
+
static int create_debug_messenger(device_t device, struct device_info* info);
-static int has_validation_layer_support(const char * const *layers, uint32_t nlayers);
-static void populate_debug_messenger_info(VkDebugUtilsMessengerCreateInfoEXT *info);
+static void debug_messenger_populate_info(VkDebugUtilsMessengerCreateInfoEXT *info);
+
+static VKAPI_ATTR VkBool32 VKAPI_CALL debug_messenger_callback(
+ VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
+ VkDebugUtilsMessageTypeFlagsEXT messageType,
+ const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
+ void* pUserData);
+// Vulkan Wrappers
VkResult CreateDebugUtilsMessengerEXT(
VkInstance instance,
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
@@ -59,11 +82,6 @@ void DestroyDebugUtilsMessengerEXT(
VkInstance instance,
VkDebugUtilsMessengerEXT debugMessenger,
const VkAllocationCallbacks* pAllocator);
-static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(
- VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
- VkDebugUtilsMessageTypeFlagsEXT messageType,
- const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
- void* pUserData);
#endif
#define CHECK(func) if(func(device, info)) { goto fail; }
@@ -71,6 +89,9 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(
device_t device_create(struct device_info *info)
{
device_t device = xmalloc(sizeof(struct device));
+ device->instance = VK_NULL_HANDLE;
+ device->logical_device = VK_NULL_HANDLE;
+ device->swap_chain = VK_NULL_HANDLE;
CHECK(create_instance);
CHECK(create_surface);
@@ -79,6 +100,7 @@ device_t device_create(struct device_info *info)
#endif
CHECK(create_physical_device);
CHECK(create_logical_device);
+ CHECK(create_swap_chain)
return device;
fail:
@@ -90,14 +112,16 @@ void device_destroy(device_t device)
{
if(!device) return;
+ free(device->swap_chain_images);
+ vkDestroySwapchainKHR(device->logical_device, device->swap_chain, NULL);
+
vkDestroyDevice(device->logical_device, NULL);
#ifdef DEBUG
DestroyDebugUtilsMessengerEXT(device->instance, device->debug_messenger, NULL);
#endif
-
+
vkDestroySurfaceKHR(device->instance, device->surface, NULL);
-
vkDestroyInstance(device->instance, NULL);
free(device);
@@ -105,6 +129,8 @@ void device_destroy(device_t device)
static int create_instance(device_t device, struct device_info *info)
{
+ int ret = 1;
+
VkApplicationInfo app_info = {0};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pEngineName = "Engine";
@@ -124,24 +150,19 @@ static int create_instance(device_t device, struct device_info *info)
char **extensions = xcalloc(info->ext_count+1, sizeof(char *));
extensions[info->ext_count] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
- for(uint32_t i = 0; i < info->ext_count; i++) {
+ for(u32 i = 0; i < info->ext_count; i++) {
extensions[i] = (char *)info->extensions[i];
}
- // we just added one more extension
create_info.enabledExtensionCount = info->ext_count+1;
create_info.ppEnabledExtensionNames = (const char * const *)extensions;
// validation layer support
- char *validation_layers[] = {
- "VK_LAYER_KHRONOS_validation"
- };
-
- uint32_t nlayers = ARR_SIZE(validation_layers);
+ u32 nlayers = ARR_SIZE(validation_layers);
- if(!has_validation_layer_support((const char * const *)validation_layers, nlayers)) {
+ if(!instance_has_validation_layers((const char * const *)validation_layers, nlayers)) {
err("validation_layer_support: failed");
- goto fail;
+ goto exit;
}
create_info.ppEnabledLayerNames = (const char * const *)validation_layers;
@@ -149,23 +170,25 @@ static int create_instance(device_t device, struct device_info *info)
// add the debug messenger for instance creation and destruction
VkDebugUtilsMessengerCreateInfoEXT msg_info = {0};
- populate_debug_messenger_info(&msg_info);
+ debug_messenger_populate_info(&msg_info);
create_info.pNext = &msg_info;
#endif
if(vkCreateInstance(&create_info, NULL, &device->instance) != VK_SUCCESS) {
err("vkCreateInstance: failed");
- goto fail;
+ goto exit;
}
+
+
+ ret = 0;
+exit:
+
#ifdef DEBUG
free(extensions);
#endif
-
- return 0;
-fail:
- return 1;
+ return ret;
}
static int create_surface(device_t device, struct device_info *info)
@@ -181,22 +204,23 @@ static int create_surface(device_t device, struct device_info *info)
static int create_physical_device(device_t device, struct device_info *info)
{
(void)info;
+ int ret = 1;
device->physical_device = VK_NULL_HANDLE;
- uint32_t dev_count = 0;
+ u32 dev_count = 0;
vkEnumeratePhysicalDevices(device->instance, &dev_count, NULL);
if(dev_count == 0) {
err("No physical devices could be found!");
- goto fail;
+ goto exit;
}
VkPhysicalDevice *devices = xcalloc(dev_count, sizeof(VkPhysicalDevice));
vkEnumeratePhysicalDevices(device->instance, &dev_count, devices);
- for(uint32_t i = 0; i < dev_count; i++) {
- if(is_device_suitable(devices[i], device->surface)) {
+ for(u32 i = 0; i < dev_count; i++) {
+ if(device_is_suitable(devices[i], device->surface)) {
device->physical_device = devices[i];
break;
}
@@ -206,39 +230,42 @@ static int create_physical_device(device_t device, struct device_info *info)
if(device->physical_device == VK_NULL_HANDLE) {
err("No suitable physical device could be found");
- goto fail;
+ goto exit;
}
-
- return 0;
-fail:
- return 1;
+
+ ret = 0;
+exit:
+ return ret;
}
static int create_logical_device(device_t device, struct device_info *info)
{
(void)info;
+ int ret = 1;
// queue family data
struct queue_family_idx indices = {0};
- find_queue_families(device->physical_device, device->surface, &indices);
+ device_queue_families(device->physical_device, device->surface, &indices);
// queue infos
+ #define QUEUE_FAMILY_COUNT 2
+
VkDeviceQueueCreateInfo queue_infos[QUEUE_FAMILY_COUNT] = {0};
- uint32_t queue_indices[QUEUE_FAMILY_COUNT] = {
+ u32 queue_indices[QUEUE_FAMILY_COUNT] = {
indices.graphics_family, indices.present_family,
};
- uint32_t unique_queue_family_count = 0;
+ u32 unique_queue_family_count = 0;
float queue_priority = 1.0f;
// basically get add only the unique queue families
- for(int i = 0; i < QUEUE_FAMILY_COUNT; i++)
+ for(size_t i = 0; i < QUEUE_FAMILY_COUNT; i++)
{
- int unique = 1;
- for(int j = 0; j < i; j++) {
+ bool unique = true;
+ for(size_t j = 0; j < i; j++) {
if(queue_indices[i] == queue_indices[j]) {
- unique = 0;
+ unique = false;
break;
}
}
@@ -264,8 +291,9 @@ static int create_logical_device(device_t device, struct device_info *info)
create_info.queueCreateInfoCount = unique_queue_family_count;
create_info.pEnabledFeatures = &device_features;
-
- create_info.enabledExtensionCount = 0;
+
+ create_info.ppEnabledExtensionNames = (const char * const *)device_extensions;
+ create_info.enabledExtensionCount = ARR_SIZE(device_extensions);
// validation layers can be set, but
// newer implementations will ignore them
@@ -274,67 +302,241 @@ static int create_logical_device(device_t device, struct device_info *info)
if(vkCreateDevice(device->physical_device, &create_info, NULL, &device->logical_device) != VK_SUCCESS) {
err("vkCreateDevice: failed");
- goto fail;
+ goto exit;
}
- // vkGetDeviceQueue(device->logical_device, indices.graphics_family, 0, &device->graphics_queue);
+ vkGetDeviceQueue(device->logical_device, indices.graphics_family, 0, &device->graphics_queue);
+ vkGetDeviceQueue(device->logical_device, indices.present_family, 0, &device->present_queue);
- return 0;
-fail:
- return 1;
+ ret = 0;
+exit:
+ return ret;
}
-// returns a bitmask if a given family is set, or not
-static int find_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family)
+static int create_swap_chain(device_t device, struct device_info *info)
{
- int ret = 0;
+ (void)info;
+ int ret = 1;
+
+ struct swap_chain_support_details details;
+ swap_chain_support(device->physical_device, device->surface, &details);
+
+ VkSurfaceFormatKHR surface_format;
+ VkPresentModeKHR present_mode;
+ VkExtent2D extent;
+ u32 image_count = 3;
- uint32_t count = 0;
+ swap_chain_choose_format(details.formats, details.nformats, &surface_format);
+ swap_chain_choose_present_mode(details.present_modes, details.npresent_modes, &present_mode);
+ swap_chain_get_extent(details.capabilities, &extent);
+
+ if(details.capabilities.maxImageCount > 0) {
+ image_count = CLAMP(image_count, details.capabilities.minImageCount, details.capabilities.maxImageCount);
+ }
+
+ // start filling in the create info
+ VkSwapchainCreateInfoKHR create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+
+ create_info.surface = device->surface;
+ create_info.minImageCount = image_count;
+ create_info.imageFormat = surface_format.format;
+ create_info.imageColorSpace = surface_format.colorSpace;
+ create_info.imageExtent = extent;
+ create_info.imageArrayLayers = 1;
+ create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ struct queue_family_idx indices;
+ device_queue_families(device->physical_device, device->surface, &indices);
+
+ u32 queue_indices[2] = { indices.graphics_family, indices.present_family };
+
+ // set the sharing mode of the images
+ if(indices.graphics_family != indices.present_family) {
+ create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+ create_info.queueFamilyIndexCount = 2;
+ create_info.pQueueFamilyIndices = queue_indices;
+ } else {
+ create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ create_info.queueFamilyIndexCount = 0;
+ create_info.pQueueFamilyIndices = NULL;
+ }
+
+ create_info.preTransform = details.capabilities.currentTransform;
+ create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+
+ create_info.presentMode = present_mode;
+ create_info.clipped = VK_TRUE;
+
+ create_info.oldSwapchain = NULL;
+
+ if (vkCreateSwapchainKHR(device->logical_device, &create_info, NULL, &device->swap_chain) != VK_SUCCESS) {
+ goto exit;
+ }
+
+ vkGetSwapchainImagesKHR(device->logical_device, device->swap_chain, &device->nimages, NULL);
+
+ device->swap_chain_images = xcalloc(device->nimages, sizeof(*device->swap_chain_images));
+ vkGetSwapchainImagesKHR(device->logical_device, device->swap_chain, &device->nimages, device->swap_chain_images);
+
+ ret = 0;
+exit:
+ swap_chain_free_support_details(&details);
+ return ret;
+}
+
+static int device_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family)
+{
+ u32 count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(phy_device, &count, NULL);
VkQueueFamilyProperties *properties = xcalloc(count, sizeof(VkQueueFamilyProperties));
vkGetPhysicalDeviceQueueFamilyProperties(phy_device, &count, properties);
- for(uint32_t i = 0; i < count; i++) {
+ for(u32 i = 0; i < count; i++) {
if(properties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
- ret |= QUEUE_FAMILY_GRAPHICS_FAMILY;
- if(queue_family != NULL) {
- queue_family->graphics_family = i;
- }
+ queue_family->graphics_family = i;
+ queue_family->has_graphics_family = true;
}
- VkBool32 present_support = 0;
+ VkBool32 present_support = false;
vkGetPhysicalDeviceSurfaceSupportKHR(phy_device, i, surface, &present_support);
+
if(present_support) {
- ret |= QUEUE_FAMILY_PRESENT_FAMILY;
- if(queue_family != NULL){
- queue_family->present_family = i;
- }
+ queue_family->present_family = i;
+ queue_family->has_present_family = true;
}
}
free(properties);
- return ret;
+ return 0;
}
-static int is_device_suitable(VkPhysicalDevice phy_device, VkSurfaceKHR surface)
+static bool device_is_suitable(VkPhysicalDevice phy_device, VkSurfaceKHR surface)
{
- if(find_queue_families(phy_device, surface, NULL) == QUEUE_FAMILY_ALL) {
- return 1;
+ struct queue_family_idx indices;
+ struct swap_chain_support_details details;
+
+ return
+ (device_queue_families(phy_device, surface, &indices),
+ indices.has_graphics_family && indices.has_present_family)
+ &&
+ (device_has_extension_support(phy_device))
+ &&
+ (swap_chain_support(phy_device, surface, &details),
+ swap_chain_free_support_details(&details),
+ (details.nformats > 0) && (details.npresent_modes > 0));
+}
+
+static bool device_has_extension_support(VkPhysicalDevice phy_device)
+{
+ u32 count = 0;
+ vkEnumerateDeviceExtensionProperties(phy_device, NULL, &count, NULL);
+
+ VkExtensionProperties *properties = xcalloc(count, sizeof(VkExtensionProperties));
+ vkEnumerateDeviceExtensionProperties(phy_device, NULL, &count, properties);
+
+ for(size_t i = 0; i < ARR_SIZE(device_extensions); i++)
+ {
+ bool present = false;
+ for(u32 j = 0; j < count; j++)
+ if(strncmp(device_extensions[i], properties[j].extensionName, 256) == 0) {
+ present = true;
+ }
+
+ if(!present) {
+ free(properties);
+ return false;
+ }
}
+
+ free(properties);
+ return true;
+}
+
+static int swap_chain_support(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct swap_chain_support_details *details)
+{
+ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phy_device, surface, &details->capabilities);
+
+ vkGetPhysicalDeviceSurfaceFormatsKHR(phy_device, surface, &details->nformats, NULL);
+ if(details->nformats > 0) {
+ details->formats = xcalloc(details->nformats, sizeof(*details->formats));
+ vkGetPhysicalDeviceSurfaceFormatsKHR(phy_device, surface, &details->nformats, details->formats);
+ }
+
+ vkGetPhysicalDeviceSurfacePresentModesKHR(phy_device, surface, &details->npresent_modes, NULL);
+ if(details->npresent_modes > 0) {
+ details->present_modes = xcalloc(details->npresent_modes, sizeof(*details->present_modes));
+ vkGetPhysicalDeviceSurfacePresentModesKHR(phy_device, surface, &details->npresent_modes, details->present_modes);
+ }
+
+ return 0;
+}
+
+static void swap_chain_free_support_details(struct swap_chain_support_details *details)
+{
+ if(details->nformats > 0) free(details->formats);
+ if(details->npresent_modes > 0) free(details->present_modes);
+}
+
+static int swap_chain_choose_format(VkSurfaceFormatKHR* formats, u32 nformats, VkSurfaceFormatKHR *format)
+{
+ for(u32 i = 0; i < nformats; i++)
+ if(formats[i].format == VK_FORMAT_B8G8R8A8_SRGB &&
+ formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
+ *format = formats[i];
+ return 0;
+ }
+ *format = formats[0];
return 0;
}
+static int swap_chain_choose_present_mode(VkPresentModeKHR *modes, u32 nmodes, VkPresentModeKHR *mode)
+{
+ for(u32 i = 0; i < nmodes; i++)
+ if(modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
+ *mode = modes[i];
+ return 0;
+ }
+
+ *mode = VK_PRESENT_MODE_FIFO_KHR;
+ return 0;
+}
+
+static int swap_chain_get_extent(VkSurfaceCapabilitiesKHR capabilities, VkExtent2D *extent)
+{
+ if(capabilities.currentExtent.width != UINT32_MAX) {
+ *extent = capabilities.currentExtent;
+ return 0;
+ }
+
+ // TODO implement
+ err("Not Implemented");
+ return 1;
+}
#ifdef DEBUG
+static bool instance_has_validation_layers(const char * const *layers, u32 nlayers)
+{
+ (void)layers;
+ (void)nlayers;
+
+ // u32 navaliable = 0;
+ // vkEnumerateInstanceLayerProperties(&navaliable, NULL);
+
+ // VkLayerProperties *available_layers = xcalloc(navaliable, sizeof(VkLayerProperties));
+ // vkEnumerateInstanceLayerProperties(&navaliable, available_layers);
+ return true;
+}
+
static int create_debug_messenger(device_t device, struct device_info *info)
{
(void)info;
VkDebugUtilsMessengerCreateInfoEXT cinfo = {0};
- populate_debug_messenger_info(&cinfo);
+ debug_messenger_populate_info(&cinfo);
if(CreateDebugUtilsMessengerEXT(device->instance, &cinfo, NULL, &device->debug_messenger) != VK_SUCCESS) {
info("CreateDebugUtilMessengerEXT: failed");
@@ -344,7 +546,7 @@ static int create_debug_messenger(device_t device, struct device_info *info)
return 0;
}
-static void populate_debug_messenger_info(VkDebugUtilsMessengerCreateInfoEXT *info)
+static void debug_messenger_populate_info(VkDebugUtilsMessengerCreateInfoEXT *info)
{
info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
info->messageSeverity =
@@ -355,23 +557,10 @@ static void populate_debug_messenger_info(VkDebugUtilsMessengerCreateInfoEXT *in
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
- info->pfnUserCallback = debug_callback;
-}
-
-static int has_validation_layer_support(const char * const *layers, uint32_t nlayers)
-{
- (void)layers;
- (void)nlayers;
-
- // uint32_t navaliable = 0;
- // vkEnumerateInstanceLayerProperties(&navaliable, NULL);
-
- // VkLayerProperties *available_layers = xcalloc(navaliable, sizeof(VkLayerProperties));
- // vkEnumerateInstanceLayerProperties(&navaliable, available_layers);
- return 1;
+ info->pfnUserCallback = debug_messenger_callback;
}
-static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(
+static VKAPI_ATTR VkBool32 VKAPI_CALL debug_messenger_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,