1106 lines
38 KiB
C
1106 lines
38 KiB
C
#include "render.h"
|
|
#include "stdio.h"
|
|
#include "string.h"
|
|
#include "pipeline.h"
|
|
#include "vk_mem_alloc.h"
|
|
#include "vulkan/vulkan_core.h"
|
|
|
|
const uint32_t MAX_FRAMES_IN_FLIGHT = 2;
|
|
|
|
const char * validation_layers[] = {
|
|
"VK_LAYER_KHRONOS_validation",
|
|
//"VK_LAYER_LUNARG_api_dump",
|
|
"VK_LAYER_KHRONOS_synchronization2",
|
|
"VK_LAYER_KHRONOS_shader_object",
|
|
};
|
|
uint32_t validation_layer_count = sizeof(validation_layers) / sizeof(const char *);
|
|
|
|
const char * instance_extensions[] = {
|
|
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
|
|
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
|
|
VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
|
|
#ifdef __APPLE__
|
|
"VK_EXT_metal_surface",
|
|
#endif
|
|
VK_KHR_SURFACE_EXTENSION_NAME,
|
|
};
|
|
uint32_t instance_extension_count = sizeof(instance_extensions) / sizeof(const char *);
|
|
|
|
const char * device_extensions[] = {
|
|
#ifdef __APPLE__
|
|
"VK_KHR_portability_subset",
|
|
#endif
|
|
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
|
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
|
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
|
|
};
|
|
uint32_t device_extension_count = sizeof(device_extensions) / sizeof(const char *);
|
|
|
|
VkFormat depth_formats[] = {
|
|
VK_FORMAT_D32_SFLOAT,
|
|
VK_FORMAT_D32_SFLOAT_S8_UINT,
|
|
VK_FORMAT_D24_UNORM_S8_UINT
|
|
};
|
|
uint32_t depth_format_count = sizeof(depth_formats) / sizeof(VkFormat);
|
|
|
|
|
|
|
|
void glfw_error(int error, const char* description) {
|
|
fprintf(stderr, "GLFW_ERR: 0x%02x - %s\n", error, description);
|
|
}
|
|
|
|
GLFWwindow* init_window() {
|
|
glfwInit();
|
|
glfwSetErrorCallback(glfw_error);
|
|
|
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
|
GLFWwindow* window = glfwCreateWindow(800, 500, "roleplay", 0, 0);
|
|
|
|
return window;
|
|
}
|
|
|
|
bool check_validation_layers(const char ** layers, uint32_t num_layers) {
|
|
uint32_t layer_count;
|
|
VkResult result;
|
|
|
|
result = vkEnumerateInstanceLayerProperties(&layer_count, 0);
|
|
if(result != VK_SUCCESS) {
|
|
return false;
|
|
}
|
|
|
|
VkLayerProperties* available_layers = malloc(sizeof(VkLayerProperties)*layer_count);
|
|
result = vkEnumerateInstanceLayerProperties(&layer_count, available_layers);
|
|
|
|
|
|
for(uint32_t i = 0; i < num_layers; i++) {
|
|
bool found = false;
|
|
for(uint32_t j = 0; j < layer_count; j++) {
|
|
if(strcmp(layers[i], available_layers[j].layerName) == 0) {
|
|
found = true;
|
|
}
|
|
}
|
|
if(found == false) {
|
|
free(available_layers);
|
|
fprintf(stderr, "Failed to find layer %s\n", layers[i]);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
free(available_layers);
|
|
return true;
|
|
}
|
|
|
|
VkResult create_instance(VkInstance* instance) {
|
|
if(check_validation_layers(validation_layers, validation_layer_count) == false) {
|
|
return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
}
|
|
|
|
VkApplicationInfo app_info = {
|
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
.pApplicationName = "roleplay",
|
|
.applicationVersion = VK_MAKE_VERSION(0, 0, 1),
|
|
.pEngineName = "roleplay",
|
|
.engineVersion = VK_MAKE_VERSION(0, 0, 1),
|
|
.apiVersion = VK_API_VERSION_1_2,
|
|
};
|
|
|
|
uint32_t glfwExtensionCount = 0;
|
|
const char** glfwExtensions;
|
|
|
|
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
|
|
|
const char** requested_extensions = malloc(sizeof(char*)*(glfwExtensionCount + instance_extension_count));
|
|
for (uint32_t i = 0; i < glfwExtensionCount; i++) {
|
|
requested_extensions[i] = glfwExtensions[i];
|
|
}
|
|
|
|
for (uint32_t i = 0; i < instance_extension_count; i++) {
|
|
requested_extensions[glfwExtensionCount + i] = instance_extensions[i];
|
|
}
|
|
|
|
VkInstanceCreateInfo instance_info = {
|
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
.pApplicationInfo = &app_info,
|
|
.enabledLayerCount = validation_layer_count,
|
|
.ppEnabledLayerNames = validation_layers,
|
|
.enabledExtensionCount = glfwExtensionCount + instance_extension_count,
|
|
.ppEnabledExtensionNames = requested_extensions,
|
|
.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR,
|
|
};
|
|
|
|
VkResult result = vkCreateInstance(&instance_info, 0, instance);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
free(requested_extensions);
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(
|
|
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
|
VkDebugUtilsMessageTypeFlagsEXT type,
|
|
const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
|
|
void* user_data) {
|
|
|
|
(void)severity;
|
|
(void)type;
|
|
(void)user_data;
|
|
|
|
fprintf(stderr, "Validation layer: %s\n", callback_data->pMessage);
|
|
|
|
return VK_FALSE;
|
|
}
|
|
|
|
VkResult create_debug_messenger(VkInstance instance, VkDebugUtilsMessengerEXT* debug_messenger) {
|
|
VkDebugUtilsMessengerCreateInfoEXT messenger_info = {
|
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
|
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
|
.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 | VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT,
|
|
.pfnUserCallback = debug_callback,
|
|
.pUserData = 0,
|
|
};
|
|
|
|
PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
|
|
|
VkResult result;
|
|
result = func(instance, &messenger_info, 0, debug_messenger);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult get_best_physical_device(VkInstance instance, VkPhysicalDevice* device) {
|
|
uint32_t device_count = 0;
|
|
VkResult result;
|
|
result = vkEnumeratePhysicalDevices(instance, &device_count, 0);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkPhysicalDevice* devices = malloc(sizeof(VkPhysicalDevice)*device_count);
|
|
result = vkEnumeratePhysicalDevices(instance, &device_count, devices);
|
|
if(result != VK_SUCCESS) {
|
|
free(devices);
|
|
return result;
|
|
}
|
|
|
|
int top_score = -1;
|
|
for(uint32_t i = 0; i < device_count; i++) {
|
|
int score = 0;
|
|
|
|
VkPhysicalDeviceProperties properties;
|
|
vkGetPhysicalDeviceProperties(devices[i], &properties);
|
|
|
|
VkPhysicalDeviceFeatures features;
|
|
vkGetPhysicalDeviceFeatures(devices[i], &features);
|
|
|
|
switch(properties.deviceType) {
|
|
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
|
|
score += 100;
|
|
break;
|
|
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
|
|
score += 50;
|
|
break;
|
|
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
|
score += 25;
|
|
break;
|
|
case VK_PHYSICAL_DEVICE_TYPE_CPU:
|
|
score += 0;
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
if(score > top_score) {
|
|
top_score = score;
|
|
*device = devices[i];
|
|
}
|
|
}
|
|
|
|
free(devices);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_logical_device(VkPhysicalDevice physical_device, VkSurfaceKHR surface, Queue* graphics_queue, Queue* present_queue, Queue* transfer_queue, VkDevice* device) {
|
|
if(graphics_queue == NULL || present_queue == NULL || transfer_queue == NULL || device == NULL) {
|
|
return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
}
|
|
|
|
uint32_t queue_family_count = 0;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, NULL);
|
|
|
|
VkQueueFamilyProperties* queue_families = malloc(sizeof(VkQueueFamilyProperties)*queue_family_count);
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families);
|
|
|
|
graphics_queue->family = 0xFFFFFFFF;
|
|
present_queue->family = 0xFFFFFFFF;
|
|
for(uint32_t idx = 0; idx < queue_family_count; idx++) {
|
|
VkBool32 present_support = VK_FALSE;
|
|
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, idx, surface, &present_support);
|
|
VkBool32 graphics_support = (queue_families[idx].queueFlags & VK_QUEUE_GRAPHICS_BIT);
|
|
|
|
if(graphics_support && present_support) {
|
|
graphics_queue->family = idx;
|
|
graphics_queue->index = 0;
|
|
|
|
present_queue->family = idx;
|
|
present_queue->index = 0;
|
|
break;
|
|
} else if (graphics_support && (graphics_queue->family == 0xFFFFFFFF)) {
|
|
graphics_queue->family = idx;
|
|
graphics_queue->index = 0;
|
|
} else if (present_support && (present_queue->family == 0xFFFFFFFF)) {
|
|
graphics_queue->family = idx;
|
|
present_queue->index = 0;
|
|
}
|
|
}
|
|
|
|
transfer_queue->family = 0xFFFFFFFF;
|
|
for(uint32_t idx = 0; idx < queue_family_count; idx++) {
|
|
VkBool32 graphics_support = (queue_families[idx].queueFlags & VK_QUEUE_GRAPHICS_BIT);
|
|
VkBool32 compute_support = (queue_families[idx].queueFlags & VK_QUEUE_COMPUTE_BIT);
|
|
VkBool32 is_graphics_family = (graphics_queue->family == idx);
|
|
VkBool32 is_present_family = (present_queue->family == idx);
|
|
uint32_t queue_count = queue_families[idx].queueCount;
|
|
|
|
if(is_graphics_family && (queue_count == 1)) {
|
|
continue;
|
|
} else if (is_present_family && (queue_count == 1)) {
|
|
continue;
|
|
}
|
|
|
|
if(graphics_support && compute_support) {
|
|
transfer_queue->family = idx;
|
|
if(is_graphics_family || is_present_family) {
|
|
transfer_queue->index = 1;
|
|
} else {
|
|
transfer_queue->index = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(graphics_queue->family == 0xFFFFFFFF || present_queue->family == 0xFFFFFFFF || transfer_queue->family == 0xFFFFFFFF) {
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
}
|
|
|
|
VkDeviceQueueCreateInfo queue_create_info[3] = {};
|
|
uint32_t queue_count = 0;
|
|
float default_queue_priority = 1.0f;
|
|
if(graphics_queue->family == present_queue->family && graphics_queue->family == transfer_queue->family) {
|
|
queue_count = 1;
|
|
|
|
queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queue_create_info[0].queueFamilyIndex = graphics_queue->family;
|
|
queue_create_info[0].queueCount = 2;
|
|
queue_create_info[0].pQueuePriorities = &default_queue_priority;
|
|
} else if (graphics_queue->family == present_queue->family) {
|
|
queue_count = 2;
|
|
|
|
queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queue_create_info[0].queueFamilyIndex = graphics_queue->family;
|
|
queue_create_info[0].queueCount = 1;
|
|
queue_create_info[0].pQueuePriorities = &default_queue_priority;
|
|
|
|
queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queue_create_info[1].queueFamilyIndex = transfer_queue->family;
|
|
queue_create_info[1].queueCount = 1;
|
|
queue_create_info[1].pQueuePriorities = &default_queue_priority;
|
|
} else if (graphics_queue->family == transfer_queue->family) {
|
|
queue_count = 2;
|
|
|
|
queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queue_create_info[0].queueFamilyIndex = graphics_queue->family;
|
|
queue_create_info[0].queueCount = 2;
|
|
queue_create_info[0].pQueuePriorities = &default_queue_priority;
|
|
|
|
queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queue_create_info[1].queueFamilyIndex = present_queue->family;
|
|
queue_create_info[1].queueCount = 1;
|
|
queue_create_info[1].pQueuePriorities = &default_queue_priority;
|
|
} else {
|
|
queue_count = 3;
|
|
|
|
queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queue_create_info[0].queueFamilyIndex = graphics_queue->family;
|
|
queue_create_info[0].queueCount = 1;
|
|
queue_create_info[0].pQueuePriorities = &default_queue_priority;
|
|
|
|
queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queue_create_info[1].queueFamilyIndex = present_queue->family;
|
|
queue_create_info[1].queueCount = 1;
|
|
queue_create_info[1].pQueuePriorities = &default_queue_priority;
|
|
|
|
queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queue_create_info[1].queueFamilyIndex = transfer_queue->family;
|
|
queue_create_info[1].queueCount = 1;
|
|
queue_create_info[1].pQueuePriorities = &default_queue_priority;
|
|
}
|
|
|
|
VkPhysicalDeviceVulkan12Features features_12 = {
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
|
.bufferDeviceAddress = VK_TRUE,
|
|
.descriptorIndexing = VK_TRUE,
|
|
.descriptorBindingPartiallyBound = VK_TRUE,
|
|
.descriptorBindingVariableDescriptorCount = VK_TRUE,
|
|
.descriptorBindingUniformBufferUpdateAfterBind = VK_TRUE,
|
|
.descriptorBindingStorageBufferUpdateAfterBind = VK_TRUE,
|
|
.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE,
|
|
};
|
|
|
|
VkPhysicalDeviceFeatures device_features = {
|
|
.samplerAnisotropy = VK_TRUE,
|
|
};
|
|
|
|
VkDeviceCreateInfo device_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
|
.pQueueCreateInfos = queue_create_info,
|
|
.queueCreateInfoCount = queue_count,
|
|
.pEnabledFeatures = &device_features,
|
|
.enabledExtensionCount = device_extension_count,
|
|
.ppEnabledExtensionNames = device_extensions,
|
|
.enabledLayerCount = validation_layer_count,
|
|
.ppEnabledLayerNames = validation_layers,
|
|
.pNext = &features_12,
|
|
};
|
|
|
|
VkResult result = vkCreateDevice(physical_device, &device_create_info, 0, device);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
vkGetDeviceQueue(*device, graphics_queue->family, graphics_queue->index, &graphics_queue->handle);
|
|
vkGetDeviceQueue(*device, present_queue->family, present_queue->index, &present_queue->handle);
|
|
vkGetDeviceQueue(*device, transfer_queue->family, transfer_queue->index, &transfer_queue->handle);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_memory_allocator(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, VmaAllocator* allocator) {
|
|
VmaAllocatorCreateInfo allocator_create_info = {
|
|
.vulkanApiVersion = VK_API_VERSION_1_2,
|
|
.instance = instance,
|
|
.physicalDevice = physical_device,
|
|
.device = device,
|
|
.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT,
|
|
};
|
|
|
|
VkResult result = vmaCreateAllocator(&allocator_create_info, allocator);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult get_swapchain_details(VkPhysicalDevice physical_device, VkSurfaceKHR surface, SwapchainDetails* details) {
|
|
details->formats = 0;
|
|
details->present_modes = 0;
|
|
|
|
VkResult result;
|
|
|
|
result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &details->capabilities);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &details->formats_count, 0);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
details->formats = malloc(sizeof(VkSurfaceFormatKHR)*details->formats_count);
|
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &details->formats_count, details->formats);
|
|
if(result != VK_SUCCESS) {
|
|
free(details->formats);
|
|
return result;
|
|
}
|
|
|
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &details->present_modes_count, 0);
|
|
if(result != VK_SUCCESS) {
|
|
free(details->formats);
|
|
return result;
|
|
}
|
|
details->present_modes = malloc(sizeof(VkPresentModeKHR)*details->present_modes_count);
|
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &details->present_modes_count, details->present_modes);
|
|
if(result != VK_SUCCESS) {
|
|
free(details->formats);
|
|
free(details->present_modes);
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkSurfaceFormatKHR choose_swapchain_format(SwapchainDetails swapchain_details) {
|
|
for(uint32_t i = 0; i < swapchain_details.formats_count; i++) {
|
|
VkSurfaceFormatKHR format = swapchain_details.formats[i];
|
|
if(format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
|
return format;
|
|
}
|
|
}
|
|
return swapchain_details.formats[0];
|
|
}
|
|
|
|
VkPresentModeKHR choose_present_mode(SwapchainDetails swapchain_details) {
|
|
for(uint32_t i = 0; i < swapchain_details.present_modes_count; i++) {
|
|
if(swapchain_details.present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
|
|
return VK_PRESENT_MODE_MAILBOX_KHR;
|
|
}
|
|
}
|
|
|
|
return VK_PRESENT_MODE_FIFO_KHR;
|
|
}
|
|
|
|
VkExtent2D choose_swapchain_extent(SwapchainDetails swapchain_details) {
|
|
return swapchain_details.capabilities.currentExtent;
|
|
}
|
|
|
|
VkResult create_swapchain(VkDevice device, VkSurfaceFormatKHR format, VkPresentModeKHR present_mode, VkExtent2D extent, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR capabilities, uint32_t graphics_family_index, uint32_t present_family_index, VkSwapchainKHR* swapchain) {
|
|
uint32_t image_count = capabilities.minImageCount + 1;
|
|
uint32_t max_images = capabilities.maxImageCount;
|
|
if((max_images > 0) && (image_count > max_images)) {
|
|
image_count = max_images;
|
|
}
|
|
|
|
VkSwapchainCreateInfoKHR swapchain_info = {
|
|
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
|
.surface = surface,
|
|
.minImageCount = image_count,
|
|
.imageFormat = format.format,
|
|
.imageColorSpace = format.colorSpace,
|
|
.imageExtent = extent,
|
|
.imageArrayLayers = 1,
|
|
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
|
.preTransform = capabilities.currentTransform,
|
|
.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
|
|
.presentMode = present_mode,
|
|
.clipped = VK_TRUE,
|
|
.oldSwapchain = *swapchain,
|
|
};
|
|
|
|
uint32_t queue_families[2] = {graphics_family_index, present_family_index};
|
|
if(graphics_family_index != present_family_index) {
|
|
swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
swapchain_info.queueFamilyIndexCount = 2;
|
|
swapchain_info.pQueueFamilyIndices = queue_families;
|
|
} else {
|
|
swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
swapchain_info.queueFamilyIndexCount = 0;
|
|
swapchain_info.pQueueFamilyIndices = 0;
|
|
}
|
|
|
|
|
|
VkResult result;
|
|
result = vkCreateSwapchainKHR(device, &swapchain_info, 0, swapchain);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult get_swapchain_images(VkDevice device, VkSwapchainKHR swapchain, VkImage** images, uint32_t* image_count) {
|
|
VkResult result;
|
|
result = vkGetSwapchainImagesKHR(device, swapchain, image_count, 0);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
*images = malloc(sizeof(VkImage)*(*image_count));
|
|
if(*images == 0) {
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
|
|
result = vkGetSwapchainImagesKHR(device, swapchain, image_count, *images);
|
|
if(result != VK_SUCCESS) {
|
|
free(*images);
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_image_views(VkDevice device, uint32_t image_count, VkImage* images, VkSurfaceFormatKHR format, VkImageView** image_views) {
|
|
*image_views = malloc(sizeof(VkImageView)*image_count);
|
|
if(*image_views == 0) {
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
|
|
for(uint32_t i = 0; i < image_count; i++) {
|
|
VkImageViewCreateInfo view_info = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
.image = images[i],
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
.format = format.format,
|
|
.components = {
|
|
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
},
|
|
.subresourceRange = {
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
};
|
|
|
|
VkResult result = vkCreateImageView(device, &view_info, 0, &(*image_views)[i]);
|
|
if(result != VK_SUCCESS) {
|
|
free(*image_views);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult find_depth_format(VkPhysicalDevice physical_device, VkImageTiling tiling, VkFormatFeatureFlags features, VkFormat* format) {
|
|
for(uint32_t i = 0; i < depth_format_count; i++) {
|
|
VkFormatProperties properties;
|
|
vkGetPhysicalDeviceFormatProperties(physical_device, depth_formats[i], &properties);
|
|
|
|
if(tiling == VK_IMAGE_TILING_LINEAR && (properties.linearTilingFeatures & features) == features) {
|
|
*format = depth_formats[i];
|
|
return VK_SUCCESS;
|
|
} else if (tiling == VK_IMAGE_TILING_OPTIMAL && (properties.optimalTilingFeatures & features) == features) {
|
|
*format = depth_formats[i];
|
|
return VK_SUCCESS;
|
|
}
|
|
}
|
|
return VK_ERROR_UNKNOWN;
|
|
}
|
|
|
|
VkResult create_render_pass(VkDevice device, VkSurfaceFormatKHR format, VkFormat depth_format, VkRenderPass* render_pass) {
|
|
VkAttachmentDescription attachments[] = {
|
|
{
|
|
.format = format.format,
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
|
},
|
|
{
|
|
.format = depth_format,
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
|
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
|
},
|
|
};
|
|
|
|
VkAttachmentReference color_attachment_refs[] = {
|
|
{
|
|
.attachment = 0,
|
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
},
|
|
};
|
|
|
|
VkAttachmentReference depth_attachment_ref = {
|
|
.attachment = 1,
|
|
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
|
};
|
|
|
|
// Create a subpass with the color and depth attachments
|
|
VkSubpassDescription subpasses[] = {
|
|
{
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
.colorAttachmentCount = sizeof(color_attachment_refs)/sizeof(VkAttachmentReference),
|
|
.pColorAttachments = color_attachment_refs,
|
|
.pDepthStencilAttachment = &depth_attachment_ref,
|
|
},
|
|
{
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
.colorAttachmentCount = sizeof(color_attachment_refs)/sizeof(VkAttachmentReference),
|
|
.pColorAttachments = color_attachment_refs,
|
|
.pDepthStencilAttachment = &depth_attachment_ref,
|
|
},
|
|
};
|
|
|
|
// This basically says "make sure nothing else is writing to the depth_stencil or the color attachment during the pipeline
|
|
VkSubpassDependency dependencies[] = {
|
|
{
|
|
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
.dstSubpass = 0,
|
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
|
.srcAccessMask = 0,
|
|
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
|
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
|
|
},
|
|
{
|
|
.srcSubpass = 0,
|
|
.dstSubpass = 1,
|
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
|
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
|
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
|
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
|
|
}
|
|
};
|
|
|
|
VkRenderPassCreateInfo render_info = {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
.attachmentCount = sizeof(attachments)/sizeof(VkAttachmentDescription),
|
|
.pAttachments = attachments,
|
|
.subpassCount = sizeof(subpasses)/sizeof(VkSubpassDescription),
|
|
.pSubpasses = subpasses,
|
|
.dependencyCount = sizeof(dependencies)/sizeof(VkSubpassDependency),
|
|
.pDependencies = dependencies,
|
|
};
|
|
|
|
VkResult result = vkCreateRenderPass(device, &render_info, 0, render_pass);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_swapchain_framebuffers(VkDevice device, uint32_t image_count, VkImageView* image_views, VkImageView depth_image_view, VkRenderPass render_pass, VkExtent2D extent, VkFramebuffer** framebuffers) {
|
|
*framebuffers = malloc(sizeof(VkFramebuffer)*image_count);
|
|
if(*framebuffers == 0) {
|
|
return 0;
|
|
}
|
|
|
|
VkFramebuffer* framebuffer_ptr = *framebuffers;
|
|
|
|
for(uint32_t i = 0; i < image_count; i++) {
|
|
VkImageView attachments[] = {
|
|
image_views[i],
|
|
depth_image_view,
|
|
};
|
|
|
|
VkFramebufferCreateInfo framebuffer_info = {
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
.renderPass = render_pass,
|
|
.attachmentCount = 2,
|
|
.pAttachments = attachments,
|
|
.width = extent.width,
|
|
.height = extent.height,
|
|
.layers = 1,
|
|
};
|
|
|
|
VkResult result = vkCreateFramebuffer(device, &framebuffer_info, 0, &framebuffer_ptr[i]);
|
|
if(result != VK_SUCCESS) {
|
|
free(*framebuffers);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkSemaphore* create_semaphores(VkDevice device, VkSemaphoreCreateFlags flags, uint32_t count) {
|
|
VkSemaphore* semaphores = malloc(sizeof(VkSemaphore)*count);
|
|
if(semaphores == 0) {
|
|
return 0;
|
|
}
|
|
|
|
VkSemaphoreCreateInfo semaphore_info = {
|
|
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
|
.flags = flags,
|
|
};
|
|
|
|
for(uint32_t i = 0; i < count; i++) {
|
|
VkResult result = vkCreateSemaphore(device, &semaphore_info, 0, &semaphores[i]);
|
|
if(result != VK_SUCCESS) {
|
|
free(semaphores);
|
|
return 0;
|
|
}
|
|
}
|
|
return semaphores;
|
|
}
|
|
|
|
VkFence* create_fences(VkDevice device, VkFenceCreateFlags flags, uint32_t count) {
|
|
VkFence* fences = malloc(sizeof(VkFence)*count);
|
|
if(fences == 0) {
|
|
return 0;
|
|
}
|
|
|
|
VkFenceCreateInfo fence_info = {
|
|
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
|
.flags = flags,
|
|
};
|
|
|
|
for(uint32_t i = 0; i < count; i++) {
|
|
VkResult result = vkCreateFence(device, &fence_info, 0, &fences[i]);
|
|
if(result != VK_SUCCESS) {
|
|
free(fences);
|
|
return 0;
|
|
}
|
|
}
|
|
return fences;
|
|
}
|
|
|
|
VkCommandBuffer* create_command_buffers(VkDevice device, VkCommandPool command_pool, uint32_t image_count) {
|
|
VkCommandBufferAllocateInfo alloc_info = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
.commandPool = command_pool,
|
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
.commandBufferCount = image_count,
|
|
};
|
|
|
|
VkCommandBuffer* command_buffers = malloc(sizeof(VkCommandBuffer)*image_count);
|
|
if(command_buffers == 0) {
|
|
return 0;
|
|
}
|
|
|
|
VkResult result = vkAllocateCommandBuffers(device, &alloc_info, command_buffers);
|
|
if(result != VK_SUCCESS) {
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
|
|
return command_buffers;
|
|
}
|
|
|
|
VkResult create_depth_image(VkDevice device, VkFormat depth_format, VkExtent2D swapchain_extent, VmaAllocator allocator, VkCommandPool extra_graphics_pool, Queue graphics_queue, VkImage* depth_image, VmaAllocation* depth_image_memory, VkImageView* depth_image_view) {
|
|
|
|
VkExtent3D depth_extent = {
|
|
.width = swapchain_extent.width,
|
|
.height = swapchain_extent.height,
|
|
.depth = 1,
|
|
};
|
|
|
|
VkImageCreateInfo depth_image_info = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
.imageType = VK_IMAGE_TYPE_2D,
|
|
.extent = depth_extent,
|
|
.mipLevels = 1,
|
|
.arrayLayers = 1,
|
|
.format = depth_format,
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
.flags = 0,
|
|
};
|
|
|
|
VmaAllocationCreateInfo allocation_info = {
|
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
|
};
|
|
|
|
VkResult result = vmaCreateImage(allocator, &depth_image_info, &allocation_info, depth_image, depth_image_memory, NULL);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkImageViewCreateInfo depth_view_info = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
.image = *depth_image,
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
.format = depth_format,
|
|
.components = {
|
|
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
},
|
|
.subresourceRange = {
|
|
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
};
|
|
|
|
result = vkCreateImageView(device, &depth_view_info, 0, depth_image_view);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = command_transition_image_layout(device, extra_graphics_pool, graphics_queue, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, *depth_image, 0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, VK_IMAGE_ASPECT_DEPTH_BIT);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult init_vulkan(GLFWwindow* window, RenderContext* context) {
|
|
VkResult result;
|
|
if(context == NULL) {
|
|
return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
}
|
|
|
|
result = create_instance(&context->instance);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_debug_messenger(context->instance, &context->debug_messenger);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = get_best_physical_device(context->instance, &context->physical_device);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
vkGetPhysicalDeviceMemoryProperties(context->physical_device, &context->memories);
|
|
|
|
result = glfwCreateWindowSurface(context->instance, window, 0, &context->surface);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_logical_device(context->physical_device, context->surface, &context->graphics_queue, &context->present_queue, &context->transfer_queue, &context->device);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_memory_allocator(context->instance, context->physical_device, context->device, &context->allocator);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkCommandPoolCreateInfo extra_pool_info = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
.queueFamilyIndex = context->graphics_queue.family,
|
|
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
|
};
|
|
result = vkCreateCommandPool(context->device, &extra_pool_info, 0, &context->extra_graphics_pool);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkCommandPoolCreateInfo graphics_pool_info = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
|
.queueFamilyIndex = context->graphics_queue.family,
|
|
};
|
|
result = vkCreateCommandPool(context->device, &graphics_pool_info, 0, &context->graphics_pool);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkCommandPoolCreateInfo transfer_pool_info = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
|
.queueFamilyIndex = context->transfer_queue.family,
|
|
};
|
|
result = vkCreateCommandPool(context->device, &transfer_pool_info, 0, &context->transfer_pool);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
context->swapchain_command_buffers = create_command_buffers(context->device, context->graphics_pool, MAX_FRAMES_IN_FLIGHT);
|
|
if(context->swapchain_command_buffers == NULL) {
|
|
return VK_ERROR_UNKNOWN;
|
|
}
|
|
|
|
context->image_available_semaphores = create_semaphores(context->device, 0, MAX_FRAMES_IN_FLIGHT);
|
|
if(context->image_available_semaphores == NULL) {
|
|
return VK_ERROR_UNKNOWN;
|
|
}
|
|
|
|
context->render_finished_semaphores = create_semaphores(context->device, 0, MAX_FRAMES_IN_FLIGHT);
|
|
if(context->render_finished_semaphores == NULL) {
|
|
return VK_ERROR_UNKNOWN;
|
|
}
|
|
|
|
context->in_flight_fences = create_fences(context->device, VK_FENCE_CREATE_SIGNALED_BIT, MAX_FRAMES_IN_FLIGHT);
|
|
if(context->in_flight_fences == NULL) {
|
|
return VK_ERROR_UNKNOWN;
|
|
}
|
|
|
|
result = get_swapchain_details(context->physical_device, context->surface, &context->swapchain_details);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
context->swapchain_format = choose_swapchain_format(context->swapchain_details);
|
|
context->swapchain_present_mode = choose_present_mode(context->swapchain_details);
|
|
context->swapchain_extent = choose_swapchain_extent(context->swapchain_details);
|
|
context->swapchain = VK_NULL_HANDLE;
|
|
result = create_swapchain(context->device, context->swapchain_format, context->swapchain_present_mode, context->swapchain_extent, context->surface, context->swapchain_details.capabilities, context->graphics_queue.family, context->present_queue.family, &context->swapchain);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = get_swapchain_images(context->device, context->swapchain, &context->swapchain_images, &context->swapchain_image_count);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_image_views(context->device, context->swapchain_image_count, context->swapchain_images, context->swapchain_format, &context->swapchain_image_views);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = find_depth_format(context->physical_device, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, &context->depth_format);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_render_pass(context->device, context->swapchain_format, context->depth_format, &context->render_pass);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_depth_image(context->device, context->depth_format, context->swapchain_extent, context->allocator, context->extra_graphics_pool, context->graphics_queue, &context->depth_image, &context->depth_image_memory, &context->depth_image_view);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_swapchain_framebuffers(context->device, context->swapchain_image_count, context->swapchain_image_views, context->depth_image_view, context->render_pass, context->swapchain_extent, &context->swapchain_framebuffers);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
context->current_frame = 0;
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult draw_frame(RenderContext* context, UIContext* ui_context, UILayer* ui_layers, uint32_t ui_layer_count) {
|
|
VkResult result;
|
|
|
|
result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
uint32_t image_index;
|
|
VkCommandBuffer command_buffer = context->swapchain_command_buffers[context->current_frame];
|
|
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
|
|
result = vkResetCommandBuffer(command_buffer, 0);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkCommandBufferBeginInfo begin_info = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
};
|
|
result = vkBeginCommandBuffer(command_buffer, &begin_info);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkViewport viewport = {
|
|
.width = context->swapchain_extent.width,
|
|
.height = context->swapchain_extent.height,
|
|
.maxDepth = 1.0f,
|
|
.minDepth = 0.0f,
|
|
};
|
|
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
|
|
|
VkRect2D scissor = {
|
|
.extent = context->swapchain_extent,
|
|
};
|
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
|
|
|
VkClearValue clear_values[2] = {{.color={{0.0f, 0.0f, 0.0f, 1.0f}}}, {.depthStencil={1.0f, 0.0f}}};
|
|
VkDeviceSize offset = 0;
|
|
|
|
VkRenderPassBeginInfo render_pass_begin = {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
.renderPass = context->render_pass,
|
|
.framebuffer = context->swapchain_framebuffers[image_index],
|
|
.renderArea.offset = {0, 0},
|
|
.renderArea.extent = context->swapchain_extent,
|
|
.clearValueCount = 2,
|
|
.pClearValues = clear_values,
|
|
};
|
|
vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
|
|
// World subpass
|
|
|
|
vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE);
|
|
// UI subpass
|
|
|
|
// Draw UI colored rects ////////////////////////////////
|
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_rect.pipeline);
|
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_rect.layout, 0, 1, &ui_context->ui_descriptor_set, 0, NULL);
|
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, &ui_context->ui_rect.vertex, &offset);
|
|
vkCmdBindIndexBuffer(command_buffer, ui_context->ui_rect.index, 0, VK_INDEX_TYPE_UINT32);
|
|
|
|
for(uint32_t i = 0; i < ui_layer_count; i++) {
|
|
if(ui_layers[i].colored_rect_count > 0) {
|
|
vkCmdBindVertexBuffers(command_buffer, 1, 1, &ui_layers[i].colored_rects, &offset);
|
|
vkCmdDrawIndexed(command_buffer, 6, ui_layers[i].colored_rect_count, 0, 0, 0);
|
|
}
|
|
}
|
|
/////////////////////////////////////////////////////////
|
|
// Draw UI text /////////////////////////////////////////
|
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, ui_context->ui_compute_text.pipeline);
|
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_text.pipeline);
|
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_text.layout, 0, 1, &ui_context->ui_descriptor_set, 0, NULL);
|
|
for(uint32_t i = 0; i < ui_layer_count; i++) {
|
|
if(ui_layers[i].text_count > 0) {
|
|
// Bind Font Descriptor
|
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_text.layout, 1, 1, &ui_layers[i].font.set, 0, NULL);
|
|
// Push pointers
|
|
vkCmdPushConstants(command_buffer, ui_context->ui_pipeline_text.layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, &ui_layers[i].texts_address);
|
|
vkCmdDrawIndexed(command_buffer, 6, ui_layers[i].text_count, 0, 0, 0);
|
|
}
|
|
}
|
|
/////////////////////////////////////////////////////////
|
|
|
|
vkCmdEndRenderPass(command_buffer);
|
|
|
|
result = vkEndCommandBuffer(command_buffer);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
|
VkSubmitInfo submit_info = {
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
.waitSemaphoreCount = 1,
|
|
.pWaitSemaphores = &context->image_available_semaphores[context->current_frame],
|
|
.pWaitDstStageMask = wait_stages,
|
|
.commandBufferCount = 1,
|
|
.pCommandBuffers = &command_buffer,
|
|
.signalSemaphoreCount = 1,
|
|
.pSignalSemaphores = &context->render_finished_semaphores[context->current_frame],
|
|
};
|
|
|
|
result = vkQueueSubmit(context->graphics_queue.handle, 1, &submit_info, context->in_flight_fences[context->current_frame]);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkPresentInfoKHR present_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
|
.waitSemaphoreCount = 1,
|
|
.pWaitSemaphores = &context->render_finished_semaphores[context->current_frame],
|
|
.swapchainCount = 1,
|
|
.pSwapchains = &context->swapchain,
|
|
.pImageIndices = &image_index,
|
|
.pResults = 0,
|
|
};
|
|
|
|
result = vkQueuePresentKHR(context->present_queue.handle, &present_info);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
context->current_frame = (context->current_frame + 1) % MAX_FRAMES_IN_FLIGHT;
|
|
|
|
return VK_SUCCESS;
|
|
}
|