Gears-C/src/render_vulkan.c

1410 lines
41 KiB
C

/**
* BACK END API
*/
// TODO(MA): Make separate functions for debug/non debug builds for readability
b32 _InitRenderer(Arena *arena)
{
Assert(InitVulkan(arena), "InitVkLib failure");
return true;
}
void _DestroyRenderer()
{
DestroyVulkan();
}
static u32 GetFrameIndex()
{
return renderer.frame_state.frame_cnt % renderer.vk.sc.img_count;
}
static VkCommandBuffer GetFrameCmdBuf()
{
return renderer.vk.frame.buffers[GetFrameIndex()];
}
static VkFence *GetFrameRenderFence()
{
return &renderer.vk.frame.render_fences[GetFrameIndex()];
}
static VkSemaphore GetFrameRenderSem()
{
return renderer.vk.frame.render_sems[GetFrameIndex()];
}
static VkSemaphore GetFrameSwapSem()
{
return renderer.vk.frame.swapchain_sems[GetFrameIndex()];
}
b32 _BeginFrame()
{
b32 success = true;
VkResult result;
VkDevice device = renderer.vk.device;
VkSwapchainKHR swapchain = renderer.vk.swapchain;
VkCommandBuffer cmd = GetFrameCmdBuf();
VkFence *fence = GetFrameRenderFence();
VkSemaphore sc_sem = GetFrameSwapSem();
VkSemaphore rndr_sem = GetFrameRenderSem();
// TODO(MA): make this work with VK_PRESENT_MODE_MAILBOX_KHR and remove assignment of present mode to FIFO
result = vkWaitForFences(device, 1, fence, VK_TRUE, 1000000000);
if (result != VK_SUCCESS)
{
Printf("vkWaitForFences failure: %s", VkResultStr(result));
success = false;
}
if (success)
{
result = vkResetFences(device, 1, fence);
if (result != VK_SUCCESS)
{
Printf("vkResetFences failure: %s", VkResultStr(result));
success = false;
}
}
if (success)
{
result = vkAcquireNextImageKHR(device, swapchain, 1000000000, sc_sem, 0, &renderer.frame_state.img_ix);
if (result == VK_ERROR_OUT_OF_DATE_KHR)
ResizeSwapchain();
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
{
Printf("vkAcquireNextImageKHR failure: %s", VkResultStr(result));
success = false;
}
}
if (success)
{
result = vkResetCommandBuffer(cmd, 0);
if (result != VK_SUCCESS)
{
Printf("vkResetCommandBuffer failure: %s", VkResultStr(result));
success = false;
}
}
if (success)
{
VkCommandBufferBeginInfo cmd_info = {
.sType = STYPE(COMMAND_BUFFER_BEGIN_INFO),
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
};
result = vkBeginCommandBuffer(cmd, &cmd_info);
if (result != VK_SUCCESS)
{
Printf("vkBeginCommandBuffer failure: %s", VkResultStr(result));
success = false;
}
}
if (success)
{
TransitionImage(cmd, &renderer.vk.sc.draw_img, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
TransitionImage(cmd, &renderer.vk.sc.depth_img, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
VkRenderingAttachmentInfo col_attach_info = {
.sType = STYPE(RENDERING_ATTACHMENT_INFO),
.imageView = renderer.vk.sc.draw_img.view,
.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
};
VkRenderingAttachmentInfo depth_attach_info = {
.sType = STYPE(RENDERING_ATTACHMENT_INFO),
.imageView = renderer.vk.sc.depth_img.view,
.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
};
VkRenderingInfo render_info = {
.sType = STYPE(RENDERING_INFO),
.layerCount = 1,
.colorAttachmentCount = 1,
.pColorAttachments = &col_attach_info,
.pDepthAttachment = &depth_attach_info,
.renderArea = {
.extent = {
.width = renderer.vk.sc.extent.width,
.height = renderer.vk.sc.extent.height,
},
},
};
vkCmdBeginRendering(cmd, &render_info);
}
return success;
}
void _ClearScreen()
{
}
void _DrawTriangle()
{
VkCommandBuffer cmd = GetFrameCmdBuf();
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer.vk.pipe.pipelines[PIPELINE_CUBE]);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer.vk.pipe.pipeline_layout, 0, DESC_TYPE_MAX, renderer.vk.pipe.sets, 0, NULL);
VkViewport viewport = {
.width = (f32)renderer.vk.sc.extent.width,
.height = (f32)renderer.vk.sc.extent.height,
.maxDepth = 1.0,
};
vkCmdSetViewport(cmd, 0, 1, &viewport);
VkRect2D scissor = {
.extent = {
.width = renderer.vk.sc.extent.width,
.height = renderer.vk.sc.extent.height,
},
};
vkCmdSetScissor(cmd, 0, 1, &scissor);
vkCmdDraw(cmd, 3, 1, 0, 0);
// TODO(MA): maybe store current image layout between functions
}
b32 _FinishFrame()
{
b32 success = true;
VkResult result;
VkCommandBuffer cmd = GetFrameCmdBuf();
VkSemaphore sc_sem = GetFrameSwapSem();
VkSemaphore rndr_sem = GetFrameRenderSem();
VkFence *fence = GetFrameRenderFence();
VkImage curr_img = renderer.vk.sc.imgs[renderer.frame_state.img_ix];
vkCmdEndRendering(cmd);
TransitionImage(cmd, &renderer.vk.sc.draw_img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
TransitionImageLayout(cmd, curr_img, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkExtent2D extent = {
.width = renderer.vk.sc.extent.width,
.height = renderer.vk.sc.extent.height,
};
CopyImageToImage(cmd, renderer.vk.sc.draw_img.img, curr_img, extent, extent);
TransitionImageLayout(cmd, curr_img, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
result = vkEndCommandBuffer(cmd);
if (result != VK_SUCCESS)
{
Printf("vkEndCommandBuffer failure: %s", VkResultStr(result));
success = false;
}
if (success)
{
VkCommandBufferSubmitInfo cmd_info = {
.sType = STYPE(COMMAND_BUFFER_SUBMIT_INFO),
.commandBuffer = cmd,
};
VkSemaphoreSubmitInfo wait_info = {
.sType = STYPE(SEMAPHORE_SUBMIT_INFO),
.semaphore = sc_sem,
.stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
.value = 1,
};
VkSemaphoreSubmitInfo signal_info = {
.sType = STYPE(SEMAPHORE_SUBMIT_INFO),
.semaphore = rndr_sem,
.stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT,
.value = 1,
};
VkSubmitInfo2 submit_info = {
.sType = STYPE(SUBMIT_INFO_2),
.waitSemaphoreInfoCount = 1,
.pWaitSemaphoreInfos = &wait_info,
.signalSemaphoreInfoCount = 1,
.pSignalSemaphoreInfos = &signal_info,
.commandBufferInfoCount = 1,
.pCommandBufferInfos = &cmd_info,
};
result = vkQueueSubmit2(renderer.vk.queues.graphics_queue, 1, &submit_info, *fence);
if (result != VK_SUCCESS)
{
Printf("vkQueueSubmit2 failure: %s", VkResultStr(result));
success = false;
}
}
if (success)
{
VkPresentInfoKHR present_info = {
.sType = STYPE(PRESENT_INFO_KHR),
.pSwapchains = &renderer.vk.swapchain,
.swapchainCount = 1,
.pWaitSemaphores = &rndr_sem,
.waitSemaphoreCount = 1,
.pImageIndices = &renderer.frame_state.img_ix,
};
result = vkQueuePresentKHR(renderer.vk.queues.graphics_queue, &present_info);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || renderer.resize_requested)
{
renderer.resize_requested = false;
ResizeSwapchain();
}
else if (result != VK_SUCCESS)
{
Printf("vkQueuePresentKHR failure: %s", VkResultStr(result));
success = false;
}
}
renderer.frame_state.frame_cnt++;
return success;
}
static void _SetRenderResolution(u32 x, u32 y)
{
renderer.vk.sc.extent.width = x;
renderer.vk.sc.extent.height = y;
renderer.resize_requested = true;
}
/**
* BACK END API END
*/
/**
* INTERNAL API
*/
// Swapchain
static void ResizeSwapchain()
{
vkDeviceWaitIdle(renderer.vk.device);
DestroySwapchain();
DestroyDrawImages();
Assert(CreateSwapchain(), "Unable to recreate swapchain");
Assert(CreateDrawImages(), "Unable to recreate draw images");
renderer.resize_requested = false;
}
// UTIL
static void CopyImageToImage(VkCommandBuffer cmd, VkImage src, VkImage dst, VkExtent2D src_ext, VkExtent2D dst_ext)
{
VkImageBlit2 blit = {
.sType = STYPE(IMAGE_BLIT_2),
.srcOffsets = {
{},
{ .x = (i32)src_ext.width, .y = (i32)src_ext.height, .z = 1 },
},
.dstOffsets = {
{},
{ .x = (i32)dst_ext.width, .y = (i32)dst_ext.height, .z = 1 },
},
.srcSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseArrayLayer = 0,
.layerCount = 1,
.mipLevel = 0,
},
.dstSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseArrayLayer = 0,
.layerCount = 1,
.mipLevel = 0,
},
};
VkBlitImageInfo2 blit_info = {
.sType = STYPE(BLIT_IMAGE_INFO_2),
.srcImage = src,
.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.dstImage = dst,
.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.filter = VK_FILTER_LINEAR,
.regionCount = 1,
.pRegions = &blit,
};
vkCmdBlitImage2(cmd, &blit_info);
}
static void TransitionImageLayout(VkCommandBuffer cmd, VkImage img, VkImageLayout curr, VkImageLayout new)
{
VkImageMemoryBarrier2 barrier = {
.sType = STYPE(IMAGE_MEMORY_BARRIER_2),
.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT,
.oldLayout = curr,
.newLayout = new,
.image = img,
.subresourceRange = {
.aspectMask = new == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
VkDependencyInfo dep_info = {
.sType = STYPE(DEPENDENCY_INFO),
.imageMemoryBarrierCount = 1,
.pImageMemoryBarriers = &barrier,
};
vkCmdPipelineBarrier2(cmd, &dep_info);
}
static void TransitionImage(VkCommandBuffer cmd, Image *img, VkImageLayout new)
{
TransitionImageLayout(cmd, img->img, img->curr_layout, new);
img->curr_layout = new;
}
// INIT
static b32 InitVulkan(Arena *arena)
{
Assert(arena != NULL, "Vulkan memory is null");
renderer.perm_arena = arena;
void *mem = ArenaAlloc(arena, MB(4));
renderer.arena = CreateArena(mem, MB(4));
Assert(InitVkGlobalFunctions(), "Unable to load vulkan functions");
{
VkResult result = vkCreateInstance(&inst_info, NULL, &renderer.vk.inst);
if (result != VK_SUCCESS)
{
Printfln("vkCreateInstance failure: %s", VkResultStr(result));
assert(false && "Failed to initialize instance");
}
}
Assert(InitVkInstanceFunctions(), "Unable to initialize instance functions");
#ifdef BUILD_DEBUG
{
Assert(VLayersSupported(), "DEBUG_BUILD ERROR: Validation layers are not supported");
Assert(vkCreateDebugUtilsMessengerEXT(renderer.vk.inst, &debug_msg_info, NULL, &renderer.vk.debug) == VK_SUCCESS,
"Unable to initialize debug messenger");
}
#endif
Assert(CreateSurface(), "Unable to create surface");
Assert(CreateDevice(), "Unable to create device");
Assert(CreateVmaAllocator(), "Unable to create VMA allocator");
Assert(CreateSwapchain(), "Unable to initialize swapchain and draw images");
Assert(CreateDrawImages(), "Unable to create draw images");
Assert(CreateFrameStructures(), "Unable to create frame structures");
Assert(CreateImmediateStructures(), "Unable to create immediate structures");
Assert(CreateDescriptors(), "Unable to initialize descriptors.");
Assert(CreatePipelines(), "Unable to initialize pipelines.");
ArenaFree(renderer.arena);
return true;
}
static b32 CreateVmaAllocator()
{
VmaVulkanFunctions vk_functions = {
.vkGetInstanceProcAddr = vkGetInstanceProcAddr,
.vkGetDeviceProcAddr = vkGetDeviceProcAddr,
};
vma_create_info.pVulkanFunctions = &vk_functions;
vma_create_info.physicalDevice = renderer.vk.phys_device;
vma_create_info.device = renderer.vk.device;
vma_create_info.instance = renderer.vk.inst;
VkResult result = vmaCreateAllocator(&vma_create_info, &renderer.vk.alloc);
if (result != VK_SUCCESS)
{
Printf("vmaCreateAllocator failure: %d", result);
}
return result == VK_SUCCESS;
}
static b32 CheckQueueSurfaceSupport(i32 index, VkPhysicalDevice device, VkSurfaceKHR surface)
{
b32 surface_supported;
vkGetPhysicalDeviceSurfaceSupportKHR(device, (u32)index, surface, &surface_supported);
return surface_supported;
}
static DeviceQueues CheckDeviceQueueSupport(VkPhysicalDevice device, VkSurfaceKHR surface)
{
DeviceQueues queues = { .graphics = -1, .transfer = -1 };
u32 queue_count;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_count, NULL);
VkQueueFamilyProperties *families = ArenaAlloc(renderer.arena, sizeof(VkQueueFamilyProperties) * queue_count);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_count, families);
for (i32 i = 0; i < queue_count; i++)
{
if (i == 0 && CheckQueueSurfaceSupport(i, device, surface))
{
queues.graphics = i;
continue;
}
if (BitEq(families[i].queueFlags, VK_QUEUE_TRANSFER_BIT))
queues.transfer = i;
}
if (queues.transfer < 0)
queues.transfer = queues.graphics;
return queues;
}
static b32 CheckDevicePropertiesSupport(VkPhysicalDevice device, VkSurfaceKHR surface, b32 *discrete)
{
b32 success = false;
VkPhysicalDeviceProperties properties = {};
vkGetPhysicalDeviceProperties(device, &properties);
if (VK_API_VERSION_MINOR(properties.apiVersion) >= 3)
{
u32 ext_count;
vkEnumerateDeviceExtensionProperties(device, NULL, &ext_count, NULL);
VkExtensionProperties *ext_properties = ArenaAlloc(renderer.arena, sizeof(VkExtensionProperties) * ext_count);
vkEnumerateDeviceExtensionProperties(device, NULL, &ext_count, ext_properties);
i32 matched = 0;
for (u32 i = 0; i < ext_count; i++) {
for (i32 j = 0; j < Len(device_extensions); j++) {
if (StrEq(ext_properties[i].extensionName, device_extensions[j])) {
matched++;
break;
}
}
}
if (matched == Len(device_extensions))
{
u32 fmt_count, present_count;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &fmt_count, NULL);
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_count, NULL);
*discrete = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
success = fmt_count && present_count;
}
}
return success;
}
static b32 CheckDeviceFeatureSupport(VkPhysicalDevice device)
{
VkPhysicalDeviceFeatures2 features2 = { .sType = STYPE(PHYSICAL_DEVICE_FEATURES_2) };
VkPhysicalDeviceVulkan12Features features_12 = { .sType = STYPE(PHYSICAL_DEVICE_VULKAN_1_2_FEATURES) };
VkPhysicalDeviceVulkan13Features features_13 = { .sType = STYPE(PHYSICAL_DEVICE_VULKAN_1_3_FEATURES) };
features2.pNext = &features_12;
vkGetPhysicalDeviceFeatures2(device, &features2);
features2.pNext = &features_13;
vkGetPhysicalDeviceFeatures2(device, &features2);
VkPhysicalDeviceFeatures features = features2.features;
b32 result = true;
result &= (b32)features.shaderUniformBufferArrayDynamicIndexing;
result &= (b32)features.shaderSampledImageArrayDynamicIndexing;
result &= (b32)features.shaderStorageBufferArrayDynamicIndexing;
result &= (b32)features.shaderStorageImageArrayDynamicIndexing;
result &= (b32)features_12.descriptorIndexing;
result &= (b32)features_12.bufferDeviceAddress;
result &= (b32)features_13.synchronization2;
result &= (b32)features_13.dynamicRendering;
return result;
}
static b32 CreateDevice()
{
VkInstance inst = renderer.vk.inst;
VkSurfaceKHR surface = renderer.vk.surface;
u32 device_count;
vkEnumeratePhysicalDevices(inst, &device_count, NULL);
VkPhysicalDevice *devices = ArenaAlloc(renderer.arena, sizeof(VkPhysicalDevice) * device_count);
vkEnumeratePhysicalDevices(inst, &device_count, devices);
b32 discrete_device = false;
DeviceQueues *queues = &renderer.vk.queues;
VkPhysicalDevice *phys_device = &renderer.vk.phys_device;
for (u32 i = 0; i < device_count; i++) {
DeviceQueues current_queues = CheckDeviceQueueSupport(devices[i], surface);
b32 discrete = false;
if (current_queues.graphics < 0)
continue;
if (!CheckDevicePropertiesSupport(devices[i], surface, &discrete))
continue;
if (discrete_device && !discrete)
continue;
if (!CheckDeviceFeatureSupport(devices[i]))
continue;
discrete_device = discrete;
*queues = current_queues;
*phys_device = devices[i];
if (discrete_device && queues->graphics != queues->transfer)
break;
}
b32 success = false;
if (phys_device != NULL)
{
VkDeviceQueueCreateInfo queue_info[2] = {};
f32 priority = 1.0f;
u32 count = 1;
queue_info[0].sType = STYPE(DEVICE_QUEUE_CREATE_INFO);
queue_info[0].queueFamilyIndex = queues->graphics;
queue_info[0].queueCount = 1;
queue_info[0].pQueuePriorities = &priority;
queue_info[0].flags = 0;
if (queues->graphics != queues->transfer) {
queue_info[1].sType = STYPE(DEVICE_QUEUE_CREATE_INFO);
queue_info[1].queueFamilyIndex = queues->transfer;
queue_info[1].queueCount = 1;
queue_info[1].pQueuePriorities = &priority;
queue_info[1].flags = 0;
count++;
}
device_info.queueCreateInfoCount = count;
device_info.pQueueCreateInfos = &queue_info[0];
VkResult result = vkCreateDevice(renderer.vk.phys_device, &device_info, NULL, &renderer.vk.device);
if (result != VK_SUCCESS) {
Printf("vkCreateDevice failure: %d", result);
}
else
{
Assert(InitVkDeviceFunctions(), "Failed to initialize device functions");
vkGetDeviceQueue(renderer.vk.device, queues->graphics, 0, &queues->graphics_queue);
vkGetDeviceQueue(renderer.vk.device, queues->transfer, 0, &queues->transfer_queue);
success = true;
}
}
return success;
}
static b32 InitVkGlobalFunctions()
{
b32 result = LoadVulkanLib();
if (result)
{
INIT_FN(vkGetInstanceProcAddr);
INIT_FN(vkEnumerateInstanceLayerProperties);
INIT_FN(vkCreateInstance);
}
return result;
}
static b32 InitVkInstanceFunctions()
{
VkInstance instance = renderer.vk.inst;
#ifdef __linux__
{
INIT_INST_FN(vkCreateXcbSurfaceKHR);
}
#endif
#ifdef BUILD_DEBUG
{
INIT_INST_FN(vkCreateDebugUtilsMessengerEXT);
INIT_INST_FN(vkDestroyDebugUtilsMessengerEXT);
}
#endif
INIT_INST_FN(vkEnumeratePhysicalDevices);
INIT_INST_FN(vkGetPhysicalDeviceQueueFamilyProperties);
INIT_INST_FN(vkGetPhysicalDeviceSurfaceSupportKHR);
INIT_INST_FN(vkCreateDevice);
INIT_INST_FN(vkGetPhysicalDeviceProperties);
INIT_INST_FN(vkGetPhysicalDeviceFeatures2);
INIT_INST_FN(vkGetPhysicalDeviceSurfaceFormatsKHR);
INIT_INST_FN(vkGetPhysicalDeviceSurfacePresentModesKHR);
INIT_INST_FN(vkEnumerateDeviceExtensionProperties);
INIT_INST_FN(vkGetDeviceProcAddr);
INIT_INST_FN(vkDestroyInstance);
INIT_INST_FN(vkDestroySurfaceKHR);
INIT_INST_FN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
INIT_INST_FN(vkGetPhysicalDeviceImageFormatProperties);
return true;
}
static b32 InitVkDeviceFunctions() {
VkDevice device = renderer.vk.device;
INIT_DEV_FN(vkCreateSwapchainKHR);
INIT_DEV_FN(vkCreateImage);
INIT_DEV_FN(vkCreateImageView);
INIT_DEV_FN(vkGetSwapchainImagesKHR);
INIT_DEV_FN(vkGetDeviceQueue);
INIT_DEV_FN(vkCreateSemaphore);
INIT_DEV_FN(vkAllocateCommandBuffers);
INIT_DEV_FN(vkCreateCommandPool);
INIT_DEV_FN(vkCreateFence);
INIT_DEV_FN(vkCreateDescriptorPool);
INIT_DEV_FN(vkCreateDescriptorSetLayout);
INIT_DEV_FN(vkAllocateDescriptorSets);
INIT_DEV_FN(vkCreatePipelineLayout);
INIT_DEV_FN(vkResetDescriptorPool);
INIT_DEV_FN(vkCreateShaderModule);
INIT_DEV_FN(vkCreateGraphicsPipelines);
INIT_DEV_FN(vkCreateComputePipelines);
INIT_DEV_FN(vkUpdateDescriptorSets);
INIT_DEV_FN(vkDestroyDevice);
INIT_DEV_FN(vkDestroyDescriptorPool);
INIT_DEV_FN(vkDestroySwapchainKHR);
INIT_DEV_FN(vkDestroyImage);
INIT_DEV_FN(vkDestroyImageView);
INIT_DEV_FN(vkDestroyCommandPool);
INIT_DEV_FN(vkDestroySemaphore);
INIT_DEV_FN(vkDestroyFence);
INIT_DEV_FN(vkDestroyPipelineLayout);
INIT_DEV_FN(vkDestroyPipeline);
INIT_DEV_FN(vkWaitForFences);
INIT_DEV_FN(vkBeginCommandBuffer);
INIT_DEV_FN(vkEndCommandBuffer);
INIT_DEV_FN(vkAcquireNextImageKHR);
INIT_DEV_FN(vkCmdBindPipeline);
INIT_DEV_FN(vkCmdBindDescriptorSets);
INIT_DEV_FN(vkCmdDispatch);
INIT_DEV_FN(vkCmdBeginRendering);
INIT_DEV_FN(vkCmdEndRendering);
INIT_DEV_FN(vkCmdSetViewport);
INIT_DEV_FN(vkCmdSetScissor);
INIT_DEV_FN(vkCmdPushConstants);
INIT_DEV_FN(vkCmdBindIndexBuffer);
INIT_DEV_FN(vkCmdDrawIndexed);
INIT_DEV_FN(vkCmdBlitImage2);
INIT_DEV_FN(vkCmdPipelineBarrier2);
INIT_DEV_FN(vkCmdCopyBufferToImage);
INIT_DEV_FN(vkCmdCopyBuffer);
INIT_DEV_FN(vkQueueSubmit2);
INIT_DEV_FN(vkResetFences);
INIT_DEV_FN(vkResetCommandBuffer);
INIT_DEV_FN(vkFreeCommandBuffers);
INIT_DEV_FN(vkDestroyDescriptorSetLayout);
INIT_DEV_FN(vkDestroyShaderModule);
INIT_DEV_FN(vkQueuePresentKHR);
INIT_DEV_FN(vkCmdDraw);
INIT_DEV_FN(vkDeviceWaitIdle);
return true;
}
// TODO(MA): implement other platforms
#ifdef __linux__
static b32 CreateSurface()
{
GameWindow *window = GetWindowPtr();
VkXcbSurfaceCreateInfoKHR surface_info = {
.sType = STYPE(XCB_SURFACE_CREATE_INFO_KHR),
.connection = window->connection,
.window = window->window
};
VkResult result = vkCreateXcbSurfaceKHR(renderer.vk.inst, &surface_info, NULL, &renderer.vk.surface);
if (result != VK_SUCCESS) {
Printf("Unable to create surface: %d", result);
}
return result == VK_SUCCESS;
}
#elif _WIN32
static b32 CreateSurface()
{
Window *window = GetWindowPtr();
VkWin32SurfaceCreateInfoKHR surface_info = {
.sType = STYPE(WIN_32_SURFACE_CREATE_INFO_KHR),
.hinstance =
};
}
#endif
static b32 LoadVulkanLib()
{
Library *lib = &renderer.vk.lib;
b32 lib_found; Function fn;
for (i32 i = 0; i < Len(vulkan_libs); i++) {
lib_found = LoadLib(vulkan_libs[i], lib);
if (lib_found) {
lib_found = LoadFn("vkGetInstanceProcAddr", lib, &fn);
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)fn.fn;
break;
}
}
return lib_found;
}
static b32 VLayersSupported()
{
b32 success;
u32 count;
vkEnumerateInstanceLayerProperties(&count, NULL);
Assert(count, "VLayersSupported(): vkEnumerateInstanceLayerProperties returned a count of 0");
VkLayerProperties *layers = ArenaAlloc(renderer.arena, sizeof(VkLayerProperties) * count);
vkEnumerateInstanceLayerProperties(&count, layers);
for (u32 i = 0; i < count; i++) {
if (StrEq(layers[i].layerName, _VK_VALIDATION)) {
success = true;
break;
}
}
return success;
}
static b32 CreateFrameStructures()
{
b32 success = true;
FrameStructures *data = &renderer.vk.frame;
u32 img_count = renderer.vk.sc.img_count;
pool_create_info.queueFamilyIndex = renderer.vk.queues.graphics;
renderer.vk.frame.pools = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandPool) * img_count);
renderer.vk.frame.buffers = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandBuffer) * img_count);
renderer.vk.frame.swapchain_sems = ArenaAlloc(renderer.perm_arena, sizeof(VkSemaphore) * img_count);
renderer.vk.frame.render_sems = ArenaAlloc(renderer.perm_arena, sizeof(VkSemaphore) * img_count);
renderer.vk.frame.render_fences = ArenaAlloc(renderer.perm_arena, sizeof(VkFence) * img_count);
for (u32 i = 0; i < renderer.vk.sc.img_count; i++)
{
VkResult result;
VkDevice device = renderer.vk.device;
result = vkCreateCommandPool(device, &pool_create_info, NULL, &data->pools[i]);
if (result != VK_SUCCESS)
success = false;
cmd_buf_info.commandPool = data->pools[i];
result = vkAllocateCommandBuffers(device, &cmd_buf_info, &data->buffers[i]);
if (result != VK_SUCCESS)
success = false;
result = vkCreateFence(device, &fence_create_info, NULL, &data->render_fences[i]);
if (result != VK_SUCCESS)
success = false;
result = vkCreateSemaphore(device, &semaphore_create_info, NULL, &data->render_sems[i]);
if (result != VK_SUCCESS)
success = false;
result = vkCreateSemaphore(device, &semaphore_create_info, NULL, &data->swapchain_sems[i]);
if (result != VK_SUCCESS)
success = false;
}
return success;
}
static b32 CreateImmediateStructures()
{
b32 success = true;
VkResult result;
VkDevice device = renderer.vk.device;
ImmediateStructures *imm = &renderer.vk.imm;
pool_create_info.queueFamilyIndex = renderer.vk.queues.transfer;
result = vkCreateCommandPool(device, &pool_create_info, NULL, &imm->pool);
if (result != VK_SUCCESS)
success = false;
cmd_buf_info.commandPool = imm->pool;
result = vkAllocateCommandBuffers(device, &cmd_buf_info, &imm->buffer);
if (result != VK_SUCCESS)
success = false;
result = vkCreateFence(device, &fence_create_info, NULL, &imm->fence);
if (result != VK_SUCCESS)
success = false;
return success;
}
static b32 CreateSwapchain()
{
b32 success = true;
VkPhysicalDevice phys_device = renderer.vk.phys_device;
VkDevice device = renderer.vk.device;
VkSurfaceKHR surface = renderer.vk.surface;
VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_device, surface, &capabilities);
// Maybe reconsider handling window sizing within here and only handle it from events themselves
// causes issues when the window size is out of sync with the current swapchain
VkExtent2D extent;
u32 width = renderer.vk.sc.extent.width;
u32 height = renderer.vk.sc.extent.height;
extent.width = u32Clamp((u32)width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = u32Clamp((u32)height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
u32 format_count;
vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, NULL);
VkSurfaceFormatKHR *formats = ArenaAlloc(renderer.arena, sizeof(VkSurfaceFormatKHR) * format_count);
vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, formats);
renderer.vk.sc.format = formats[0].format;
renderer.vk.sc.color_space = formats[0].colorSpace;
u32 present_count;
vkGetPhysicalDeviceSurfacePresentModesKHR(phys_device, surface, &present_count, NULL);
VkPresentModeKHR *present_modes = ArenaAlloc(renderer.arena, sizeof(VkSurfaceFormatKHR) * present_count);
vkGetPhysicalDeviceSurfacePresentModesKHR(phys_device, surface, &present_count, present_modes);
VkPresentModeKHR present_mode;
for (u32 i = 0; i < present_count; i++)
{
if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
{
present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
break;
}
}
if (present_mode != VK_PRESENT_MODE_MAILBOX_KHR)
present_mode = VK_PRESENT_MODE_FIFO_KHR;
swapchain_create_info.minImageCount = capabilities.minImageCount + 1;
swapchain_create_info.surface = surface;
swapchain_create_info.imageFormat = renderer.vk.sc.format;
swapchain_create_info.imageColorSpace = renderer.vk.sc.color_space;
swapchain_create_info.imageExtent = extent;
swapchain_create_info.preTransform = capabilities.currentTransform;
swapchain_create_info.presentMode = present_mode;
VkResult result;
result = vkCreateSwapchainKHR(device, &swapchain_create_info, NULL, &renderer.vk.swapchain);
if (result != VK_SUCCESS)
success = false;
u32 image_count;
vkGetSwapchainImagesKHR(device, renderer.vk.swapchain, &image_count, NULL);
VkImage *sc_images = ArenaAlloc(renderer.perm_arena, sizeof(VkImage) * image_count);
VkImageView *sc_views = ArenaAlloc(renderer.perm_arena, sizeof(VkImageView) * image_count);
vkGetSwapchainImagesKHR(device, renderer.vk.swapchain, &image_count, sc_images);
for (u32 i = 0; i < image_count; i++)
{
sc_image_view_create_info.image = sc_images[i];
sc_image_view_create_info.format = renderer.vk.sc.format;
result = vkCreateImageView(device, &sc_image_view_create_info, NULL, &sc_views[i]);
if (result != VK_SUCCESS)
success = false;
}
renderer.vk.sc.imgs = sc_images;
renderer.vk.sc.views = sc_views;
renderer.vk.sc.img_count = image_count;
renderer.vk.sc.extent.width = extent.width;
renderer.vk.sc.extent.height = extent.height;
renderer.vk.sc.extent.depth = 1;
return success;
}
static b32 CreateDrawImages()
{
b32 success = true;
VkResult result;
VkFormat image_format = GetImageFormat();
VkExtent3D extent = renderer.vk.sc.extent;
VkDevice device = renderer.vk.device;
VmaAllocationCreateInfo alloc_create_info = {
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
};
// Draw Image
draw_image_create_info.format = image_format;
draw_image_create_info.extent = extent;
result = vmaCreateImage(renderer.vk.alloc, &draw_image_create_info,
&alloc_create_info, &renderer.vk.sc.draw_img.img, &renderer.vk.sc.draw_img.alloc, NULL);
if (result != VK_SUCCESS)
success = false;
// Draw Image View
draw_image_view_create_info.image = renderer.vk.sc.draw_img.img;
draw_image_view_create_info.format = image_format;
result = vkCreateImageView(device, &draw_image_view_create_info, NULL, &renderer.vk.sc.draw_img.view);
if (result != VK_SUCCESS)
success = false;
// Depth Image
depth_image_create_info.extent = extent;
result = vmaCreateImage(renderer.vk.alloc, &depth_image_create_info,
&alloc_create_info, &renderer.vk.sc.depth_img.img, &renderer.vk.sc.depth_img.alloc, NULL);
if (result != VK_SUCCESS)
success = false;
// Depth Image View
depth_image_view_create_info.image = renderer.vk.sc.depth_img.img;
result = vkCreateImageView(device, &depth_image_view_create_info, NULL, &renderer.vk.sc.depth_img.view);
if (result != VK_SUCCESS)
success = false;
// Setting values
renderer.vk.sc.extent = extent;
renderer.vk.sc.depth_img.fmt = depth_image_create_info.format;
renderer.vk.sc.depth_img.curr_layout = VK_IMAGE_LAYOUT_UNDEFINED;
renderer.vk.sc.draw_img.fmt = draw_image_create_info.format;
renderer.vk.sc.draw_img.curr_layout = VK_IMAGE_LAYOUT_UNDEFINED;
return success;
}
static VkFormat GetImageFormat()
{
VkPhysicalDevice phys_device = renderer.vk.phys_device;
VkImageType image_type = VK_IMAGE_TYPE_2D;
VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
VkImageUsageFlags usage_flags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
VkFormat format = 0;
for (i32 i = 0; i < Len(VK_IMAGE_FORMATS); i++)
{
VkImageFormatProperties properties;
VkResult result;
result = vkGetPhysicalDeviceImageFormatProperties(phys_device, VK_IMAGE_FORMATS[i], image_type,
tiling, usage_flags, 0, &properties);
if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
continue;
if (result == VK_SUCCESS)
{
format = VK_IMAGE_FORMATS[i];
break;
}
}
Assert(format != 0, "[Error] unable to find appropriate image format");
return format;
}
static b32 CreateDescriptors()
{
b32 success = true;
VkDevice device = renderer.vk.device;
VkResult result;
result = vkCreateDescriptorPool(device, &desc_pool_info, NULL, &renderer.vk.pipe.pool);
if (result != VK_SUCCESS)
success = false;
result = vkCreateDescriptorSetLayout(device, &shared_layout_create_info, NULL, &renderer.vk.pipe.layouts[DESC_TYPE_SHARED]);
if (result != VK_SUCCESS)
success = false;
for (u32 i = DESC_TYPE_COMBINED_SAMPLER; i < DESC_TYPE_MAX; i++)
{
bindless_layout_binding.descriptorType = desc_type_map[i];
result = vkCreateDescriptorSetLayout(device, &bindless_layout_create_info, NULL, &renderer.vk.pipe.layouts[i]);
if (result != VK_SUCCESS)
success = false;
}
set_allocate_info.descriptorPool = renderer.vk.pipe.pool;
set_allocate_info.pSetLayouts = renderer.vk.pipe.layouts;
result = vkAllocateDescriptorSets(device, &set_allocate_info, renderer.vk.pipe.sets);
if (result != VK_SUCCESS)
success = false;
pipeline_layout_create_info.setLayoutCount = DESC_TYPE_MAX;
pipeline_layout_create_info.pSetLayouts = renderer.vk.pipe.layouts;
result = vkCreatePipelineLayout(device, &pipeline_layout_create_info, NULL, &renderer.vk.pipe.pipeline_layout);
if (result != VK_SUCCESS)
success = false;
return success;
}
static b32 CreatePipelines()
{
b32 success = true;
VkResult result;
VkDevice device = renderer.vk.device;
VkShaderModule cube_vert, cube_frag;
success &= CreateShaderModule(shader_quad_vert, shader_quad_vert_len, &cube_vert);
success &= CreateShaderModule(shader_quad_frag, shader_quad_frag_len, &cube_frag);
VkPipelineShaderStageCreateInfo cube_shader_stages[] = {
{
.sType = STYPE(PIPELINE_SHADER_STAGE_CREATE_INFO),
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = cube_vert,
.pName = "main",
},
{
.sType = STYPE(PIPELINE_SHADER_STAGE_CREATE_INFO),
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = cube_frag,
.pName = "main",
},
};
VkPipelineRenderingCreateInfo pipeline_render_info = {
.sType = STYPE(PIPELINE_RENDERING_CREATE_INFO),
.colorAttachmentCount = 1,
.pColorAttachmentFormats = &renderer.vk.sc.draw_img.fmt,
.depthAttachmentFormat = renderer.vk.sc.depth_img.fmt,
};
cube_create_info.pStages = cube_shader_stages;
cube_create_info.stageCount = Len(cube_shader_stages);
cube_create_info.layout = renderer.vk.pipe.pipeline_layout;
cube_create_info.pNext = &pipeline_render_info;
result = vkCreateGraphicsPipelines(device, 0, 1, &cube_create_info, NULL, &renderer.vk.pipe.pipelines[PIPELINE_CUBE]);
if (result != VK_SUCCESS)
{
Printf("vkCreateGraphicsPipelines failure: %s", VkResultStr(result));
success = false;
}
vkDestroyShaderModule(device, cube_vert, NULL);
vkDestroyShaderModule(device, cube_frag, NULL);
return success;
}
static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module)
{
VkResult result;
b32 success = true;
VkShaderModuleCreateInfo module_info = {
.sType = STYPE(SHADER_MODULE_CREATE_INFO),
.codeSize = len,
.pCode = (u32 *)bytes,
};
result = vkCreateShaderModule(renderer.vk.device, &module_info, NULL, module);
if (result != VK_SUCCESS)
{
Printf("vkCreateShaderModule failure: %s", VkResultStr(result));
success = false;
}
return success;
}
static void DestroySwapchain()
{
for (u32 i = 0; i < renderer.vk.sc.img_count; i++)
{
vkDestroyImageView(renderer.vk.device, renderer.vk.sc.views[i], NULL);
}
vkDestroySwapchainKHR(renderer.vk.device, renderer.vk.swapchain, NULL);
}
static void DestroyDrawImages()
{
SwapchainStructures *sc = &renderer.vk.sc;
VkDevice device = renderer.vk.device;
VmaAllocator vma_alloc = renderer.vk.alloc;
vkDestroyImageView(device, sc->draw_img.view, NULL);
vmaDestroyImage(vma_alloc, sc->draw_img.img, sc->draw_img.alloc);
vkDestroyImageView(device, sc->depth_img.view, NULL);
vmaDestroyImage(vma_alloc, sc->depth_img.img, sc->depth_img.alloc);
}
static void DestroyVulkan()
{
VkDevice device = renderer.vk.device;
VkInstance instance = renderer.vk.inst;
FrameStructures data = renderer.vk.frame;
ImmediateStructures imm = renderer.vk.imm;
SwapchainStructures sc = renderer.vk.sc;
VmaAllocator vma_alloc = renderer.vk.alloc;
VkSwapchainKHR swapchain = renderer.vk.swapchain;
PipelineStructures pipe = renderer.vk.pipe;
vkDeviceWaitIdle(device);
for (u32 i = PIPELINE_CUBE; i < PIPELINE_MAX; i++)
vkDestroyPipeline(device, pipe.pipelines[i], NULL);
vkDestroyPipelineLayout(device, pipe.pipeline_layout, NULL);
for (u32 i = DESC_TYPE_SHARED; i < DESC_TYPE_MAX; i++)
vkDestroyDescriptorSetLayout(device, pipe.layouts[i], NULL);
vkDestroyDescriptorPool(device, pipe.pool, NULL);
DestroyDrawImages();
DestroySwapchain();
vkDestroyFence(device, imm.fence, NULL);
vkFreeCommandBuffers(device, imm.pool, 1, &imm.buffer);
vkDestroyCommandPool(device, imm.pool, NULL);
for (u32 i = 0; i < sc.img_count; i++)
{
vkDestroySemaphore(device, data.render_sems[i], NULL);
vkDestroySemaphore(device, data.swapchain_sems[i], NULL);
vkDestroyFence(device, data.render_fences[i], NULL);
vkFreeCommandBuffers(device, data.pools[i], 1, &data.buffers[i]);
vkDestroyCommandPool(device, data.pools[i], NULL);
}
vmaDestroyAllocator(renderer.vk.alloc);
vkDestroyDevice(renderer.vk.device, NULL);
vkDestroySurfaceKHR(renderer.vk.inst, renderer.vk.surface, NULL);
#ifdef BUILD_DEBUG
{
vkDestroyDebugUtilsMessengerEXT(renderer.vk.inst, renderer.vk.debug, NULL);
}
#endif
vkDestroyInstance(renderer.vk.inst, NULL);
}
const char *VkResultStr(VkResult result)
{
switch (result)
{
case VK_SUCCESS:
return "VK_SUCCESS";
case VK_NOT_READY:
return "VK_NOT_READY";
case VK_TIMEOUT:
return "VK_TIMEOUT";
case VK_EVENT_SET:
return "VK_EVENT_SET";
case VK_EVENT_RESET:
return "VK_EVENT_RESET";
case VK_INCOMPLETE:
return "VK_INCOMPLETE";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "VK_ERROR_OUT_OF_HOST_MEMORY";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
case VK_ERROR_INITIALIZATION_FAILED:
return "VK_ERROR_INITIALIZATION_FAILED";
case VK_ERROR_DEVICE_LOST:
return "VK_ERROR_DEVICE_LOST";
case VK_ERROR_MEMORY_MAP_FAILED:
return "VK_ERROR_MEMORY_MAP_FAILED";
case VK_ERROR_LAYER_NOT_PRESENT:
return "VK_ERROR_LAYER_NOT_PRESENT";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "VK_ERROR_EXTENSION_NOT_PRESENT";
case VK_ERROR_FEATURE_NOT_PRESENT:
return "VK_ERROR_FEATURE_NOT_PRESENT";
case VK_ERROR_INCOMPATIBLE_DRIVER:
return "VK_ERROR_INCOMPATIBLE_DRIVER";
case VK_ERROR_TOO_MANY_OBJECTS:
return "VK_ERROR_TOO_MANY_OBJECTS";
case VK_ERROR_FORMAT_NOT_SUPPORTED:
return "VK_ERROR_FORMAT_NOT_SUPPORTED";
case VK_ERROR_FRAGMENTED_POOL:
return "VK_ERROR_FRAGMENTED_POOL";
case VK_ERROR_UNKNOWN:
return "VK_ERROR_UNKNOWN";
case VK_ERROR_OUT_OF_POOL_MEMORY:
return "VK_ERROR_OUT_OF_POOL_MEMORY";
case VK_ERROR_INVALID_EXTERNAL_HANDLE:
return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
case VK_ERROR_FRAGMENTATION:
return "VK_ERROR_FRAGMENTATION";
case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS:
return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS";
case VK_PIPELINE_COMPILE_REQUIRED:
return "VK_PIPELINE_COMPILE_REQUIRED";
case VK_ERROR_SURFACE_LOST_KHR:
return "VK_ERROR_SURFACE_LOST_KHR";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
case VK_SUBOPTIMAL_KHR:
return "VK_SUBOPTIMAL_KHR";
case VK_ERROR_OUT_OF_DATE_KHR:
return "VK_ERROR_OUT_OF_DATE_KHR";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
case VK_ERROR_VALIDATION_FAILED_EXT:
return "VK_ERROR_VALIDATION_FAILED_EXT";
case VK_ERROR_INVALID_SHADER_NV:
return "VK_ERROR_INVALID_SHADER_NV";
#ifdef VK_ENABLE_BETA_EXTENSIONS
case VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR:
return "VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR";
#endif
#ifdef VK_ENABLE_BETA_EXTENSIONS
case VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR:
return "VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR";
#endif
#ifdef VK_ENABLE_BETA_EXTENSIONS
case VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR:
return "VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR";
#endif
#ifdef VK_ENABLE_BETA_EXTENSIONS
case VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR:
return "VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR";
#endif
#ifdef VK_ENABLE_BETA_EXTENSIONS
case VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR:
return "VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR";
#endif
#ifdef VK_ENABLE_BETA_EXTENSIONS
case VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR:
return "VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR";
#endif
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
case VK_ERROR_NOT_PERMITTED_KHR:
return "VK_ERROR_NOT_PERMITTED_KHR";
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
case VK_THREAD_IDLE_KHR:
return "VK_THREAD_IDLE_KHR";
case VK_THREAD_DONE_KHR:
return "VK_THREAD_DONE_KHR";
case VK_OPERATION_DEFERRED_KHR:
return "VK_OPERATION_DEFERRED_KHR";
case VK_OPERATION_NOT_DEFERRED_KHR:
return "VK_OPERATION_NOT_DEFERRED_KHR";
case VK_ERROR_COMPRESSION_EXHAUSTED_EXT:
return "VK_ERROR_COMPRESSION_EXHAUSTED_EXT";
case VK_RESULT_MAX_ENUM:
return "VK_RESULT_MAX_ENUM";
default:
return "??????";
}
}
static VkBool32 DebugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
VkDebugUtilsMessageTypeFlagsEXT message_type,
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
void *pUserData
) {
char *ms, *mt;
switch (message_severity) {
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
ms = (char *)"VERBOSE";
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
ms = (char *)"INFO";
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
ms = (char *)"WARNING";
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
ms = (char *)"ERROR";
break;
default:
ms = (char *)"UNKNOWN";
break;
}
switch (message_type) {
case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
mt = (char *)"General";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT:
mt = (char *)"Validation";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
mt = (char *)"Validation | General";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
mt = (char *)"Performance";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
mt = (char *)"General | Performance";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
mt = (char *)"Validation | Performance";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
mt = (char *)"General | Validation | Performance";
break;
default:
mt = (char *)"Unknown";
break;
}
Printf("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage);
return VK_FALSE;
}