|
|
|
@@ -15,25 +15,23 @@
|
|
|
|
|
#include <SDL3/SDL_log.h>
|
|
|
|
|
#include <SDL3/SDL_main.h>
|
|
|
|
|
#include <SDL3/SDL_vulkan.h>
|
|
|
|
|
#include <vma/vk_mem_alloc.h>
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <vk_mem_alloc.h>
|
|
|
|
|
|
|
|
|
|
#include "pipeline_builder.h"
|
|
|
|
|
#include "src/descriptor_builder.h"
|
|
|
|
|
#include "src/graphics_context.h"
|
|
|
|
|
#include "utilities/commons.h"
|
|
|
|
|
#include "utilities/errors_common.h"
|
|
|
|
|
#include "vulkan/vulkan_core.h"
|
|
|
|
|
|
|
|
|
|
#include "vulkan_commons.h"
|
|
|
|
|
#include "vulkan_commands.h"
|
|
|
|
|
#include "vulkan_buffers.h"
|
|
|
|
|
#include "vulkan_commands.h"
|
|
|
|
|
#include "vulkan_commons.h"
|
|
|
|
|
#include "vulkan_image.h"
|
|
|
|
|
#include "vulkan_render_pass.h"
|
|
|
|
|
#include "vulkan_swapchain.h"
|
|
|
|
|
#include "pipeline_builder.h"
|
|
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#define APPLICATION_NAME "RedScarfEngine PoC"
|
|
|
|
|
#define ENGINE_NAME "RedScarf Engine"
|
|
|
|
@@ -48,8 +46,9 @@
|
|
|
|
|
* @return VkBool32 Should always return VK_FALSE. The VK_TRUE value is reserved for use in layer development
|
|
|
|
|
*/
|
|
|
|
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
|
|
|
|
|
VkDebugUtilsMessageTypeFlagsEXT message_type,
|
|
|
|
|
const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data)
|
|
|
|
|
VkDebugUtilsMessageTypeFlagsEXT message_type,
|
|
|
|
|
const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
|
|
|
|
|
void* user_data)
|
|
|
|
|
{
|
|
|
|
|
(void)message_severity;
|
|
|
|
|
(void)message_type;
|
|
|
|
@@ -80,9 +79,10 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverity
|
|
|
|
|
* @param debug_messenger Debug messanger handle
|
|
|
|
|
* @return VkResult VK_SUCCESS on success
|
|
|
|
|
*/
|
|
|
|
|
static VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* create_info,
|
|
|
|
|
const VkAllocationCallbacks* allocator,
|
|
|
|
|
VkDebugUtilsMessengerEXT* debug_messenger)
|
|
|
|
|
static VkResult CreateDebugUtilsMessengerEXT(VkInstance instance,
|
|
|
|
|
const VkDebugUtilsMessengerCreateInfoEXT* create_info,
|
|
|
|
|
const VkAllocationCallbacks* allocator,
|
|
|
|
|
VkDebugUtilsMessengerEXT* debug_messenger)
|
|
|
|
|
{
|
|
|
|
|
PFN_vkCreateDebugUtilsMessengerEXT func = NULL;
|
|
|
|
|
|
|
|
|
@@ -108,13 +108,12 @@ static rse_err_t setup_debug_messenger(VkInstance instance, VkDebugUtilsMessenge
|
|
|
|
|
|
|
|
|
|
create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
|
|
|
create_info.pNext = NULL;
|
|
|
|
|
create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
|
|
|
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
|
|
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
|
|
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
|
|
|
|
create_info.messageSeverity =
|
|
|
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
|
|
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
|
|
|
|
create_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;
|
|
|
|
|
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
|
|
|
|
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
|
|
|
|
create_info.pfnUserCallback = debug_callback;
|
|
|
|
|
create_info.pUserData = NULL; // Optional
|
|
|
|
|
create_info.flags = 0U;
|
|
|
|
@@ -134,8 +133,9 @@ static rse_err_t setup_debug_messenger(VkInstance instance, VkDebugUtilsMessenge
|
|
|
|
|
* @param debug_messenger Debug messanger handle
|
|
|
|
|
* @param allocator Memory allocator
|
|
|
|
|
*/
|
|
|
|
|
static void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debug_messenger,
|
|
|
|
|
const VkAllocationCallbacks* allocator)
|
|
|
|
|
static void DestroyDebugUtilsMessengerEXT(VkInstance instance,
|
|
|
|
|
VkDebugUtilsMessengerEXT debug_messenger,
|
|
|
|
|
const VkAllocationCallbacks* allocator)
|
|
|
|
|
{
|
|
|
|
|
PFN_vkDestroyDebugUtilsMessengerEXT func =
|
|
|
|
|
(PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
|
|
|
@@ -173,7 +173,7 @@ static rse_err_t create_instance(VkInstance* instance)
|
|
|
|
|
"VK_KHR_xlib_surface",
|
|
|
|
|
#endif /* WAYLAND */
|
|
|
|
|
#elif defined(_WIN32) || defined(WIN32)
|
|
|
|
|
"VK_KHR_win32_surface",
|
|
|
|
|
"VK_KHR_win32_surface",
|
|
|
|
|
#endif /* _WIN32 || WIN32 */
|
|
|
|
|
"VK_EXT_debug_utils",
|
|
|
|
|
};
|
|
|
|
@@ -211,13 +211,13 @@ static rse_err_t create_instance(VkInstance* instance)
|
|
|
|
|
|
|
|
|
|
/* Check if selected layers are supported*/
|
|
|
|
|
for (i = 0; i < enabled_instance_layers_count; ++i) {
|
|
|
|
|
for(j = 0; i < layersCount; ++j) {
|
|
|
|
|
if(strcmp(layer_properties[j].layerName, enabled_instance_layers_names[i]) == 0) {
|
|
|
|
|
for (j = 0; i < layersCount; ++j) {
|
|
|
|
|
if (strcmp(layer_properties[j].layerName, enabled_instance_layers_names[i]) == 0) {
|
|
|
|
|
supported = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(supported == 0) {
|
|
|
|
|
if (supported == 0) {
|
|
|
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Selected layer is not supported: %s", layer_properties[j].layerName);
|
|
|
|
|
return RSE_ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
|
|
|
@@ -226,14 +226,16 @@ static rse_err_t create_instance(VkInstance* instance)
|
|
|
|
|
|
|
|
|
|
/* Check if selected extensions are supported*/
|
|
|
|
|
for (i = 0; i < enabled_instance_extensions_count; ++i) {
|
|
|
|
|
for(j = 0; j < extensionCount; ++j) {
|
|
|
|
|
if(strcmp(extensions_properties[j].extensionName, enabled_instance_extensions_names[i]) == 0) {
|
|
|
|
|
for (j = 0; j < extensionCount; ++j) {
|
|
|
|
|
if (strcmp(extensions_properties[j].extensionName, enabled_instance_extensions_names[i]) == 0) {
|
|
|
|
|
supported = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(supported == 0) {
|
|
|
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Selected extension is not supported: %s", extensions_properties[j].extensionName);
|
|
|
|
|
if (supported == 0) {
|
|
|
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU,
|
|
|
|
|
"Selected extension is not supported: %s",
|
|
|
|
|
extensions_properties[j].extensionName);
|
|
|
|
|
return RSE_ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
supported = 0;
|
|
|
|
@@ -293,7 +295,8 @@ static rse_err_t pick_physical_device(VkInstance instance, VkPhysicalDevice* phy
|
|
|
|
|
{
|
|
|
|
|
uint32_t physical_device_count = 0U;
|
|
|
|
|
VkPhysicalDevice* physical_devices = NULL;
|
|
|
|
|
VkPhysicalDeviceProperties device_properties = {0};;
|
|
|
|
|
VkPhysicalDeviceProperties device_properties = {0};
|
|
|
|
|
;
|
|
|
|
|
VkPhysicalDeviceFeatures device_features = {0};
|
|
|
|
|
|
|
|
|
|
/* Get number of existing physical devices */
|
|
|
|
@@ -378,9 +381,12 @@ static rse_err_t create_device(struct graphics_context_t* context)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get information about supported queue families */
|
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(context->vulkan_handles.physical_device, &queue_families_property_count, NULL);
|
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(context->vulkan_handles.physical_device,
|
|
|
|
|
&queue_families_property_count,
|
|
|
|
|
NULL);
|
|
|
|
|
rse_malloc(queue_family_properties, sizeof(VkQueueFamilyProperties) * queue_families_property_count);
|
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(context->vulkan_handles.physical_device, &queue_families_property_count,
|
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(context->vulkan_handles.physical_device,
|
|
|
|
|
&queue_families_property_count,
|
|
|
|
|
queue_family_properties);
|
|
|
|
|
|
|
|
|
|
/* Get queue families that support graphics operations AND have most
|
|
|
|
@@ -401,7 +407,10 @@ static rse_err_t create_device(struct graphics_context_t* context)
|
|
|
|
|
|
|
|
|
|
/* Check for family with surface support */
|
|
|
|
|
VkBool32 presentSupport = VK_FALSE;
|
|
|
|
|
vkGetPhysicalDeviceSurfaceSupportKHR(context->vulkan_handles.physical_device, familyIdx, context->vulkan_handles.surface, &presentSupport);
|
|
|
|
|
vkGetPhysicalDeviceSurfaceSupportKHR(context->vulkan_handles.physical_device,
|
|
|
|
|
familyIdx,
|
|
|
|
|
context->vulkan_handles.surface,
|
|
|
|
|
&presentSupport);
|
|
|
|
|
if (presentSupport) {
|
|
|
|
|
presentation_familiy_idx = familyIdx;
|
|
|
|
|
presentation_familiy_found = true;
|
|
|
|
@@ -426,16 +435,17 @@ static rse_err_t create_device(struct graphics_context_t* context)
|
|
|
|
|
context->queue_family_indices[QUEUE_FAMILY_INDEX_GRAPHICS] = graphics_family_idx;
|
|
|
|
|
context->queue_family_indices[QUEUE_FAMILY_INDEX_PRESENTATION] = presentation_familiy_idx;
|
|
|
|
|
|
|
|
|
|
rse_malloc(graphics_familiy_queue_priorities, sizeof(float) * queue_family_properties[graphics_family_idx].queueCount);
|
|
|
|
|
rse_malloc(graphics_familiy_queue_priorities,
|
|
|
|
|
sizeof(float) * queue_family_properties[graphics_family_idx].queueCount);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < queue_family_properties[graphics_family_idx].queueCount; i++) {
|
|
|
|
|
graphics_familiy_queue_priorities[i] = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rse_malloc(presentation_familiy_queue_priorities, sizeof(float) * queue_family_properties[presentation_familiy_idx].queueCount);
|
|
|
|
|
rse_malloc(presentation_familiy_queue_priorities,
|
|
|
|
|
sizeof(float) * queue_family_properties[presentation_familiy_idx].queueCount);
|
|
|
|
|
for (size_t i = 0; i < queue_family_properties[presentation_familiy_idx].queueCount; i++) {
|
|
|
|
|
presentation_familiy_queue_priorities[i] =
|
|
|
|
|
1.0f;
|
|
|
|
|
presentation_familiy_queue_priorities[i] = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
device_queue_createinfos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
@@ -463,13 +473,19 @@ static rse_err_t create_device(struct graphics_context_t* context)
|
|
|
|
|
device_create_info.ppEnabledExtensionNames = enabled_device_extensions_names;
|
|
|
|
|
device_create_info.pEnabledFeatures = NULL;
|
|
|
|
|
|
|
|
|
|
if (VK_SUCCESS != vkCreateDevice(context->vulkan_handles.physical_device, &device_create_info, NULL, &context->vulkan_handles.device)) {
|
|
|
|
|
if (VK_SUCCESS != vkCreateDevice(context->vulkan_handles.physical_device,
|
|
|
|
|
&device_create_info,
|
|
|
|
|
NULL,
|
|
|
|
|
&context->vulkan_handles.device)) {
|
|
|
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to create logical device");
|
|
|
|
|
return RSE_ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vkGetDeviceQueue(context->vulkan_handles.device, graphics_family_idx, 0, &context->vulkan_handles.graphics_queue);
|
|
|
|
|
vkGetDeviceQueue(context->vulkan_handles.device, presentation_familiy_idx, 0, &context->vulkan_handles.present_queue);
|
|
|
|
|
vkGetDeviceQueue(context->vulkan_handles.device,
|
|
|
|
|
presentation_familiy_idx,
|
|
|
|
|
0,
|
|
|
|
|
&context->vulkan_handles.present_queue);
|
|
|
|
|
|
|
|
|
|
rse_free(presentation_familiy_queue_priorities);
|
|
|
|
|
rse_free(graphics_familiy_queue_priorities);
|
|
|
|
@@ -505,7 +521,6 @@ static rse_err_t create_memory_allocator(struct graphics_context_t* context)
|
|
|
|
|
return RSE_ERROR_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Create a Sync Objects
|
|
|
|
|
*
|
|
|
|
@@ -522,25 +537,34 @@ static rse_err_t create_sync_objects(struct graphics_context_t* context)
|
|
|
|
|
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < SWAP_BUFFER_COUNT; ++i) {
|
|
|
|
|
if (VK_SUCCESS != vkCreateSemaphore(context->vulkan_handles.device, &semaphore_info, NULL, &context->vulkan_handles.image_available_semaphores[i]) ||
|
|
|
|
|
VK_SUCCESS != vkCreateSemaphore(context->vulkan_handles.device, &semaphore_info, NULL, &context->vulkan_handles.render_finished_semaphores[i]) ||
|
|
|
|
|
VK_SUCCESS != vkCreateFence(context->vulkan_handles.device, &fenceInfo, NULL, &context->vulkan_handles.in_flight_fences[i])) {
|
|
|
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to create sync objects.");
|
|
|
|
|
return RSE_ERROR_INTERNAL_ERROR;
|
|
|
|
|
if (VK_SUCCESS != vkCreateSemaphore(context->vulkan_handles.device,
|
|
|
|
|
&semaphore_info,
|
|
|
|
|
NULL,
|
|
|
|
|
&context->vulkan_handles.image_available_semaphores[i]) ||
|
|
|
|
|
VK_SUCCESS != vkCreateSemaphore(context->vulkan_handles.device,
|
|
|
|
|
&semaphore_info,
|
|
|
|
|
NULL,
|
|
|
|
|
&context->vulkan_handles.render_finished_semaphores[i]) ||
|
|
|
|
|
VK_SUCCESS != vkCreateFence(context->vulkan_handles.device,
|
|
|
|
|
&fenceInfo,
|
|
|
|
|
NULL,
|
|
|
|
|
&context->vulkan_handles.in_flight_fences[i])) {
|
|
|
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to create sync objects.");
|
|
|
|
|
return RSE_ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return RSE_ERROR_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rse_err_t vulkan_init(struct graphics_context_t* context)
|
|
|
|
|
{
|
|
|
|
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
|
|
|
|
|
|
|
|
|
STATUS_CHECK(create_instance(&context->vulkan_handles.instance));
|
|
|
|
|
STATUS_CHECK(setup_debug_messenger(context->vulkan_handles.instance, &context->vulkan_handles.debug_messenger));
|
|
|
|
|
STATUS_CHECK(create_surface(context->vulkan_handles.instance, context->window_handle, &context->vulkan_handles.surface));
|
|
|
|
|
STATUS_CHECK(
|
|
|
|
|
create_surface(context->vulkan_handles.instance, context->window_handle, &context->vulkan_handles.surface));
|
|
|
|
|
STATUS_CHECK(pick_physical_device(context->vulkan_handles.instance, &context->vulkan_handles.physical_device));
|
|
|
|
|
STATUS_CHECK(create_device(context));
|
|
|
|
|
STATUS_CHECK(create_memory_allocator(context));
|
|
|
|
@@ -574,12 +598,20 @@ rse_err_t vulkan_draw_frame(struct graphics_context_t* context)
|
|
|
|
|
VkPresentInfoKHR present_info = {0};
|
|
|
|
|
VkSwapchainKHR swap_chains[1];
|
|
|
|
|
|
|
|
|
|
vkWaitForFences(context->vulkan_handles.device, 1, &context->vulkan_handles.in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
|
|
|
|
|
vkWaitForFences(context->vulkan_handles.device,
|
|
|
|
|
1,
|
|
|
|
|
&context->vulkan_handles.in_flight_fences[context->current_frame],
|
|
|
|
|
VK_TRUE,
|
|
|
|
|
UINT64_MAX);
|
|
|
|
|
|
|
|
|
|
STATUS_CHECK(buffers_update(context));
|
|
|
|
|
|
|
|
|
|
result = vkAcquireNextImageKHR(context->vulkan_handles.device, context->swapchain_data.swapchain, UINT64_MAX, context->vulkan_handles.image_available_semaphores[context->current_frame],
|
|
|
|
|
VK_NULL_HANDLE, &image_index);
|
|
|
|
|
result = vkAcquireNextImageKHR(context->vulkan_handles.device,
|
|
|
|
|
context->swapchain_data.swapchain,
|
|
|
|
|
UINT64_MAX,
|
|
|
|
|
context->vulkan_handles.image_available_semaphores[context->current_frame],
|
|
|
|
|
VK_NULL_HANDLE,
|
|
|
|
|
&image_index);
|
|
|
|
|
|
|
|
|
|
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
|
|
|
|
recreate_swapchain(context);
|
|
|
|
@@ -612,7 +644,10 @@ rse_err_t vulkan_draw_frame(struct graphics_context_t* context)
|
|
|
|
|
submit_info.signalSemaphoreCount = 1;
|
|
|
|
|
submit_info.pSignalSemaphores = signal_semaphores;
|
|
|
|
|
|
|
|
|
|
if (vkQueueSubmit(context->vulkan_handles.graphics_queue, 1, &submit_info, context->vulkan_handles.in_flight_fences[context->current_frame]) != VK_SUCCESS) {
|
|
|
|
|
if (vkQueueSubmit(context->vulkan_handles.graphics_queue,
|
|
|
|
|
1,
|
|
|
|
|
&submit_info,
|
|
|
|
|
context->vulkan_handles.in_flight_fences[context->current_frame]) != VK_SUCCESS) {
|
|
|
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to submit draw command buffer!");
|
|
|
|
|
return RSE_ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
|
|
|
|