summaryrefslogtreecommitdiff
path: root/src/graphics.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphics.c')
-rw-r--r--src/graphics.c1146
1 files changed, 1146 insertions, 0 deletions
diff --git a/src/graphics.c b/src/graphics.c
new file mode 100644
index 0000000..8da9c43
--- /dev/null
+++ b/src/graphics.c
@@ -0,0 +1,1146 @@
+#include <string.h>
+#include <errno.h>
+#include <vulkan/vulkan.h>
+
+#include "graphics.h"
+#include "common.h"
+
+// TODO: add more error checking
+// TODO: add log output
+// TODO: check for memory leaks
+
+#define SWAP_CHAIN_IMAGES 3
+
+#define CLAMP(val, min, max) (((val) < (min)) ? (min) : ((val) > (max) ? (max) : (val)))
+
+#define ECHECK(f, ...) if(f(__VA_ARGS__) != 0) { err(#f ": failed"); goto exit; }
+#define FCHECK(f, ...) if(f(__VA_ARGS__) != 0) { err(#f ": failed"); goto fail; }
+
+#define VCHECK(f, ...) \
+ do { \
+ VkResult res; \
+ if((res = f(__VA_ARGS__)) != VK_SUCCESS) { \
+ err(#f ": %s", str_VkResult(res)); \
+ goto exit; } \
+ } while(0)
+
+#ifdef DEBUG
+char *validation_layers[] = {
+ "VK_LAYER_KHRONOS_validation"
+};
+#endif
+
+char *device_extensions[] = {
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME
+};
+
+struct queue_family_idx {
+ 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)
+
+// -- Major Functions ---
+static int create_instance(graphics_t graphics, struct graphics_info *info);
+static int create_surface(graphics_t graphics, struct graphics_info *info);
+static int create_physical_device(graphics_t graphics, struct graphics_info *info);
+static int create_logical_device(graphics_t graphics, struct graphics_info *info);
+static int create_pipeline(graphics_t graphics, struct graphics_info *info);
+static int create_swap_chain(graphics_t graphics, struct graphics_info *info);
+static int create_command_pool(graphics_t graphics, struct graphics_info *info);
+static int create_sync_objects(graphics_t graphics, struct graphics_info *info);
+
+static void destroy_swap_chain(graphics_t graphics);
+static void destroy_pipeline(graphics_t graphics);
+// static void destroy_command_pool(graphics_t graphics);
+static void destroy_sync_objects(graphics_t graphics);
+
+// --- Helper Functions ---
+static char *str_VkResult(VkResult result);
+
+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);
+
+#define PPLN graphics->pipeline
+static int pipeline_load_shader_module(VkDevice device, char *path, VkShaderModule *module);
+
+#define SWCH graphics->swap_chain
+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);
+
+#define CMND graphics->command
+static int command_buffer_record(graphics_t graphics, u32 image_index);
+
+#define SYNC graphics->sync
+
+F_LOAD_FILE_ALIGNED(u32) // from config.h
+
+// --- Debug Functions ---
+#ifdef DEBUG
+static bool instance_has_validation_layers(const char * const *layers, u32 nlayers);
+
+static int create_debug_messenger(graphics_t graphics, struct graphics_info* 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,
+ const VkAllocationCallbacks* pAllocator,
+ VkDebugUtilsMessengerEXT* pDebugMessenger);
+void DestroyDebugUtilsMessengerEXT(
+ VkInstance instance,
+ VkDebugUtilsMessengerEXT debugMessenger,
+ const VkAllocationCallbacks* pAllocator);
+#endif
+
+#define CCHECK(f) FCHECK(f, graphics, info)
+
+graphics_t graphics_create(struct graphics_info *info)
+{
+ graphics_t graphics = xmalloc(sizeof(struct graphics));
+ graphics->instance = VK_NULL_HANDLE;
+ graphics->logical_device = VK_NULL_HANDLE;
+
+
+ PPLN.pipeline = VK_NULL_HANDLE;
+ PPLN.layout = VK_NULL_HANDLE;
+ PPLN.render_pass = VK_NULL_HANDLE;
+
+ SWCH.swap_chain = VK_NULL_HANDLE;
+ SWCH.nimages = 0;
+
+ CMND.pool = VK_NULL_HANDLE;
+
+ SYNC.semph_image_available = VK_NULL_HANDLE;
+ SYNC.semph_render_finished = VK_NULL_HANDLE;
+ SYNC.fence_inflight = VK_NULL_HANDLE;
+
+ CCHECK(create_instance);
+ CCHECK(create_surface);
+#ifdef DEBUG
+ CCHECK(create_debug_messenger);
+#endif
+ CCHECK(create_physical_device);
+ CCHECK(create_logical_device);
+ CCHECK(create_pipeline);
+ CCHECK(create_swap_chain);
+ CCHECK(create_command_pool);
+ CCHECK(create_sync_objects);
+
+ return graphics;
+fail:
+ graphics_destroy(graphics);
+ return NULL;
+}
+
+void graphics_destroy(graphics_t graphics)
+{
+ if(!graphics) return;
+
+ vkDeviceWaitIdle(graphics->logical_device);
+
+ destroy_sync_objects(graphics);
+
+ vkDestroyCommandPool(graphics->logical_device, CMND.pool, NULL);
+
+ destroy_swap_chain(graphics);
+ destroy_pipeline(graphics);
+
+ vkDestroyDevice(graphics->logical_device, NULL);
+
+ #ifdef DEBUG
+ DestroyDebugUtilsMessengerEXT(graphics->instance, graphics->debug_messenger, NULL);
+ #endif
+
+ vkDestroySurfaceKHR(graphics->instance, graphics->surface, NULL);
+ vkDestroyInstance(graphics->instance, NULL);
+
+ free(graphics);
+}
+
+int graphics_draw_frame(graphics_t graphics)
+{
+ int ret = 1;
+
+ // wait for the previous frame to finish
+ vkWaitForFences(graphics->logical_device, 1, &SYNC.fence_inflight, VK_TRUE, UINT64_MAX);
+
+ // aquire the next image the form the swap chain
+ u32 image_index;
+ VkResult res = vkAcquireNextImageKHR(graphics->logical_device, SWCH.swap_chain, UINT64_MAX, SYNC.semph_image_available, VK_NULL_HANDLE, &image_index);
+
+ // recreate the swap chain on resize
+ if(res == VK_ERROR_OUT_OF_DATE_KHR) {
+ destroy_swap_chain(graphics);
+ create_swap_chain(graphics, NULL);
+
+ ret = 0; goto exit;
+ }
+
+ vkResetFences(graphics->logical_device, 1, &SYNC.fence_inflight);
+
+ // reset the command buffer
+ vkResetCommandBuffer(CMND.buffer, 0);
+ command_buffer_record(graphics, image_index);
+
+ // prepare the queue submit info
+ VkSubmitInfo submit_info = {0};
+ submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+
+ VkSemaphore wait_semaphs[] = { SYNC.semph_image_available };
+ VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
+ submit_info.waitSemaphoreCount = ARR_SIZE(wait_semaphs);
+ submit_info.pWaitSemaphores = wait_semaphs;
+ submit_info.pWaitDstStageMask = wait_stages;
+
+ submit_info.commandBufferCount = 1;
+ submit_info.pCommandBuffers = &CMND.buffer;
+
+ VkSemaphore signal_semphs[] = { SYNC.semph_image_available };
+ submit_info.signalSemaphoreCount = ARR_SIZE(signal_semphs);
+ submit_info.pSignalSemaphores = signal_semphs;
+
+ // submit the graphics work
+ VCHECK(vkQueueSubmit, graphics->graphics_queue, 1, &submit_info, SYNC.fence_inflight);
+
+ // prepare the graphics info
+ VkPresentInfoKHR present_info = {0};
+ present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+
+ present_info.waitSemaphoreCount = ARR_SIZE(signal_semphs);
+ present_info.pWaitSemaphores = signal_semphs;
+
+ VkSwapchainKHR swap_chains[] = { SWCH.swap_chain };
+ present_info.swapchainCount = ARR_SIZE(swap_chains);
+ present_info.pSwapchains = swap_chains;
+ present_info.pImageIndices = &image_index;
+ present_info.pResults = NULL; // Optional
+
+
+ vkQueuePresentKHR(graphics->present_queue, &present_info);
+
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+static int create_instance(graphics_t graphics, struct graphics_info *info)
+{
+ int ret = 1;
+
+ VkApplicationInfo app_info = {0};
+ app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ app_info.pEngineName = "Engine";
+ app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
+ app_info.apiVersion = VK_API_VERSION_1_0;
+
+ app_info.pApplicationName = info->name;
+ app_info.applicationVersion = info->version;
+
+ VkInstanceCreateInfo create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ create_info.pApplicationInfo = &app_info;
+
+ create_info.enabledLayerCount = 0;
+
+#ifdef DEBUG
+ // add debug utils extensions for debug callback
+ char **extensions = xcalloc(info->ext_count+1, sizeof(*extensions));
+ extensions[info->ext_count] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
+
+ for(u32 i = 0; i < info->ext_count; i++) {
+ extensions[i] = (char *)info->extensions[i];
+ }
+
+ create_info.enabledExtensionCount = info->ext_count+1;
+ create_info.ppEnabledExtensionNames = (const char * const *)extensions;
+
+ // validation layer support
+ u32 nlayers = ARR_SIZE(validation_layers);
+
+ if(!instance_has_validation_layers((const char * const *)validation_layers, nlayers)) {
+ err("validation_layer_support: failed");
+ goto exit;
+ }
+
+ create_info.ppEnabledLayerNames = (const char * const *)validation_layers;
+ create_info.enabledLayerCount = nlayers;
+
+ // add the debug messenger for instance creation and destruction
+ VkDebugUtilsMessengerCreateInfoEXT msg_info = {0};
+ debug_messenger_populate_info(&msg_info);
+
+ create_info.pNext = &msg_info;
+#else
+ create_info.enabledExtensionCount = info->ext_count;
+ create_info.ppEnabledExtensionNames = (const char * const *)info->extensions;
+
+ create_info.enabledLayerCount = 0;
+#endif
+
+ VCHECK(vkCreateInstance, &create_info, NULL, &graphics->instance);
+
+ ret = 0;
+exit:
+#ifdef DEBUG
+ free(extensions);
+#endif
+ return ret;
+}
+
+static int create_surface(graphics_t graphics, struct graphics_info *info)
+{
+ if(info->surface_func(graphics->instance, &graphics->surface)) {
+ err("Couldn't create a VkSurfaceKHR");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int create_physical_device(graphics_t graphics, struct graphics_info *info)
+{
+ (void)info;
+ int ret = 1;
+
+ graphics->physical_device = VK_NULL_HANDLE;
+
+ u32 dev_count = 0;
+ vkEnumeratePhysicalDevices(graphics->instance, &dev_count, NULL);
+
+ if(dev_count == 0) {
+ err("No physical devices could be found!");
+ goto exit;
+ }
+
+ VkPhysicalDevice *devices = xcalloc(dev_count, sizeof(*devices));
+ vkEnumeratePhysicalDevices(graphics->instance, &dev_count, devices);
+
+ for(u32 i = 0; i < dev_count; i++) {
+ if(device_is_suitable(devices[i], graphics->surface)) {
+ graphics->physical_device = devices[i];
+ break;
+ }
+ }
+
+ free(devices);
+
+ if(graphics->physical_device == VK_NULL_HANDLE) {
+ err("No suitable physical device could be found");
+ goto exit;
+ }
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+static int create_logical_device(graphics_t graphics, struct graphics_info *info)
+{
+ (void)info;
+ int ret = 1;
+
+ // queue family data
+ struct queue_family_idx indices = {0};
+ device_queue_families(graphics->physical_device, graphics->surface, &indices);
+
+ // queue infos
+ u32 unique_queue_family_count = 0;
+ u32 queue_indices[] = {
+ indices.graphics_family, indices.present_family,
+ };
+
+ VkDeviceQueueCreateInfo queue_infos[ARR_SIZE(queue_indices)] = {0};
+
+ float queue_priority = 1.0f;
+ // basically get only the unique queue families
+ for(size_t i = 0; i < ARR_SIZE(queue_indices); i++)
+ {
+ bool unique = true;
+ for(size_t j = 0; j < i; j++) {
+ if(queue_indices[i] == queue_indices[j]) {
+ unique = false;
+ break;
+ }
+ }
+
+ if(!unique) continue;
+
+ queue_infos[unique_queue_family_count].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ queue_infos[unique_queue_family_count].queueFamilyIndex = queue_indices[i];
+ queue_infos[unique_queue_family_count].queueCount = 1;
+ queue_infos[unique_queue_family_count].pQueuePriorities = &queue_priority;
+
+ unique_queue_family_count++;
+ }
+
+ // device features
+ VkPhysicalDeviceFeatures device_features = {0};
+
+ // logical device create info
+ VkDeviceCreateInfo create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+
+ create_info.pQueueCreateInfos = queue_infos;
+ create_info.queueCreateInfoCount = unique_queue_family_count;
+
+ create_info.pEnabledFeatures = &device_features;
+
+ 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
+ // so i wont bother adding them
+ create_info.enabledLayerCount = 0;
+
+ VCHECK(vkCreateDevice, graphics->physical_device, &create_info, NULL, &graphics->logical_device);
+
+ vkGetDeviceQueue(graphics->logical_device, indices.graphics_family, 0, &graphics->graphics_queue);
+ vkGetDeviceQueue(graphics->logical_device, indices.present_family, 0, &graphics->present_queue);
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+static int create_swap_chain(graphics_t graphics, struct graphics_info *info)
+{
+ (void)info;
+ int ret = 1;
+
+ struct swap_chain_support_details details;
+ swap_chain_support(graphics->physical_device, graphics->surface, &details);
+
+ VkSurfaceFormatKHR surface_format;
+ VkPresentModeKHR present_mode;
+ VkExtent2D extent;
+ u32 image_count = SWAP_CHAIN_IMAGES;
+
+ 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 = graphics->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 = {0};
+ device_queue_families(graphics->physical_device, graphics->surface, &indices);
+
+ u32 queue_indices[] = { 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 = ARR_SIZE(queue_indices);
+ 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;
+
+ VCHECK(vkCreateSwapchainKHR, graphics->logical_device, &create_info, NULL, &SWCH.swap_chain);
+
+ // Get the Images
+ SWCH.image_format = surface_format.format;
+ SWCH.extent = extent;
+
+ vkGetSwapchainImagesKHR(graphics->logical_device, SWCH.swap_chain, &SWCH.nimages, NULL);
+
+ SWCH.images = xcalloc(SWCH.nimages, sizeof(*SWCH.images));
+ SWCH.image_views = xcalloc(SWCH.nimages, sizeof(SWCH.image_views));
+ SWCH.framebuffers = xcalloc(SWCH.nimages, sizeof(*SWCH.framebuffers));
+
+ vkGetSwapchainImagesKHR(graphics->logical_device, SWCH.swap_chain, &SWCH.nimages, SWCH.images);
+
+ for(u32 i = 0; i < SWCH.nimages; i++)
+ {
+ VkImageViewCreateInfo create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ create_info.image = SWCH.images[i];
+
+ create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ create_info.format = surface_format.format;
+
+ create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+
+ create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ create_info.subresourceRange.baseMipLevel = 0;
+ create_info.subresourceRange.levelCount = 1;
+ create_info.subresourceRange.baseArrayLayer = 0;
+ create_info.subresourceRange.layerCount = 1;
+
+ VCHECK(vkCreateImageView, graphics->logical_device, &create_info, NULL, &SWCH.image_views[i]);
+ }
+
+ for(u32 i = 0; i < SWCH.nimages; i++)
+ {
+ VkImageView attachments[] = {
+ SWCH.image_views[i]
+ };
+
+ VkFramebufferCreateInfo framebuffer_info = {0};
+ framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ framebuffer_info.renderPass = PPLN.render_pass;
+ framebuffer_info.attachmentCount = 1;
+ framebuffer_info.pAttachments = attachments;
+ framebuffer_info.width = SWCH.extent.width;
+ framebuffer_info.height = SWCH.extent.height;
+ framebuffer_info.layers = 1;
+
+ VCHECK(vkCreateFramebuffer, graphics->logical_device, &framebuffer_info, NULL, &SWCH.framebuffers[i]);
+ }
+
+ ret = 0;
+exit:
+ swap_chain_free_support_details(&details);
+ return ret;
+}
+
+static void destroy_swap_chain(graphics_t graphics)
+{
+ for(u32 i = 0; i < SWCH.nimages; i++) {
+ vkDestroyImageView(graphics->logical_device, SWCH.image_views[i], NULL);
+ vkDestroyFramebuffer(graphics->logical_device, SWCH.framebuffers[i], NULL);
+ }
+
+ if(SWCH.nimages != 0) {
+ free(SWCH.images);
+ free(SWCH.image_views);
+ free(SWCH.framebuffers);
+ }
+
+ vkDestroySwapchainKHR(graphics->logical_device, SWCH.swap_chain, NULL);
+}
+
+static int create_pipeline(graphics_t graphics, struct graphics_info *info)
+{
+ (void)info;
+ int ret = 1;
+
+ // Shader Things
+ VkShaderModule vert_shader = VK_NULL_HANDLE;
+ VkShaderModule frag_shader = VK_NULL_HANDLE;
+
+ pipeline_load_shader_module(graphics->logical_device, "shaders/shader1.vert.spv", &vert_shader);
+ pipeline_load_shader_module(graphics->logical_device, "shaders/shader1.frag.spv", &frag_shader);
+
+ VkPipelineShaderStageCreateInfo vert_stage = {0};
+ vert_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ vert_stage.stage = VK_SHADER_STAGE_VERTEX_BIT;
+ vert_stage.module = vert_shader;
+ vert_stage.pName = "main";
+
+ VkPipelineShaderStageCreateInfo frag_stage = {0};
+ frag_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ frag_stage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ frag_stage.module = frag_shader;
+ frag_stage.pName = "main";
+
+ VkPipelineShaderStageCreateInfo shader_stages[] = { vert_stage, frag_stage };
+
+ VkDynamicState dynamic_states[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
+
+ // A Bunch of other things for the pipeline
+ VkPipelineDynamicStateCreateInfo dynamic_state = {0};
+ dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dynamic_state.dynamicStateCount = ARR_SIZE(dynamic_states);
+ dynamic_state.pDynamicStates = dynamic_states;
+
+ // vertex things - hard coded (for now)
+ VkPipelineVertexInputStateCreateInfo vertex_input = {0};
+ vertex_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertex_input.vertexBindingDescriptionCount = 0;
+ vertex_input.pVertexBindingDescriptions = NULL;
+ vertex_input.vertexAttributeDescriptionCount = 0;
+ vertex_input.pVertexAttributeDescriptions = NULL;
+
+ VkPipelineInputAssemblyStateCreateInfo input_assembly = {0};
+ input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ input_assembly.primitiveRestartEnable = VK_FALSE;
+
+ VkPipelineViewportStateCreateInfo viewport_state = {0};
+ viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewport_state.viewportCount = 1;
+ viewport_state.scissorCount = 1;
+
+ VkPipelineRasterizationStateCreateInfo rasterizer = {0};
+ rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rasterizer.depthClampEnable = VK_FALSE;
+ rasterizer.rasterizerDiscardEnable = VK_FALSE;
+ rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
+ rasterizer.lineWidth = 1.0f;
+ rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
+ rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
+
+ rasterizer.depthBiasEnable = VK_FALSE;
+ rasterizer.depthBiasConstantFactor = 0.0f; // Optional
+ rasterizer.depthBiasClamp = 0.0f; // Optional
+ rasterizer.depthBiasSlopeFactor = 0.0f; // Optional
+
+ VkPipelineMultisampleStateCreateInfo multisampling = {0};
+ multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ multisampling.sampleShadingEnable = VK_FALSE;
+ multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ multisampling.minSampleShading = 1.0f; // Optional
+ multisampling.pSampleMask = NULL; // Optional
+ multisampling.alphaToCoverageEnable = VK_FALSE; // Optional
+ multisampling.alphaToOneEnable = VK_FALSE; // Optional
+
+ VkPipelineColorBlendAttachmentState color_blend_attachment = {0};
+ color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+ color_blend_attachment.blendEnable = VK_FALSE;
+ color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
+ color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
+ color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; // Optional
+ color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
+ color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
+ color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
+
+ VkPipelineColorBlendStateCreateInfo color_blend = {0};
+ color_blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ color_blend.logicOpEnable = VK_FALSE;
+ color_blend.logicOp = VK_LOGIC_OP_COPY; // Optional
+ color_blend.attachmentCount = 1;
+ color_blend.pAttachments = &color_blend_attachment;
+ color_blend.blendConstants[0] = 0.0f; // Optional
+ color_blend.blendConstants[1] = 0.0f; // Optional
+ color_blend.blendConstants[2] = 0.0f; // Optional
+ color_blend.blendConstants[3] = 0.0f; // Optional
+
+ // Create Pipeline Layout
+ VkPipelineLayoutCreateInfo pipeline_layout_info = {0};
+ pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipeline_layout_info.setLayoutCount = 0; // Optional
+ pipeline_layout_info.pSetLayouts = NULL; // Optional
+ pipeline_layout_info.pushConstantRangeCount = 0; // Optional
+ pipeline_layout_info.pPushConstantRanges = NULL; // Optional
+
+ VCHECK(vkCreatePipelineLayout, graphics->logical_device, &pipeline_layout_info, NULL, &PPLN.layout);
+
+ // get the required format
+ // currently the only to do that
+ // TOOD: fix this
+ VkSurfaceFormatKHR surface_format;
+ struct swap_chain_support_details details;
+ swap_chain_support(graphics->physical_device, graphics->surface, &details);
+ swap_chain_choose_format(details.formats, details.nformats, &surface_format);
+ swap_chain_free_support_details(&details);
+
+ // Create Render Pass
+ VkAttachmentDescription color_attachment = {0};
+ color_attachment.format = surface_format.format;
+ color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+
+ VkAttachmentReference color_attachment_ref = {0};
+ color_attachment_ref.attachment = 0;
+ color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ VkSubpassDescription subpass = {0};
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &color_attachment_ref;
+
+ VkSubpassDependency dependency = {0};
+ dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
+ dependency.dstSubpass = 0;
+ dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.srcAccessMask = 0;
+ dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+ VkRenderPassCreateInfo render_pass_info = {0};
+ render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ render_pass_info.attachmentCount = 1;
+ render_pass_info.pAttachments = &color_attachment;
+ render_pass_info.subpassCount = 1;
+ render_pass_info.pSubpasses = &subpass;
+ render_pass_info.dependencyCount = 1;
+ render_pass_info.pDependencies = &dependency;
+
+ VCHECK(vkCreateRenderPass, graphics->logical_device, &render_pass_info, NULL, &PPLN.render_pass);
+
+ // Finally Create the Pipeline
+ VkGraphicsPipelineCreateInfo pipeline_info = {0};
+ pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ pipeline_info.stageCount = 2;
+ pipeline_info.pStages = shader_stages;
+
+ pipeline_info.pVertexInputState = &vertex_input;
+ pipeline_info.pInputAssemblyState = &input_assembly;
+ pipeline_info.pViewportState = &viewport_state;
+ pipeline_info.pRasterizationState = &rasterizer;
+ pipeline_info.pMultisampleState = &multisampling;
+ pipeline_info.pDepthStencilState = NULL;
+ pipeline_info.pColorBlendState = &color_blend;
+ pipeline_info.pDynamicState = &dynamic_state;
+
+ pipeline_info.layout = PPLN.layout;
+ pipeline_info.renderPass = PPLN.render_pass;
+ pipeline_info.subpass = 0;
+
+ pipeline_info.basePipelineHandle = VK_NULL_HANDLE; // Optional
+ pipeline_info.basePipelineIndex = -1; // Optional
+
+ VCHECK(vkCreateGraphicsPipelines, graphics->logical_device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &PPLN.pipeline);
+
+ ret = 0;
+exit:
+ vkDestroyShaderModule(graphics->logical_device, frag_shader, NULL);
+ vkDestroyShaderModule(graphics->logical_device, vert_shader, NULL);
+ return ret;
+}
+
+static void destroy_pipeline(graphics_t graphics)
+{
+ vkDestroyPipeline(graphics->logical_device, PPLN.pipeline, NULL);
+ vkDestroyPipelineLayout(graphics->logical_device, PPLN.layout, NULL);
+ vkDestroyRenderPass(graphics->logical_device, PPLN.render_pass, NULL);
+}
+
+static int create_command_pool(graphics_t graphics, struct graphics_info *info)
+{
+ (void)info;
+ int ret = 1;
+
+ struct queue_family_idx indices;
+ device_queue_families(graphics->physical_device, graphics->surface, &indices);
+
+ VkCommandPoolCreateInfo pool_info = {0};
+ pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+ pool_info.queueFamilyIndex = indices.graphics_family;
+
+ VCHECK(vkCreateCommandPool, graphics->logical_device, &pool_info, NULL, &CMND.pool);
+
+ // allocate the command buffer(s)
+ VkCommandBufferAllocateInfo allocate_info = {0};
+ allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ allocate_info.commandPool = CMND.pool;
+ allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ allocate_info.commandBufferCount = 1;
+
+ VCHECK(vkAllocateCommandBuffers, graphics->logical_device, &allocate_info, &CMND.buffer);
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+static int create_sync_objects(graphics_t graphics, struct graphics_info *info)
+{
+ (void)info;
+ int ret = 1;
+
+ VkSemaphoreCreateInfo semph_info = {0};
+ semph_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+
+ VkFenceCreateInfo fence_info = {0};
+ fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+
+ VCHECK(vkCreateSemaphore, graphics->logical_device, &semph_info, NULL, &SYNC.semph_image_available);
+ VCHECK(vkCreateSemaphore, graphics->logical_device, &semph_info, NULL, &SYNC.semph_render_finished);
+ VCHECK(vkCreateFence, graphics->logical_device, &fence_info, NULL, &SYNC.fence_inflight);
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+static void destroy_sync_objects(graphics_t graphics)
+{
+ vkDestroySemaphore(graphics->logical_device, SYNC.semph_image_available, NULL);
+ vkDestroySemaphore(graphics->logical_device, SYNC.semph_render_finished, NULL);
+ vkDestroyFence(graphics->logical_device, SYNC.fence_inflight, NULL);
+}
+
+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(*properties));
+ vkGetPhysicalDeviceQueueFamilyProperties(phy_device, &count, properties);
+
+ for(u32 i = 0; i < count; i++) {
+ if(properties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
+ queue_family->graphics_family = i;
+ queue_family->has_graphics_family = true;
+ }
+
+ VkBool32 present_support = false;
+ vkGetPhysicalDeviceSurfaceSupportKHR(phy_device, i, surface, &present_support);
+
+ if(present_support) {
+ queue_family->present_family = i;
+ queue_family->has_present_family = true;
+ }
+ }
+
+ free(properties);
+ return 0;
+}
+
+static bool device_is_suitable(VkPhysicalDevice phy_device, VkSurfaceKHR surface)
+{
+ 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)
+{
+ bool ret = false;
+
+ u32 count = 0;
+ vkEnumerateDeviceExtensionProperties(phy_device, NULL, &count, NULL);
+
+ VkExtensionProperties *properties = xcalloc(count, sizeof(*properties));
+ 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;
+ break;
+ }
+
+ if(!present) {
+ goto exit;
+ }
+ }
+
+ ret = true;
+exit:
+ free(properties);
+ return ret;
+}
+
+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;
+}
+
+static int pipeline_load_shader_module(VkDevice device, char *path, VkShaderModule *module)
+{
+ int ret = 1;
+
+ size_t size = 0;
+ u32 *buf = NULL;
+
+ ECHECK(load_file_u32_aligned, path, &size, NULL);
+ buf = xmalloc(size);
+ ECHECK(load_file_u32_aligned, path, &size, buf);
+
+ VkShaderModuleCreateInfo create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ create_info.codeSize = size;
+ create_info.pCode = buf;
+
+ VCHECK(vkCreateShaderModule, device, &create_info, NULL, module);
+
+ ret = 0;
+exit:
+ if(buf) free(buf);
+ return ret;
+}
+
+static int command_buffer_record(graphics_t graphics, u32 image_index)
+{
+ int ret = 1;
+
+ // Begin the buffer
+ VkCommandBufferBeginInfo begin_info = {0};
+ begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ begin_info.flags = 0; // Optional
+ begin_info.pInheritanceInfo = NULL; // Optional
+
+ VCHECK(vkBeginCommandBuffer, CMND.buffer, &begin_info);
+
+ // Begin the render pass
+ VkRenderPassBeginInfo render_pass_info = {0};
+ render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ render_pass_info.renderPass = PPLN.render_pass;
+ render_pass_info.framebuffer = SWCH.framebuffers[image_index];
+
+ render_pass_info.renderArea.offset = (VkOffset2D){0, 0};
+ render_pass_info.renderArea.extent = SWCH.extent;
+
+ VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
+ render_pass_info.clearValueCount = 1;
+ render_pass_info.pClearValues = &clear_color;
+
+ vkCmdBeginRenderPass(CMND.buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
+
+ // Begin the drawing commands
+ vkCmdBindPipeline(CMND.buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, PPLN.pipeline);
+
+ VkViewport viewport = {0};
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = (float)SWCH.extent.width;
+ viewport.height = (float)SWCH.extent.height;
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ vkCmdSetViewport(CMND.buffer, 0, 1, &viewport);
+
+ VkRect2D scissor = {0};
+ scissor.offset = (VkOffset2D){0, 0};
+ scissor.extent = SWCH.extent;
+ vkCmdSetScissor(CMND.buffer, 0, 1, &scissor);
+
+ // 3 vertices, 1 instance (for instanced rendering)
+ // 0 is the first vertex, 0 is the fist instance
+ vkCmdDraw(CMND.buffer, 3, 1, 0, 0);
+
+ // Cleaning up
+ vkCmdEndRenderPass(CMND.buffer);
+
+ VCHECK(vkEndCommandBuffer, CMND.buffer);
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+#define X_VK_RESULT_TABLE(X) \
+ X(VK_SUCCESS) \
+ X(VK_NOT_READY) \
+ X(VK_TIMEOUT) \
+ X(VK_EVENT_SET) \
+ X(VK_EVENT_RESET) \
+ X(VK_INCOMPLETE) \
+ X(VK_ERROR_OUT_OF_HOST_MEMORY) \
+ X(VK_ERROR_OUT_OF_DEVICE_MEMORY) \
+ X(VK_ERROR_INITIALIZATION_FAILED) \
+ X(VK_ERROR_DEVICE_LOST) \
+ X(VK_ERROR_MEMORY_MAP_FAILED) \
+ X(VK_ERROR_LAYER_NOT_PRESENT) \
+ X(VK_ERROR_EXTENSION_NOT_PRESENT) \
+ X(VK_ERROR_FEATURE_NOT_PRESENT) \
+ X(VK_ERROR_INCOMPATIBLE_DRIVER) \
+ X(VK_ERROR_TOO_MANY_OBJECTS) \
+ X(VK_ERROR_FORMAT_NOT_SUPPORTED) \
+ X(VK_ERROR_FRAGMENTED_POOL) \
+ X(VK_ERROR_UNKNOWN) \
+ X(VK_ERROR_OUT_OF_POOL_MEMORY) \
+ X(VK_ERROR_INVALID_EXTERNAL_HANDLE) \
+ X(VK_ERROR_FRAGMENTATION) \
+ X(VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS) \
+
+#define X_VK_RESULT_CASE(error) \
+ case error: return #error;
+
+static char *str_VkResult(VkResult result)
+{
+ switch(result) {
+ X_VK_RESULT_TABLE(X_VK_RESULT_CASE)
+ default:
+ return "VK_ERROR_OTHER";
+ }
+}
+
+#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(graphics_t graphics, struct graphics_info *info)
+{
+ (void)info;
+ int ret = 1;
+
+ VkDebugUtilsMessengerCreateInfoEXT cinfo = {0};
+ debug_messenger_populate_info(&cinfo);
+
+ VCHECK(CreateDebugUtilsMessengerEXT, graphics->instance, &cinfo, NULL, &graphics->debug_messenger);
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+static void debug_messenger_populate_info(VkDebugUtilsMessengerCreateInfoEXT *info)
+{
+ info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
+ info->messageSeverity =
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+ 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;
+ info->pfnUserCallback = debug_messenger_callback;
+}
+
+static VKAPI_ATTR VkBool32 VKAPI_CALL debug_messenger_callback(
+ VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
+ VkDebugUtilsMessageTypeFlagsEXT messageType,
+ const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
+ void* pUserData)
+{
+ (void)messageSeverity;
+ (void)messageType;
+ (void)pUserData;
+
+ warn("Validation Layer: %s", pCallbackData->pMessage);
+ return VK_FALSE;
+}
+
+VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) {
+ PFN_vkCreateDebugUtilsMessengerEXT f = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
+ if (f != NULL) {
+ return f(instance, pCreateInfo, pAllocator, pDebugMessenger);
+ } else {
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ }
+}
+
+void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) {
+ PFN_vkDestroyDebugUtilsMessengerEXT f = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
+ if (f != NULL) {
+ f(instance, debugMessenger, pAllocator);
+ }
+}
+
+#endif