diff --git a/graphics/rse_graphics.h b/graphics/rse_graphics.h index b5ef3c6e..cb2f72f1 100644 --- a/graphics/rse_graphics.h +++ b/graphics/rse_graphics.h @@ -3,9 +3,28 @@ #include -void rse_graphics_init(void); -uint8_t rse_graphics_run(void); +#include "utilities/rse_commons.h" +/** + * @brief Initializes graphics backend. This has to be called before any new mesh, texture or any other object is + * added + * + * @return rse_err_t RSE_ERROR_NO_ERROR on success + */ +rse_err_t rse_graphics_init(void); + +/** + * @brief Runs graphics engine. This has to be called after all objects are added to the scene + * + * @return rse_err_t RSE_ERROR_NO_ERROR on success + */ +rse_err_t rse_graphics_run(void); + + +/** + * @brief Custom function for testing engine. Remove it whe releasing + * + */ void rse_graphics_test_function(void); #endif /* RSE_GRAPHICS_H */ \ No newline at end of file diff --git a/graphics/src/locale_vulkan.h b/graphics/src/locale_vulkan.h index 2c967b71..d64a7fdc 100644 --- a/graphics/src/locale_vulkan.h +++ b/graphics/src/locale_vulkan.h @@ -14,14 +14,16 @@ #include "utilities/localization.h" -#define vulkan_error_messages vulkan_error_messages_nolocale[SELECTED_LANGUAGE] +#define vulkan_messages vulkan_messages_nolocale[SELECTED_LANGUAGE] -enum vulkan_errors_t { +enum vulkan_messages_t { + VULKAN_DEBUG_MESSENGER_SETUP_FAILED, VULKAN_LAYER_NOT_SUPPORTED, VULKAN_EXTENSION_NOT_SUPPORTED, VULKAN_INTANCE_INIT_FAILED, VULKAN_NO_PHYSICAL_DEVICES, VULKAN_NO_SUITABLE_PHYSICAL_DEVICES, + VULKAN_BINDLESS_DESIGN_NOT_SUPPORTED, VULKAN_QUEUE_NOT_SUPPORTED, VULKAN_FAILED_TO_CREATE_DEVICE, VULKAN_ALLOCATOR_CREATION_FAILED, @@ -31,6 +33,7 @@ enum vulkan_errors_t { VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED, VULKAN_SURFACE_CREATION_FAILED, VULKAN_SWAPCHAIN_CREATION_FAILED, + VULKAN_ACQUIRE_SWAPCHAIN_FAILED, VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED, VULKAN_SHADER_UNABLE_TO_OPEN, VULKAN_SHADER_UNABLE_TO_CREATE_SHADER, @@ -47,11 +50,17 @@ enum vulkan_errors_t { VULKAN_MESH_NO_FREE, VULKAN_MESH_INSTANCE_NO_FREE, VULAKN_DRAW_FAILED, - LAST_MESSAGE + VULKAN_FORMAT_NOT_FOUND, + VULKAN_IMAGE_NOT_CREATED, + VULKAN_IMAGE_VIEW_NOT_CREATED, + VULKAN_MAX_TEXTURE_COUNT_REACHED, + VULKAN_LAST_MESSAGE }; -static const char vulkan_error_messages_nolocale[LAST_LANGUAGE][LAST_MESSAGE][MAX_MESSAGE_LENGHT] = { +static const char vulkan_messages_nolocale[LAST_LANGUAGE][VULKAN_LAST_MESSAGE][MAX_MESSAGE_LENGHT] = { {/* EN_US */ + /* VULKAN_DEBUG_MESSENGER_SETUP_FAILED*/ + "Failed to setup debug messenger\n", /* VULKAN_LAYER_NOT_SUPPORTED */ "Selected layer is not supported: %s\n", /* VULKAN_EXTENSION_NOT_SUPPORTED */ @@ -62,6 +71,8 @@ static const char vulkan_error_messages_nolocale[LAST_LANGUAGE][LAST_MESSAGE][MA "No physical graphical physical devices found in system\n", /* VULKAN_NO_SUITABLE_PHYSICAL_DEVICES */ "No suitable physical device found\n", + /* VULKAN_BINDLESS_DESIGN_NOT_SUPPORTED */ + "Required features for bindless design not supported\n", /* VULKAN_QUEUE_NOT_SUPPORTED */ "Selected physical device does not support required queue capabilities\n", /* VULKAN_FAILED_TO_CREATE_DEVICE */ @@ -80,6 +91,8 @@ static const char vulkan_error_messages_nolocale[LAST_LANGUAGE][LAST_MESSAGE][MA "Failed to create window surface\n", /* VULKAN_SWAPCHAIN_CREATION_FAILED */ "Failed to create swapchain\n", + /* VULKAN_ACQUIRE_SWAPCHAIN_FAILED */ + "Failed to acquire swapchain image\n", /* VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED */ "Failed to create swapchain image view\n", /* VULKAN_SHADER_UNABLE_TO_OPEN */ @@ -111,7 +124,15 @@ static const char vulkan_error_messages_nolocale[LAST_LANGUAGE][LAST_MESSAGE][MA /* VULKAN_MESH_INSTANCE_NO_FREE */ "Could not allocate new mesh instance\n", /* VULAKN_DRAW_FAILED */ - "Failed to submit draw command buffer!", + "Failed to submit draw command buffer!\n", + /* VULKAN_ERROR_FORMAT_NOT_FOUND */ + "Failed to find correct format\n", + /* VULKAN_IMAGE_NOT_CREATED */ + "Failed to create image\n", + /* VULKAN_IMAGE_VIEW_NOT_CREATED */ + "Failed to create image view\n", + /* VULKAN_MAX_TEXTURE_COUNT_REACHED */ + "Failed to find free texture image handle\n", } }; diff --git a/graphics/src/locale_window.h b/graphics/src/locale_window.h index 42f2adcd..b7ddc1be 100644 --- a/graphics/src/locale_window.h +++ b/graphics/src/locale_window.h @@ -16,15 +16,15 @@ #define window_error_messages window_error_messages_nolocale[SELECTED_LANGUAGE] -enum Errors +enum window_messages_t { WINDOW_GLFW_INIT_FAILED, WINDOW_VULKAN_NOT_SUPPORTED, WINDOW_NOT_CREATED, - LAST_MESSAGE + WINDOW_LAST_MESSAGE }; -static const char window_error_messages_nolocale[LAST_LANGUAGE][LAST_MESSAGE][MAX_MESSAGE_LENGHT] = { +static const char window_error_messages_nolocale[LAST_LANGUAGE][WINDOW_LAST_MESSAGE][MAX_MESSAGE_LENGHT] = { {/* EN_US */ /* WINDOW_GLFW_INIT_FAILED */ "GLFW init failed!\n", diff --git a/graphics/src/mesh_controller.c b/graphics/src/mesh_controller.c index 63e51f40..b0318c10 100644 --- a/graphics/src/mesh_controller.c +++ b/graphics/src/mesh_controller.c @@ -1,6 +1,8 @@ #include "mesh_controller.h" #include "vulkan_buffers.h" +#include "vulkan_errors.h" +#include "utilities/rse_errors_common.h" #include "locale_vulkan.h" #include "utilities/logger.h" @@ -53,13 +55,12 @@ uint16_t create_mesh(struct rse_vertex_t* vertices, } if(iter >= MAX_MESH_NUMBER) { - LOGE(vulkan_error_messages[VULKAN_MESH_NO_FREE]); + LOGE(vulkan_messages[VULKAN_MESH_NO_FREE]); /* TODO: Add error handling */ return MAX_MESH_NUMBER; } g_meshes[iter].is_mesh_id_taken = MESH_ID_TAKEN; - g_meshes[iter].unique_id = iter; g_meshes[iter].vertex_data.count = vertices_count; g_meshes[iter].index_data.count = indices_count; @@ -71,7 +72,7 @@ uint16_t create_mesh(struct rse_vertex_t* vertices, return iter; } -void create_mesh_instance(uint16_t mesh_id, +rse_err_t create_mesh_instance(uint16_t mesh_id, struct rse_instance_data_t instance_data) { size_t iter = 0U; @@ -83,9 +84,8 @@ void create_mesh_instance(uint16_t mesh_id, } if(iter >= MAX_INSTANCE_NUMBER) { - LOGE(vulkan_error_messages[VULKAN_MESH_NO_FREE]); - /* TODO: Add error handling */ - return; + LOGE(vulkan_messages[VULKAN_MESH_NO_FREE]); + return VULKAN_ERROR_MAX_INSTANCE_COUNT_REACHED; } g_meshes[mesh_id].instance_data[iter].instance_taken = MESH_ID_TAKEN; @@ -95,6 +95,8 @@ void create_mesh_instance(uint16_t mesh_id, } update_mesh_instances(mesh_id, &instance_data); + + return RSE_ERROR_NO_ERROR; } size_t get_vertices_count(uint16_t mesh_id) diff --git a/graphics/src/mesh_controller.h b/graphics/src/mesh_controller.h index 3339a8d6..b9e5ef0d 100644 --- a/graphics/src/mesh_controller.h +++ b/graphics/src/mesh_controller.h @@ -13,6 +13,7 @@ #define RSE_MESH_CONTROLLER_H #include "vulkan_commons.h" +#include "utilities/rse_commons.h" /** * @brief Create a new mesh for provided vertices and indices. @@ -33,7 +34,7 @@ uint16_t create_mesh(struct rse_vertex_t* vertices, * @param mesh_id Mesh id * @param instance_data Transformation info */ -void create_mesh_instance(uint16_t mesh_id, +rse_err_t create_mesh_instance(uint16_t mesh_id, struct rse_instance_data_t instance_data); /** @@ -60,10 +61,12 @@ size_t get_indices_count(uint16_t mesh_id); */ size_t get_instances_count(uint16_t mesh_id); +/** + * @brief Get vertex offset in vertex buffer for selected mesh + * + * @param mesh_id Mesh identifies + * @return size_t Offset + */ size_t get_vertex_offset(uint16_t mesh_id); -VkDrawIndexedIndirectCommand get_indices_data_buffer(uint16_t mesh_id); - - - #endif /* RSE_MESH_CONTROLLER_H */ \ No newline at end of file diff --git a/graphics/src/rse_graphics.c b/graphics/src/rse_graphics.c index 1ad10820..9441a686 100644 --- a/graphics/src/rse_graphics.c +++ b/graphics/src/rse_graphics.c @@ -5,13 +5,17 @@ #include "mesh_controller.h" #include "vulkan_commons.h" #include "rse_vulkan_image.h" +#include "utilities/logger.h" +#include "utilities/rse_commons.h" +#include "utilities/rse_errors_common.h" #include "rse_math.h" extern struct rse_vulkan_state_t g_vulkan_state; -void rse_graphics_init(void) +rse_err_t rse_graphics_init(void) { + rse_err_t status = RSE_ERROR_NO_ERROR; g_vulkan_state.graphics_queue = VK_NULL_HANDLE; g_vulkan_state.physical_device = VK_NULL_HANDLE; g_vulkan_state.current_frame = 0U; @@ -21,17 +25,22 @@ void rse_graphics_init(void) g_vulkan_state.pipeline_layout = VK_NULL_HANDLE; g_vulkan_state.swapchain = VK_NULL_HANDLE; - window_init(); + STATUS_CHECK(window_init()); + STATUS_CHECK(preinit_vulkan()); - if (0 != preinit_vulkan()) - return; + return status; } void rse_graphics_test_function(void) { - int8_t tex_id_2 = 0; + rse_err_t status = RSE_ERROR_NO_ERROR; + uint8_t tex_id_2 = 0; - tex_id_2 = rse_load_texture("../../test_image.png"); + status = rse_load_texture("../../test_image.png", &tex_id_2); + if (status != RSE_ERROR_NO_ERROR) { + LOGE("Failed to do something. Check error messages"); + return; + } // FIXME: Temporary array of vertices, for testing purposes struct rse_vertex_t vertices[] = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, @@ -71,17 +80,16 @@ void rse_graphics_test_function(void) }); } -uint8_t rse_graphics_run(void) +rse_err_t rse_graphics_run(void) { - if (0 != init_vulkan()) { - return -1; - } + rse_err_t status = RSE_ERROR_NO_ERROR; + STATUS_CHECK(init_vulkan()); - window_loop(); + STATUS_CHECK(window_loop()); deinit_vulkan(); window_terminate(); - return 0; + return status; } diff --git a/graphics/src/rse_math.c b/graphics/src/rse_math.c index fb37abff..d536b90f 100644 --- a/graphics/src/rse_math.c +++ b/graphics/src/rse_math.c @@ -29,27 +29,6 @@ static float scalar_cross_vec3(const struct vec3_t* vec1, const struct vec3_t* v +(vec1->z * vec2->z); } -// static struct mat4_t mat4_times_vector3_t(const struct mat4_t* mat, const struct vec3_t* vec) -// { -// /* We can't do that, mathematically speaking, but we can just assume that the 4th -// * element of vector is just 1. */ -// struct mat4_t result = rse_math_uniform_mat4(); - -// result.x_1 = mat->x_1 * vec->x; -// result.x_2 = mat->x_2 * vec->y; -// result.x_3 = mat->x_3 * vec->z; - -// result.y_1 = mat->y_1 * vec->x; -// result.y_2 = mat->y_2 * vec->y; -// result.y_3 = mat->y_3 * vec->z; - -// result.z_1 = mat->z_1 * vec->x; -// result.z_2 = mat->z_2 * vec->y; -// result.z_3 = mat->z_3 * vec->z; - -// return result; -// } - float rse_math_deg_to_radians(float degrees) { return degrees * (PI/180.0f); diff --git a/graphics/src/rse_math.h b/graphics/src/rse_math.h index fe6163ec..7613895a 100644 --- a/graphics/src/rse_math.h +++ b/graphics/src/rse_math.h @@ -12,10 +12,6 @@ #ifndef RSE_MATH_H #define RSE_MATH_H -#ifdef __cplusplus -extern "C" { -#endif - /** * @brief Simple representation of vector * @@ -122,8 +118,5 @@ struct mat4_t rse_math_perspective(float fovy_rad, float aspect_ratio, float z_n * @return struct mat4_t resulting matrix */ struct mat4_t rse_math_rotate(struct mat4_t matrix, float radians, struct vec3_t rotation_vector); -#ifdef __cplusplus -} -#endif #endif /* RSE_MATH_H */ \ No newline at end of file diff --git a/graphics/src/rse_vulkan_commands.c b/graphics/src/rse_vulkan_commands.c index 9321c7a2..16b24c54 100644 --- a/graphics/src/rse_vulkan_commands.c +++ b/graphics/src/rse_vulkan_commands.c @@ -3,39 +3,40 @@ #include "vulkan_errors.h" #include "locale_vulkan.h" #include "utilities/logger.h" +#include "utilities/rse_errors_common.h" VkCommandPool g_command_pool = VK_NULL_HANDLE; /** * @brief Create Command Pools * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED */ -static uint8_t create_command_pools() +static rse_err_t create_command_pools() { VkCommandPoolCreateInfo create_info; create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; create_info.pNext = NULL; create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - create_info.queueFamilyIndex = g_vulkan_state.queue_family_indices[0]; /* TODO: Change when more families are needed */ + create_info.queueFamilyIndex = g_vulkan_state.queue_family_indices[0]; if (VK_SUCCESS != vkCreateCommandPool(g_vulkan_state.device, &create_info, NULL, &g_command_pool)) { - LOGF(vulkan_error_messages[VULKAN_COMMAND_POOL_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_COMMAND_POOL_CREATION_FAILED]); return VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Allocate Command Buffers * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED */ -static uint8_t allocate_command_buffers() +static rse_err_t allocate_command_buffers() { VkCommandBufferAllocateInfo allocate_info; @@ -43,16 +44,16 @@ static uint8_t allocate_command_buffers() allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocate_info.pNext = NULL; allocate_info.commandPool = g_command_pool; - allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; /* TODO: When needed, add secondary command buffer */ + allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocate_info.commandBufferCount = SWAP_BUFFER_COUNT; if (VK_SUCCESS != vkAllocateCommandBuffers(g_vulkan_state.device, &allocate_info, g_vulkan_state.command_buffers)) { - LOGF(vulkan_error_messages[VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED]); + LOGF(vulkan_messages[VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED]); return VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } VkCommandBuffer rse_begin_single_time_command() @@ -100,9 +101,9 @@ void rse_end_single_time_comands(VkCommandBuffer command_buffer) vkFreeCommandBuffers(g_vulkan_state.device, g_command_pool, 1, &command_buffer); } -uint8_t init_commands() +rse_err_t init_commands() { - uint8_t status = VULKAN_ERROR_NO_ERROR; + rse_err_t status = RSE_ERROR_NO_ERROR; STATUS_CHECK(create_command_pools()); STATUS_CHECK(allocate_command_buffers()); diff --git a/graphics/src/rse_vulkan_commands.h b/graphics/src/rse_vulkan_commands.h index 838d4c54..2da268ae 100644 --- a/graphics/src/rse_vulkan_commands.h +++ b/graphics/src/rse_vulkan_commands.h @@ -14,11 +14,33 @@ #include "vulkan_commons.h" #include "vk_mem_alloc.h" +#include "utilities/rse_commons.h" -uint8_t init_commands(); +/** + * @brief Initialize vulkan commands pools and sets + * + * @return rse_err_t RSE_ERROR_NO_ERROR on success + */ +rse_err_t init_commands(); + +/** + * @brief Destroy vulkan commands sets and pools + * + */ void destroy_commands(); +/** + * @brief Helper function, creates command buffer for recording a command. Useful for copying buffer na images. + * + * @return VkCommandBuffer Created command buffer, ready to be filled with commands. + */ VkCommandBuffer rse_begin_single_time_command(); + +/** + * @brief Close command buffer and execute recorded command. + * + * @param command_buffer Command buffer for execution + */ void rse_end_single_time_comands(VkCommandBuffer command_buffer); #endif /* RSE_VULKAN_COMMANDS_H */ \ No newline at end of file diff --git a/graphics/src/rse_vulkan_image.c b/graphics/src/rse_vulkan_image.c index 44c01e87..7b1f8cc5 100644 --- a/graphics/src/rse_vulkan_image.c +++ b/graphics/src/rse_vulkan_image.c @@ -2,6 +2,7 @@ #include "utilities/file_utils.h" #include "utilities/logger.h" +#include "utilities/rse_errors_common.h" #include "locale_vulkan.h" #include "vulkan_errors.h" #include "rse_vulkan_commands.h" @@ -42,7 +43,7 @@ struct rse_vulkan_image_t g_depth_image; VkSampler g_sampler; -static uint8_t create_sampler() +static rse_err_t create_sampler() { VkSamplerCreateInfo create_info = {0}; @@ -73,17 +74,14 @@ static uint8_t create_sampler() return 1; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } -// static uint8_t has_stencil_component(VkFormat format) { -// return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT; -// } - -static VkFormat find_supported_format(const VkFormat* candidates, +static rse_err_t find_supported_format(const VkFormat* candidates, size_t candidates_count, VkImageTiling tiling, - VkFormatFeatureFlags features) + VkFormatFeatureFlags features, + VkFormat* found_format) { size_t i = 0U; @@ -92,20 +90,21 @@ static VkFormat find_supported_format(const VkFormat* candidates, vkGetPhysicalDeviceFormatProperties(g_vulkan_state.physical_device, candidates[i], &props); if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) { - return candidates[i]; + *found_format = candidates[i]; + return RSE_ERROR_NO_ERROR; } else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) { - return candidates[i]; + *found_format = candidates[i]; + return RSE_ERROR_NO_ERROR; } } - LOGE("Failed to find correct format"); - //FIXME: Add error handling - return 0; + LOGE(vulkan_messages[VULKAN_FORMAT_NOT_FOUND]); + return VULKAN_ERROR_FORMAT_NOT_FOUND; } -static uint8_t create_depth_resources() +static rse_err_t create_depth_resources() { - uint8_t status = VULKAN_ERROR_NO_ERROR; + rse_err_t status = RSE_ERROR_NO_ERROR; VkFormat depth_format = {0}; VkExtent3D image_extent = {0}; VkImageCreateInfo image_info = {0}; @@ -114,7 +113,7 @@ static uint8_t create_depth_resources() VkSurfaceCapabilitiesKHR physical_device_surface_capabilities; - depth_format = find_depth_format(); + STATUS_CHECK(find_depth_format(&depth_format)); vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_vulkan_state.physical_device, g_vulkan_state.surface, &physical_device_surface_capabilities); @@ -156,8 +155,8 @@ static uint8_t create_depth_resources() &g_depth_image.image, &g_depth_image.allocation, &g_depth_image.allocation_info)) { - LOGF("Failed to create image"); - return -1; + LOGF(vulkan_messages[VULKAN_IMAGE_NOT_CREATED]); + return VULKAN_ERROR_IMAGE_NOT_CREATED; } image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -180,19 +179,20 @@ static uint8_t create_depth_resources() &image_view_create_info, NULL, &g_depth_image.image_view)) { - LOGF(vulkan_error_messages[VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED]); return VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED; } - return status; + return RSE_ERROR_NO_ERROR; } -static VkDeviceSize format_to_pixel_size(VkFormat format) +static rse_err_t format_to_pixel_size(VkFormat format, + VkDeviceSize* format_size) { switch (format) { case VK_FORMAT_R8G8B8A8_SRGB: - return 4; + *format_size = 4; break; default: @@ -200,12 +200,17 @@ static VkDeviceSize format_to_pixel_size(VkFormat format) break; } - return 0; + return RSE_ERROR_NO_ERROR; } -static int8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat format, unsigned char* pixels) +static rse_err_t create_vulkan_image(uint32_t width, + uint32_t height, + VkFormat format, + unsigned char* pixels, + uint8_t* texture_id) { + rse_err_t status = RSE_ERROR_NO_ERROR; struct rse_vulkan_buffer_t staging_buffer = {0}; VkDeviceSize staging_buffer_size = 0U; VkImageCreateInfo image_info = {0}; @@ -217,23 +222,26 @@ static int8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat form VkExtent3D image_extent = {0}; VkImageViewCreateInfo image_view_create_info = {0}; struct rse_vulkan_image_t* free_texture_image = NULL; - size_t i = 0U; + *texture_id = 0U; - while(free_texture_image == NULL || i > RSE_MAX_IMAGE_COUNT) { - if(g_texture_images[i].id_taken == IMAGE_FREE) { - free_texture_image = &g_texture_images[i]; + while(free_texture_image == NULL || *texture_id > RSE_MAX_IMAGE_COUNT) { + if(g_texture_images[*texture_id].id_taken == IMAGE_FREE) { + free_texture_image = &g_texture_images[*texture_id]; } else { - ++i; + *texture_id += 1; } } /* Check if we found free image handle */ if (free_texture_image == NULL) { - LOGE("Failed to find free texture image handle"); - return -1; + LOGE(vulkan_messages[VULKAN_MAX_TEXTURE_COUNT_REACHED]); + *texture_id = -1; + return VULKAN_ERROR_MAX_TEXTURE_COUNT_REACHED; } - staging_buffer_size = width * height * format_to_pixel_size(format); + STATUS_CHECK(format_to_pixel_size(format, &staging_buffer_size)); + + staging_buffer_size = staging_buffer_size * width * height; image_extent.width = width; image_extent.height = height; @@ -270,8 +278,8 @@ static int8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat form &free_texture_image->image, &free_texture_image->allocation, &free_texture_image->allocation_info)) { - LOGF("Failed to create image"); - return -1; + LOGF(vulkan_messages[VULKAN_IMAGE_NOT_CREATED]); + return VULKAN_ERROR_IMAGE_NOT_CREATED; } /* Put image into correct layout to copy pixels from buffer to image memory */ @@ -306,15 +314,12 @@ static int8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat form rse_end_single_time_comands(command_buffer); /* Copy pixel data to GPU memory */ - if (VK_SUCCESS != create_buffer(staging_buffer_size, + STATUS_CHECK(create_buffer(staging_buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, - &staging_buffer)) { - LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]); - return -1; - } + &staging_buffer)); memcpy(staging_buffer.allocation_info.pMappedData, pixels, staging_buffer_size); @@ -376,17 +381,17 @@ static int8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat form &image_view_create_info, NULL, &free_texture_image->image_view)) { - LOGF("Failed to create image view"); - return -1; + LOGF(vulkan_messages[VULKAN_IMAGE_VIEW_NOT_CREATED]); + return VULKAN_ERROR_IMAGE_VIEW_NOT_CREATED; } free_texture_image->id_taken = IMAGE_TAKEN; - return i; + return RSE_ERROR_NO_ERROR; } -uint8_t init_vulkan_images() +rse_err_t init_vulkan_images() { - uint8_t status = VULKAN_ERROR_NO_ERROR; + rse_err_t status = RSE_ERROR_NO_ERROR; STATUS_CHECK(create_sampler()); STATUS_CHECK(create_depth_resources()); @@ -394,16 +399,14 @@ uint8_t init_vulkan_images() return status; } -int8_t rse_load_texture(const char* file_path) +rse_err_t rse_load_texture(const char* file_path, uint8_t* texture_id) { + rse_err_t status = RSE_ERROR_NO_ERROR; int width = 0; int height = 0; int channels = 0; stbi_uc* pixel_buffer = NULL; - int8_t ret; - - pixel_buffer = stbi_load(file_path, &width, &height, &channels, STBI_rgb_alpha); if (pixel_buffer == NULL) { @@ -412,14 +415,14 @@ int8_t rse_load_texture(const char* file_path) } /* Create actual Vulkan Image */ - ret = create_vulkan_image(width, + status = create_vulkan_image(width, height, VK_FORMAT_R8G8B8A8_SRGB, - pixel_buffer); + pixel_buffer, texture_id); stbi_image_free(pixel_buffer); - return ret; + return status; } @@ -440,7 +443,7 @@ void rse_destroy_textures() vmaDestroyImage(g_vulkan_state.allocator, g_depth_image.image, g_depth_image.allocation); } -int8_t image_exists(uint8_t image_id) { +uint8_t image_exists(uint8_t image_id) { return g_texture_images[image_id].id_taken == IMAGE_TAKEN; } @@ -474,16 +477,20 @@ size_t get_textures_count() return count; } -VkFormat find_depth_format() +rse_err_t find_depth_format(VkFormat* found_format) { #define formats_count 3 + rse_err_t status; VkFormat formats[formats_count] = {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}; - return find_supported_format( + STATUS_CHECK(find_supported_format( formats, formats_count, VK_IMAGE_TILING_OPTIMAL, - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT - ); + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, + found_format + )); + + return status; #undef formats_count } \ No newline at end of file diff --git a/graphics/src/rse_vulkan_image.h b/graphics/src/rse_vulkan_image.h index e705061a..7e9dd96a 100644 --- a/graphics/src/rse_vulkan_image.h +++ b/graphics/src/rse_vulkan_image.h @@ -14,6 +14,7 @@ #define RSE_TEXTURE_H #include "utilities/file_utils.h" +#include "utilities/rse_commons.h" #include "vulkan_commons.h" #include @@ -27,17 +28,18 @@ /** * @brief Initialize vulkan with image views and stuff * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success + * @return rse_err_t RSE_ERROR_NO_ERROR on success */ -uint8_t init_vulkan_images(void); +rse_err_t init_vulkan_images(void); /** * @brief Loads image from file, for later to be uysed as a texture * - * @param path Path to texture file - * @return int8_t -1 on error. Texture ID on success + * @param file_path Path to texture file + * @param texture_id Texture ID will be set up here + * @return rse_err_t RSE_ERROR_NO_ERROR on success */ -int8_t rse_load_texture(const char* path); +rse_err_t rse_load_texture(const char* file_path, uint8_t* texture_id); /** * @brief Destroy all loaded textures. Usefull for closing application or just clearing. @@ -64,9 +66,9 @@ VkSampler rse_get_texture_sampler(); * @brief Checks if image exists for provided image ID. * * @param image_id Image ID - * @return int8_t 1 on success, 0 on failure + * @return uint8_t 1 on success, 0 on failure */ -int8_t image_exists(uint8_t image_id); +uint8_t image_exists(uint8_t image_id); /** * @brief Returns number of loaded texture @@ -75,7 +77,7 @@ int8_t image_exists(uint8_t image_id); */ size_t get_textures_count(); -VkFormat find_depth_format(); +rse_err_t find_depth_format(VkFormat* found_format); VkImageView rse_get_depth_image_view(); diff --git a/graphics/src/rse_window_errors.h b/graphics/src/rse_window_errors.h new file mode 100644 index 00000000..acd52a81 --- /dev/null +++ b/graphics/src/rse_window_errors.h @@ -0,0 +1,24 @@ +/** + * @file window_errors.h + * @author Piotr Krygier (everyonecancode@gmail.com) + * @brief + * @version 0.1 + * @date 2023-10-06 + * + * @copyright Copyright (c) 2023 + * + */ + +#ifndef RSE_WINDOW_ERRORS_H +#define RSE_WINDOW_ERRORS_H + +#define RSE_WINDOW_MODULE_ID 0x0200U + +/* Error codes */ +enum rse_window_error_t { + WINDOW_ERROR_GLFW_INIT_FAILED = RSE_WINDOW_MODULE_ID, + WINDOW_ERROR_VULKAN_NOT_LOADED, + WINDOW_ERROR_WINDOW_NOT_CREATED +}; + +#endif /* RSE_WINDOW_ERRORS_H */ \ No newline at end of file diff --git a/graphics/src/shaders/shader.frag b/graphics/src/shaders/shader.frag index 9784f2dc..64b5b629 100644 --- a/graphics/src/shaders/shader.frag +++ b/graphics/src/shaders/shader.frag @@ -1,7 +1,10 @@ #version 450 /* Each time texture count is changed this value also need to change. I have to fix it somehow. */ -layout(binding = 1) uniform sampler2D texSampler[1]; + +#extension GL_EXT_nonuniform_qualifier : enable + +layout(set = 1, binding = 1) uniform sampler2D texSampler[]; layout(location = 0) in vec3 fragColor; layout(location = 1) in vec2 fragTexCoord; diff --git a/graphics/src/vulkan_base.c b/graphics/src/vulkan_base.c index 292a1ff5..713f12d4 100644 --- a/graphics/src/vulkan_base.c +++ b/graphics/src/vulkan_base.c @@ -11,23 +11,26 @@ #include "vulkan_base.h" -#include "vulkan_errors.h" #include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wpedantic" -#pragma GCC diagnostic ignored "-Wignored-qualifiers" -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" -#pragma GCC diagnostic ignored "-Wswitch" -#pragma GCC diagnostic ignored "-Wparentheses" +/* We are building with -Werror flag on, but there are some warning in VMA implementation. Thus diagnostic push */ +// #pragma GCC diagnostic push +// #pragma GCC diagnostic ignored "-Wunused-function" +// #pragma GCC diagnostic ignored "-Wunused-variable" +// #pragma GCC diagnostic ignored "-Wpedantic" +// #pragma GCC diagnostic ignored "-Wignored-qualifiers" +// #pragma GCC diagnostic ignored "-Wmissing-field-initializers" +// #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +// #pragma GCC diagnostic ignored "-Wswitch" +// #pragma GCC diagnostic ignored "-Wparentheses" #include "vk_mem_alloc.h" -#pragma GCC diagnostic pop +// #pragma GCC diagnostic pop #include "locale_vulkan.h" +#include "utilities/locale_common.h" +#include "utilities/rse_errors_common.h" #include "utilities/logger.h" +#include "vulkan_errors.h" #include "window.h" #include "vulkan_commons.h" @@ -73,60 +76,7 @@ VkSemaphore g_render_finished_semaphores[SWAP_BUFFER_COUNT] = {}; VkFence g_in_flight_fences[SWAP_BUFFER_COUNT] = {}; - #ifndef NDEBUG -static void setup_debug_messenger(); -static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, - VkDebugUtilsMessageTypeFlagsEXT message_type, - const VkDebugUtilsMessengerCallbackDataEXT* callback_data, - void* user_data); - -static VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* create_info, - const VkAllocationCallbacks* allocator, - VkDebugUtilsMessengerEXT* debug_messenger); - -static void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debug_messenger, - const VkAllocationCallbacks* allocator); -#endif - - - -static void set_enabled_extension(); -static uint8_t create_instance(); -static uint8_t create_surface(); -static uint8_t pick_physical_device(); -static uint8_t create_device(); -static uint8_t create_memory_allocator(); - -static uint8_t create_sync_objects(); - - - -#ifndef NDEBUG -/** - * @brief Setup debugging system for Vulkan API - * - */ -void setup_debug_messenger() -{ - VkDebugUtilsMessengerCreateInfoEXT create_info; - - 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_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; - create_info.pfnUserCallback = debug_callback; - create_info.pUserData = NULL; // Optional - create_info.flags = 0U; - - if (CreateDebugUtilsMessengerEXT(g_vulkan_instance, &create_info, NULL, &g_debug_messenger) != VK_SUCCESS) { - fprintf(stderr, "failed to set up debug messenger!"); - } -} /** * @brief Calback for debug messenger @@ -137,15 +87,29 @@ void setup_debug_messenger() * @param user_data Data provided by the user * @return VkBool32 Should always return VK_FALSE. The VK_TRUE value is reserved for use in layer development */ -VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, +static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type, const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { + enum log_level_t log_level = LOGLEVEL_TRACE; (void)message_severity; (void)message_type; (void)user_data; - LOGD(callback_data->pMessage); + /* There is no guarantee, that the error message will have single severity flag set, so we can't use switch() + * here. We have to check flags and set severity to most important one */ + + if (message_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + log_level = LOGLEVEL_ERROR; + } else if (message_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + log_level = LOGLEVEL_WARNING; + } else if (message_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { + log_level = LOGLEVEL_INFO; + } else if (message_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { + log_level = LOGLEVEL_TRACE; + } + + LOGGER(log_level, callback_data->pMessage); return VK_FALSE; } @@ -159,7 +123,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBit * @param debug_messenger Debug messanger handle * @return VkResult VK_SUCCESS on success */ -VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* create_info, +static VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* create_info, const VkAllocationCallbacks* allocator, VkDebugUtilsMessengerEXT* debug_messenger) { @@ -175,6 +139,34 @@ VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMes return VK_SUCCESS; } +/** + * @brief Setup debugging system for Vulkan API + * + */ +static rse_err_t setup_debug_messenger() +{ + VkDebugUtilsMessengerCreateInfoEXT create_info = {0}; + + 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_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; + create_info.pfnUserCallback = debug_callback; + create_info.pUserData = NULL; // Optional + create_info.flags = 0U; + + if (CreateDebugUtilsMessengerEXT(g_vulkan_instance, &create_info, NULL, &g_debug_messenger) != VK_SUCCESS) { + LOGF(vulkan_messages[VULKAN_DEBUG_MESSENGER_SETUP_FAILED]); + return VULKAN_ERROR_DEBUG_MESSENGER_CREATION_FAILED; + } + + return RSE_ERROR_NO_ERROR; +} + /** * @brief Proxy for vkDestroyDebugUtilsMessengerEXT * @@ -182,7 +174,7 @@ VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMes * @param debug_messenger Debug messanger handle * @param allocator Memory allocator */ -void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debug_messenger, +static void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debug_messenger, const VkAllocationCallbacks* allocator) { PFN_vkDestroyDebugUtilsMessengerEXT func = @@ -192,13 +184,13 @@ void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT } } -#endif +#endif /* DEBUG */ /** * @brief Enable instance extensions, based on system and requirements * */ -void set_enabled_extension() +static void set_enabled_extension() { g_enabled_instance_extensions_names[0] = "VK_KHR_surface"; g_enabled_instance_extensions_names[1] = "VK_KHR_device_group_creation"; @@ -210,49 +202,54 @@ void set_enabled_extension() g_enabled_instance_extensions_names[2] = "VK_KHR_xcb_surface"; } #elif defined(_WIN32) || defined(WIN32) - g_enabled_instance_extensions_names.push_back("VK_KHR_win32_surface"); + g_enabled_instance_extensions_names[2] = "VK_KHR_win32_surface"; #endif +/* Add custom extensions here and make VK_EXT_debug_utils last */ + +/* ----------------------------------------------------------- */ + #ifndef NDEBUG g_enabled_instance_extensions_names[3] = "VK_EXT_debug_utils"; #endif + }; /** * @brief Create the Vulkan Instance object * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_INSTANCE_INIT_FAILED */ -uint8_t create_instance() +static rse_err_t create_instance() { - size_t i; - size_t j; - uint8_t supported = 0; - uint32_t extensionCount = 0; - uint32_t layersCount = 0; - VkApplicationInfo application_info = {}; - VkInstanceCreateInfo create_info = {}; + size_t i = 0U; + size_t j = 0U; + uint8_t supported = 0U; + uint32_t extensionCount = 0U; + uint32_t layersCount = 0U; + VkApplicationInfo application_info = {0}; + VkInstanceCreateInfo create_info = {0}; VkLayerProperties* layer_properties; VkExtensionProperties* extensions_properties; vkEnumerateInstanceLayerProperties(&layersCount, NULL); - layer_properties = malloc(sizeof(VkLayerProperties) * layersCount); + rse_malloc(layer_properties, sizeof(VkLayerProperties) * layersCount); vkEnumerateInstanceLayerProperties(&layersCount, layer_properties); vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL); - extensions_properties = malloc(sizeof(VkExtensionProperties) * extensionCount); + rse_malloc(extensions_properties, sizeof(VkExtensionProperties) * extensionCount); vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensions_properties); #ifndef NDEBUG - LOGD("Supported Layers"); + LOGD("Supported Layers: \n"); for (i = 0; i < layersCount; i++) { - LOGD("%s", layer_properties[i].layerName); + LOGD("\t-%s\n", layer_properties[i].layerName); } - LOGD("Supported Extensions"); + LOGD("Supported Extensions: \n"); for (size_t i = 0; i < extensionCount; i++) { - LOGD("%s", extensions_properties[i].extensionName); + LOGD("\t-%s\n", extensions_properties[i].extensionName); } #endif @@ -264,14 +261,13 @@ uint8_t create_instance() break; } } + if(supported == 0) { + LOGF(vulkan_messages[VULKAN_LAYER_NOT_SUPPORTED], layer_properties[j].layerName); + return VULKAN_ERROR_LAYER_NOT_SUPPORTED; + } + supported = 0; } - if(supported == 0) { - LOGF(vulkan_error_messages[VULKAN_LAYER_NOT_SUPPORTED], layer_properties[j].layerName); - return VULKAN_ERROR_LAYER_NOT_SUPPORTED; - } - supported = 0; - /* Check if selected extensions are supported*/ for (i = 0; i < ENABLED_EXTENSIONS_COUT; ++i) { for(j = 0; j < extensionCount; ++j) { @@ -280,10 +276,11 @@ uint8_t create_instance() break; } } - } - if(supported == 0) { - LOGF(vulkan_error_messages[VULKAN_EXTENSION_NOT_SUPPORTED], extensions_properties[j].extensionName); - return VULKAN_ERROR_EXTENSION_NOT_SUPPORTED; + if(supported == 0) { + LOGF(vulkan_messages[VULKAN_EXTENSION_NOT_SUPPORTED], extensions_properties[j].extensionName); + return VULKAN_ERROR_EXTENSION_NOT_SUPPORTED; + } + supported = 0; } application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -309,36 +306,35 @@ uint8_t create_instance() VkResult result = vkCreateInstance(&create_info, NULL, &g_vulkan_instance); if (VK_SUCCESS != result) { - LOGF(vulkan_error_messages[VULKAN_INTANCE_INIT_FAILED]); + LOGF(vulkan_messages[VULKAN_INTANCE_INIT_FAILED]); return VULKAN_ERROR_INSTANCE_INIT_FAILED; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Create a Surface, connection between Vulkan and actual window * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: */ -uint8_t create_surface() +static rse_err_t create_surface() { if (VK_SUCCESS != glfwCreateWindowSurface(g_vulkan_instance, get_window_handle(), NULL, &g_vulkan_state.surface)) { - LOGF(vulkan_error_messages[VULKAN_SURFACE_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_SURFACE_CREATION_FAILED]); return VULKAN_ERROR_SURFACE_CREATION_FAILED; } - - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Choose physical device. Used later for vkDevice * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND * VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND */ -uint8_t pick_physical_device() +static rse_err_t pick_physical_device() { uint32_t physical_device_count = 0U; VkPhysicalDevice* physical_devices = NULL; @@ -349,11 +345,12 @@ uint8_t pick_physical_device() vkEnumeratePhysicalDevices(g_vulkan_instance, &physical_device_count, NULL); if (0 == physical_device_count) { - LOGF(vulkan_error_messages[VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND]); + LOGF(vulkan_messages[VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND]); return VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND; } - physical_devices = malloc(sizeof(VkPhysicalDevice) * physical_device_count); + rse_malloc(physical_devices, sizeof(VkPhysicalDevice) * physical_device_count); + vkEnumeratePhysicalDevices(g_vulkan_instance, &physical_device_count, physical_devices); /* Check for suitability */ @@ -373,35 +370,36 @@ uint8_t pick_physical_device() if (VK_NULL_HANDLE == g_vulkan_state.physical_device) { /* No suitable device found */ - LOGF(vulkan_error_messages[VULKAN_NO_SUITABLE_PHYSICAL_DEVICES]); + LOGF(vulkan_messages[VULKAN_NO_SUITABLE_PHYSICAL_DEVICES]); return VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Create vkDevice object * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_QUEUE_NOT_SUPPORTED * VULKAN_ERROR_DEVICE_CREATION_FAILED */ -uint8_t create_device() +static rse_err_t create_device() { size_t device_queues_count = 0; uint32_t queue_families_property_count = 0U; ssize_t graphics_family_idx = -1; ssize_t presentation_familiy_idx = -1; VkQueueFamilyProperties* queue_family_properties = NULL; - VkDeviceCreateInfo device_create_info = {}; - VkDeviceQueueCreateInfo device_queue_createinfos[2] = {}; /* TODO: Change when we want more queues */ + VkDeviceCreateInfo device_create_info = {0}; + VkDeviceQueueCreateInfo device_queue_createinfos[2] = {0}; float* graphics_familiy_queue_priorities = NULL; float* presentation_familiy_queue_priorities = NULL; VkPhysicalDeviceFeatures2 physical_features2 = {0}; VkPhysicalDeviceDescriptorIndexingFeatures indexing_features = {0}; VkBool32 bindless_supported = VK_FALSE; + /* Enable descriptori indexing for bindless textures */ indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; physical_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; @@ -411,13 +409,13 @@ uint8_t create_device() bindless_supported = indexing_features.descriptorBindingPartiallyBound && indexing_features.runtimeDescriptorArray; if (bindless_supported == VK_FALSE) { - LOGE("This engine requires bindless support"); - return 1; + LOGF(vulkan_messages[VULKAN_BINDLESS_DESIGN_NOT_SUPPORTED]); + return VULKAN_ERROR_MISSING_FEATURES_FOR_BINDLESS_DESIGN; } /* Get information about supported queue families */ vkGetPhysicalDeviceQueueFamilyProperties(g_vulkan_state.physical_device, &queue_families_property_count, NULL); - queue_family_properties = malloc(sizeof(VkQueueFamilyProperties) * queue_families_property_count); + rse_malloc(queue_family_properties, sizeof(VkQueueFamilyProperties) * queue_families_property_count); vkGetPhysicalDeviceQueueFamilyProperties(g_vulkan_state.physical_device, &queue_families_property_count, queue_family_properties); @@ -442,11 +440,9 @@ uint8_t create_device() if (presentSupport) { presentation_familiy_idx = familyIdx; /* If this is the same queue family as in graphics family, don't increase queue count */ - //TODO: This is still ugly, but fixes an error. Change later. if (presentation_familiy_idx != graphics_family_idx) { device_queues_count++; } - LOGI("Setting present family idx to %d", familyIdx); } if (graphics_family_idx > 0 && presentation_familiy_idx > 0) { @@ -457,21 +453,22 @@ uint8_t create_device() /* This is not magic number ;P. We want to support exact number of required queues flags */ if (0 > graphics_family_idx) { - LOGF(vulkan_error_messages[VULKAN_QUEUE_NOT_SUPPORTED]); + LOGF(vulkan_messages[VULKAN_QUEUE_NOT_SUPPORTED]); return VULKAN_ERROR_QUEUE_NOT_SUPPORTED; } - g_vulkan_state.queue_family_indices[0] = graphics_family_idx; /* TODO: Change when more families are needed */ + g_vulkan_state.queue_family_indices[0] = graphics_family_idx; + + rse_malloc(graphics_familiy_queue_priorities, sizeof(float) * queue_family_properties[graphics_family_idx].queueCount); - graphics_familiy_queue_priorities = malloc(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; /* TODO: When queues have different tasks, change this if needed */ + graphics_familiy_queue_priorities[i] = 1.0f; } - presentation_familiy_queue_priorities = malloc(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; /* TODO: When queues have different tasks, change this if needed */ + 1.0f; } device_queue_createinfos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; @@ -497,27 +494,26 @@ uint8_t create_device() device_create_info.ppEnabledLayerNames = NULL; device_create_info.enabledExtensionCount = ENABLED_DEVICE_EXTENSIONS_COUT; device_create_info.ppEnabledExtensionNames = g_enabled_device_extensions_names; - device_create_info.pEnabledFeatures = NULL; /* TODO: Enable features, when needed */ - + device_create_info.pEnabledFeatures = NULL; if (VK_SUCCESS != vkCreateDevice(g_vulkan_state.physical_device, &device_create_info, NULL, &g_vulkan_state.device)) { - LOGF(vulkan_error_messages[VULKAN_FAILED_TO_CREATE_DEVICE]); + LOGF(vulkan_messages[VULKAN_FAILED_TO_CREATE_DEVICE]); return VULKAN_ERROR_DEVICE_CREATION_FAILED; } vkGetDeviceQueue(g_vulkan_state.device, graphics_family_idx, 0, &g_vulkan_state.graphics_queue); vkGetDeviceQueue(g_vulkan_state.device, presentation_familiy_idx, 0, &g_present_queue); - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Create a Memory Allocator object * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_ALLOCATOR_CREATION_FAILED */ -uint8_t create_memory_allocator() +static rse_err_t create_memory_allocator() { VmaVulkanFunctions vulkan_functions = {0}; vulkan_functions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr; @@ -531,21 +527,21 @@ uint8_t create_memory_allocator() allocator_create_info.pVulkanFunctions = &vulkan_functions; if (VK_SUCCESS != vmaCreateAllocator(&allocator_create_info, &g_vulkan_state.allocator)) { - LOGF(vulkan_error_messages[VULKAN_ERROR_ALLOCATOR_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_ERROR_ALLOCATOR_CREATION_FAILED]); return VULKAN_ERROR_ALLOCATOR_CREATION_FAILED; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Create a Sync Objects * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_SYNCOBJCTS_CREATION_FAILED */ -uint8_t create_sync_objects() +static rse_err_t create_sync_objects() { VkSemaphoreCreateInfo semaphore_info = {}; semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; @@ -558,23 +554,23 @@ uint8_t create_sync_objects() if (VK_SUCCESS != vkCreateSemaphore(g_vulkan_state.device, &semaphore_info, NULL, &g_image_available_semaphores[i]) || VK_SUCCESS != vkCreateSemaphore(g_vulkan_state.device, &semaphore_info, NULL, &g_render_finished_semaphores[i]) || VK_SUCCESS != vkCreateFence(g_vulkan_state.device, &fenceInfo, NULL, &g_in_flight_fences[i])) { - LOGF(vulkan_error_messages[VULKAN_SYNCOBJCTS_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_SYNCOBJCTS_CREATION_FAILED]); return VULKAN_ERROR_SYNCOBJCTS_CREATION_FAILED; } } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } -uint8_t preinit_vulkan() +rse_err_t preinit_vulkan() { - uint8_t status = VULKAN_ERROR_NO_ERROR; + rse_err_t status = RSE_ERROR_NO_ERROR; set_enabled_extension(); STATUS_CHECK(create_instance()); #ifndef NDEBUG - setup_debug_messenger(); + STATUS_CHECK(setup_debug_messenger()); #endif STATUS_CHECK(create_surface()); STATUS_CHECK(pick_physical_device()); @@ -587,27 +583,28 @@ uint8_t preinit_vulkan() return status; } -uint8_t init_vulkan() +rse_err_t init_vulkan() { - uint8_t status = VULKAN_ERROR_NO_ERROR; + rse_err_t status = RSE_ERROR_NO_ERROR; STATUS_CHECK(create_pipeline()); STATUS_CHECK(create_descriptors()); STATUS_CHECK(create_sync_objects()); rse_init_time(); + return status; } -void draw_frame() +rse_err_t draw_frame() { uint32_t image_index = 0U; VkResult result = VK_FALSE; - VkSubmitInfo submit_info = {}; - VkSemaphore wait_semaphores[1]; //TODO: Increase when needed + VkSubmitInfo submit_info = {0}; + VkSemaphore wait_semaphores[1]; VkPipelineStageFlags wait_stages[1]; VkSemaphore signal_semaphores[1]; - VkPresentInfoKHR present_info = {}; + VkPresentInfoKHR present_info = {0}; VkSwapchainKHR swap_chains[1]; vkWaitForFences(g_vulkan_state.device, 1, &g_in_flight_fences[g_vulkan_state.current_frame], VK_TRUE, UINT64_MAX); @@ -619,10 +616,10 @@ void draw_frame() if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { recreate_swapchain(); - return; + return RSE_ERROR_NO_ERROR; } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - // throw std::runtime_error("failed to acquire swap chain image!"); - return; + LOGF(vulkan_messages[VULKAN_ACQUIRE_SWAPCHAIN_FAILED]); + return VULKAN_ERROR_ACQUIRE_SWAPCHAIN_FAILED; } update_uniform_buffers(); @@ -633,7 +630,6 @@ void draw_frame() record_command_buffer(image_index); - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; wait_semaphores[0] = g_image_available_semaphores[g_vulkan_state.current_frame]; @@ -650,11 +646,10 @@ void draw_frame() submit_info.pSignalSemaphores = signal_semaphores; if (vkQueueSubmit(g_vulkan_state.graphics_queue, 1, &submit_info, g_in_flight_fences[g_vulkan_state.current_frame]) != VK_SUCCESS) { - LOGF(vulkan_error_messages[VULAKN_DRAW_FAILED]); - return; + LOGF(vulkan_messages[VULAKN_DRAW_FAILED]); + return VULKAN_ERROR_DRAW_FAILED; } - present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present_info.waitSemaphoreCount = 1; @@ -669,6 +664,8 @@ void draw_frame() vkQueuePresentKHR(g_present_queue, &present_info); g_vulkan_state.current_frame = (g_vulkan_state.current_frame + 1) % SWAP_BUFFER_COUNT; + + return RSE_ERROR_NO_ERROR; } void deinit_vulkan() diff --git a/graphics/src/vulkan_base.h b/graphics/src/vulkan_base.h index 7b7d7ef4..12a72792 100644 --- a/graphics/src/vulkan_base.h +++ b/graphics/src/vulkan_base.h @@ -17,35 +17,33 @@ #include #include "vulkan_commons.h" +#include "utilities/rse_commons.h" /** * @brief Initialize Vulkan backend for buffers and stuff * - * @param state - * @return uint8_t 0 on success. Status code on failure + * @return rse_err_t 0 on success. Status code on failure */ -uint8_t preinit_vulkan(); +rse_err_t preinit_vulkan(); /** * @brief Initialize Vulkan backend with descriptors * - * @param state - * @return uint8_t 0 on success. Status code on failure + * @return rse_err_t 0 on success. Status code on failure */ -uint8_t init_vulkan(); +rse_err_t init_vulkan(); /** * @brief Deinitialize Vulkan backend * - * @param state - */ + * */ void deinit_vulkan(); /** * @brief Draw frame on the screen. * - * @param state + * @return rse_err_t */ -void draw_frame(); +rse_err_t draw_frame(); #endif /* RSE_GRAPHICS_VULKANBASE_HPP */ \ No newline at end of file diff --git a/graphics/src/vulkan_buffers.c b/graphics/src/vulkan_buffers.c index 8aa3d49e..28f080c4 100644 --- a/graphics/src/vulkan_buffers.c +++ b/graphics/src/vulkan_buffers.c @@ -3,6 +3,7 @@ #include "vulkan_errors.h" #include "locale_vulkan.h" #include "utilities/logger.h" +#include "utilities/rse_errors_common.h" #include "mesh_controller.h" #include "rse_math.h" #include "rse_vulkan_commands.h" @@ -48,57 +49,54 @@ static void copy_buffer(VkBuffer src, VkBuffer dst, VkDeviceSize size, VkDeviceS /** * @brief Create a buffer holding all vertex data * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_BUFFER_CREATION_FAILED * VULKAN_ERROR_VERTEX_BUFFER_MAPPING_FAILED */ -static uint8_t create_vertex_buffer() +static rse_err_t create_vertex_buffer() { + rse_err_t status = RSE_ERROR_NO_ERROR; VkDeviceSize buffer_size; buffer_size = MAX_VERTEX_BUFFER_SIZE; /* Create Vertex Buffer*/ - if (VK_SUCCESS != create_buffer(buffer_size, + STATUS_CHECK(create_buffer(buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0, /* Will not be mapped with vmaMapMemory */ - &g_vertex_buffer)) { - LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]); - return VULKAN_ERROR_BUFFER_CREATION_FAILED; - } + &g_vertex_buffer)); g_vertex_buffer.allocated_size = 0; - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Create an index buffer, connected with vertex buffer * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_BUFFER_CREATION_FAILED */ -static uint8_t create_index_buffer() +static rse_err_t create_index_buffer() { + rse_err_t status = RSE_ERROR_NO_ERROR; VkDeviceSize buffer_size; buffer_size = MAX_VERTEX_BUFFER_SIZE; /* Create Index Buffer*/ - if (VK_SUCCESS != create_buffer(buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + STATUS_CHECK(create_buffer(buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0, /* Will not be mapped with vmaMapMemory */ - &g_index_buffer)) { - LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]); - return VULKAN_ERROR_BUFFER_CREATION_FAILED; - } + &g_index_buffer)); g_index_buffer.allocated_size = 0; - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } -static uint8_t create_instance_buffers() +static rse_err_t create_instance_buffers() { + rse_err_t status = RSE_ERROR_NO_ERROR; size_t iter = 0U; VkDeviceSize buffer_size; @@ -106,51 +104,45 @@ static uint8_t create_instance_buffers() for (iter = 0; iter < MAX_MESH_NUMBER; ++iter) { /* Create Instance Buffer */ - if (VK_SUCCESS != create_buffer(buffer_size, + STATUS_CHECK(create_buffer(buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0, /* Will not be mapped with vmaMapMemory */ - &g_instance_buffers[iter])) { - LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]); - return VULKAN_ERROR_BUFFER_CREATION_FAILED; - } + &g_instance_buffers[iter])); g_instance_buffers[iter].allocated_size = 0; } - if (VK_SUCCESS != create_buffer(sizeof(VkDrawIndexedIndirectCommand) * MAX_MESH_NUMBER, + STATUS_CHECK(create_buffer(sizeof(VkDrawIndexedIndirectCommand) * MAX_MESH_NUMBER, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, - &g_draw_indirect_command_buffer)) { - LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]); - return VULKAN_ERROR_BUFFER_CREATION_FAILED; - } - return VULKAN_ERROR_NO_ERROR; - + &g_draw_indirect_command_buffer)); + return RSE_ERROR_NO_ERROR; } /** * @brief Create a Uniform Buffers * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. */ -static uint8_t create_uniform_buffer() +static rse_err_t create_uniform_buffer() { + rse_err_t status = RSE_ERROR_NO_ERROR; VkDeviceSize buffer_size = sizeof(struct rse_uniform_buffer_object_t); for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) { - create_buffer(buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, + STATUS_CHECK(create_buffer(buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, - &g_vulkan_state.uniform_buffers[i]); + &g_vulkan_state.uniform_buffers[i])); } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } -uint8_t create_buffer(const VkDeviceSize size, +rse_err_t create_buffer(const VkDeviceSize size, VkBufferUsageFlags buffer_usage, VmaMemoryUsage memory_usage, const VmaAllocationCreateFlags allocation_flags, @@ -183,11 +175,11 @@ uint8_t create_buffer(const VkDeviceSize size, &buffer->buffer, &buffer->allocation, &buffer->allocation_info)) { - LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_BUFFER_CREATION_FAILED]); return VULKAN_ERROR_BUFFER_CREATION_FAILED; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } void destroy_buffer(struct rse_vulkan_buffer_t* buffer) @@ -224,12 +216,13 @@ void update_uniform_buffers() memcpy(g_vulkan_state.uniform_buffers[g_vulkan_state.current_frame].allocation_info.pMappedData, &ubo, sizeof(ubo)); } -uint8_t rse_add_vertices(uint16_t mesh_id, +rse_err_t rse_add_vertices(uint16_t mesh_id, const struct rse_vertex_t* vertices, const uint16_t* indices, struct rse_buffer_data_t* vertex_data, struct rse_buffer_data_t* index_data) { + rse_err_t status = RSE_ERROR_NO_ERROR; VkDrawIndexedIndirectCommand draw_indirect_command; struct rse_vulkan_buffer_t staging_buffer; size_t vertices_size = sizeof(vertices[0]) * vertex_data->count; @@ -238,15 +231,12 @@ uint8_t rse_add_vertices(uint16_t mesh_id, struct rse_vulkan_buffer_t* index_buffer = &g_index_buffer; /* Creating staging buffer*/ - if (VK_SUCCESS != create_buffer(MAX_VERTEX_BUFFER_SIZE, + STATUS_CHECK(create_buffer(MAX_VERTEX_BUFFER_SIZE, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, - &staging_buffer)) { - LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]); - return VULKAN_ERROR_BUFFER_CREATION_FAILED; - } + &staging_buffer)); /* Fill staging buffer with vertex data */ memset(staging_buffer.allocation_info.pMappedData, 0, MAX_VERTEX_BUFFER_SIZE); @@ -280,26 +270,24 @@ uint8_t rse_add_vertices(uint16_t mesh_id, memcpy(g_draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), &draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand)); - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } -uint8_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* instance_data) +rse_err_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* instance_data) { + rse_err_t status = RSE_ERROR_NO_ERROR; VkDrawIndexedIndirectCommand draw_indirect_command; struct rse_vulkan_buffer_t staging_buffer; struct rse_vulkan_buffer_t* instance_buffer = &g_instance_buffers[mesh_id]; size_t instance_size = sizeof(struct rse_instance_data_t); /* Creating staging buffer*/ - if (VK_SUCCESS != create_buffer(MAX_VERTEX_BUFFER_SIZE, + STATUS_CHECK(create_buffer(MAX_VERTEX_BUFFER_SIZE, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, - &staging_buffer)) { - LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]); - return VULKAN_ERROR_BUFFER_CREATION_FAILED; - } + &staging_buffer)); /* Copy transformation information about instance */ memcpy(staging_buffer.allocation_info.pMappedData, instance_data, instance_size); @@ -316,7 +304,7 @@ uint8_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* inst draw_indirect_command.instanceCount++; memcpy(g_draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), &draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand)); - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** @@ -324,10 +312,10 @@ uint8_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* inst * * @param command_buffer Command buffer, that will hold commands * @param image_index Image index - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED */ -uint8_t record_command_buffer(uint32_t image_index) +rse_err_t record_command_buffer(uint32_t image_index) { VkCommandBuffer command_buffer = g_vulkan_state.command_buffers[g_vulkan_state.current_frame]; VkDescriptorSet descriptor_sets[] = {g_vulkan_state.descriptor_sets[g_vulkan_state.current_frame], @@ -352,7 +340,7 @@ uint8_t record_command_buffer(uint32_t image_index) begin_info.pInheritanceInfo = NULL; if (vkBeginCommandBuffer(command_buffer, &begin_info) != VK_SUCCESS) { - LOGF(vulkan_error_messages[VULKAN_RECORD_COMMAND_BEGIN_FAILED]); + LOGF(vulkan_messages[VULKAN_RECORD_COMMAND_BEGIN_FAILED]); return VULKAN_ERROR_RECORD_COMMAND_BEGIN_FAILED; } @@ -401,16 +389,16 @@ uint8_t record_command_buffer(uint32_t image_index) vkCmdEndRenderPass(command_buffer); if (VK_SUCCESS != vkEndCommandBuffer(command_buffer)) { - LOGF(vulkan_error_messages[VULKAN_RECORD_COMMAND_BUFFER_FAILED]); + LOGF(vulkan_messages[VULKAN_RECORD_COMMAND_BUFFER_FAILED]); return VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } -uint8_t create_buffers() +rse_err_t create_buffers() { - uint8_t status = VULKAN_ERROR_NO_ERROR; + rse_err_t status = RSE_ERROR_NO_ERROR; STATUS_CHECK(create_vertex_buffer()); STATUS_CHECK(create_index_buffer()); diff --git a/graphics/src/vulkan_buffers.h b/graphics/src/vulkan_buffers.h index 9a13c145..d7d584ec 100644 --- a/graphics/src/vulkan_buffers.h +++ b/graphics/src/vulkan_buffers.h @@ -2,6 +2,8 @@ #define RSE_VULKAN_BUFFERS_H #include "vulkan_commons.h" +#include "utilities/rse_commons.h" + #include "vk_mem_alloc.h" #include @@ -21,9 +23,9 @@ struct rse_buffer_data_t /** * @brief Create buffers needed by vulkan pipeline * - * @return uint8_t + * @return rse_err_t RSE_ERROR_NO_ERROR on success */ -uint8_t create_buffers(); +rse_err_t create_buffers(); /** * @brief Update uniform buffers @@ -38,9 +40,9 @@ void update_uniform_buffers(); * @param indices Indices to add * @param vertex_data Mutable vertex data. Count will be read and buffer offset will be set * @param index_data Mutable index data. Count will be read and buffer offset will be set - * @return uint8_t + * @return rse_err_t RSE_ERROR_NO_ERROR on success */ -uint8_t rse_add_vertices(uint16_t mesh_id, +rse_err_t rse_add_vertices(uint16_t mesh_id, const struct rse_vertex_t* vertices, const uint16_t* indices, struct rse_buffer_data_t* vertex_data, @@ -51,18 +53,18 @@ uint8_t rse_add_vertices(uint16_t mesh_id, * * @param mesh_id Mesh ID * @param instance_data Instance data - * @return uint8_t VULKAN_ERROR_NO_ERROR on success + * @return rse_err_t RSE_ERROR_NO_ERROR on success */ -uint8_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* instance_data); +rse_err_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* instance_data); /** * @brief Record commands for given image index * * @param vulkan_state * @param imageIndex - * @return uint8_t VULKAN_ERROR_NO_ERROR on success + * @return rse_err_t RSE_ERROR_NO_ERROR on success */ -uint8_t record_command_buffer(uint32_t imageIndex); +rse_err_t record_command_buffer(uint32_t imageIndex); /** * @brief Reset command buffer for current frame. @@ -87,10 +89,10 @@ void destroy_buffers(); * @param memory_usage memory usage flags (mostly VMA_MEMORY_USAGE_AUTO) * @param allocation_flags VMA allocation flags * @param buffer Buffer, that will be allocated - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED */ -uint8_t create_buffer(const VkDeviceSize size, +rse_err_t create_buffer(const VkDeviceSize size, VkBufferUsageFlags buffer_usage, VmaMemoryUsage memory_usage, const VmaAllocationCreateFlags allocation_flags, diff --git a/graphics/src/vulkan_descriptors.c b/graphics/src/vulkan_descriptors.c index 4ff1c0b3..c5b27cf3 100644 --- a/graphics/src/vulkan_descriptors.c +++ b/graphics/src/vulkan_descriptors.c @@ -2,6 +2,7 @@ #include "locale_vulkan.h" #include "utilities/logger.h" +#include "utilities/rse_errors_common.h" #include "vulkan_errors.h" #include "vulkan_commons.h" #include "rse_vulkan_image.h" @@ -12,16 +13,13 @@ VkDescriptorPool gDescriptorPool; VkDescriptorPool gDescriptorPool_bindless; -static uint8_t create_descriptor_pool(); -static uint8_t create_descriptor_sets(); - /** * @brief Create a Descriptor Pool * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED */ -uint8_t create_descriptor_pool() +static rse_err_t create_descriptor_pool() { VkDescriptorPoolSize pool_sizes[2] = {}; VkDescriptorPoolCreateInfo pool_info = {}; @@ -38,7 +36,7 @@ uint8_t create_descriptor_pool() pool_info.maxSets = (uint32_t)(SWAP_BUFFER_COUNT); if (vkCreateDescriptorPool(g_vulkan_state.device, &pool_info, NULL, &gDescriptorPool) != VK_SUCCESS) { - LOGF(vulkan_error_messages[VULKAN_DESCRIPTOR_POOL_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_DESCRIPTOR_POOL_CREATION_FAILED]); return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED; } @@ -47,19 +45,19 @@ uint8_t create_descriptor_pool() pool_info.pPoolSizes = &pool_sizes[1]; if (vkCreateDescriptorPool(g_vulkan_state.device, &pool_info, NULL, &gDescriptorPool_bindless) != VK_SUCCESS) { - LOGF(vulkan_error_messages[VULKAN_DESCRIPTOR_POOL_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_DESCRIPTOR_POOL_CREATION_FAILED]); return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Create a Descriptor Sets * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED */ -uint8_t create_descriptor_sets() +static rse_err_t create_descriptor_sets() { uint32_t max_binding = MAX_BINDLESS_RESOURCES - 1; VkDescriptorSetLayout layouts[SWAP_BUFFER_COUNT] = { @@ -90,12 +88,12 @@ uint8_t create_descriptor_sets() allocInfo_bindless.descriptorSetCount = 1; if (vkAllocateDescriptorSets(g_vulkan_state.device, &allocInfo, g_vulkan_state.descriptor_sets) != VK_SUCCESS) { - LOGF(vulkan_error_messages[VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED]); + LOGF(vulkan_messages[VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED]); return VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED; } if (vkAllocateDescriptorSets(g_vulkan_state.device, &allocInfo_bindless, &g_vulkan_state.descriptor_sets_bindless) != VK_SUCCESS) { - LOGF(vulkan_error_messages[VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED]); + LOGF(vulkan_messages[VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED]); return VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED; } @@ -138,12 +136,12 @@ uint8_t create_descriptor_sets() vkUpdateDescriptorSets(g_vulkan_state.device, 2, descriptor_writes, 0, NULL); } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } -uint8_t create_descriptors() +rse_err_t create_descriptors() { - uint8_t status = VULKAN_ERROR_NO_ERROR; + rse_err_t status = RSE_ERROR_NO_ERROR; STATUS_CHECK(create_descriptor_pool()); STATUS_CHECK(create_descriptor_sets()); diff --git a/graphics/src/vulkan_descriptors.h b/graphics/src/vulkan_descriptors.h index 07b7144f..1acfa2bf 100644 --- a/graphics/src/vulkan_descriptors.h +++ b/graphics/src/vulkan_descriptors.h @@ -2,6 +2,8 @@ #define RSE_VULKAN_DESCRIPTORS_H #include +#include "utilities/rse_commons.h" + #define MAX_BINDLESS_RESOURCES 16536 @@ -9,14 +11,13 @@ * @brief Create descriptors * * @param vulkan_state - * @return uint8_t + * @return rse_err_t RSE_ERROR_NO_ERROR on success */ -uint8_t create_descriptors(); +rse_err_t create_descriptors(); /** * @brief Destroy all descriptors * - * @param vulkan_state */ void destroy_descriptors(); diff --git a/graphics/src/vulkan_errors.h b/graphics/src/vulkan_errors.h index 76470c43..bb5e8418 100644 --- a/graphics/src/vulkan_errors.h +++ b/graphics/src/vulkan_errors.h @@ -1,21 +1,17 @@ #ifndef VULKAN_ERRORS_H #define VULKAN_ERRORS_H -/* Macro for checking status of function execution in initVulkan. Created to avoid writing boilerplate code */ -#define STATUS_CHECK(FUNC) \ - status = FUNC; \ - if (VULKAN_ERROR_NO_ERROR != status) { \ - return status; \ - } +#define RSE_VULKAN_MODULE_ID 0x0300U -enum VULKAN_ERROR +enum rse_vulkan_error_t { - VULKAN_ERROR_NO_ERROR = 0x0U, + VULKAN_ERROR_DEBUG_MESSENGER_CREATION_FAILED = RSE_VULKAN_MODULE_ID, VULKAN_ERROR_LAYER_NOT_SUPPORTED, VULKAN_ERROR_EXTENSION_NOT_SUPPORTED, VULKAN_ERROR_INSTANCE_INIT_FAILED, VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND, VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND, + VULKAN_ERROR_MISSING_FEATURES_FOR_BINDLESS_DESIGN, VULKAN_ERROR_QUEUE_NOT_SUPPORTED, VULKAN_ERROR_DEVICE_CREATION_FAILED, VULKAN_ERROR_ALLOCATOR_CREATION_FAILED, @@ -31,6 +27,7 @@ enum VULKAN_ERROR VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED, VULKAN_ERROR_RENDERPASS_CREATION_FAILED, VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED, + VULKAN_ERROR_FORMAT_NOT_FOUND, VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED, VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED, VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED, @@ -38,6 +35,12 @@ enum VULKAN_ERROR VULKAN_ERROR_RECORD_COMMAND_BEGIN_FAILED, VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED, VULKAN_ERROR_SYNCOBJCTS_CREATION_FAILED, + VULKAN_ERROR_ACQUIRE_SWAPCHAIN_FAILED, + VULKAN_ERROR_MAX_INSTANCE_COUNT_REACHED, + VULKAN_ERROR_IMAGE_NOT_CREATED, + VULKAN_ERROR_IMAGE_VIEW_NOT_CREATED, + VULKAN_ERROR_MAX_TEXTURE_COUNT_REACHED, + VULKAN_ERROR_DRAW_FAILED, }; #endif \ No newline at end of file diff --git a/graphics/src/vulkan_pipeline.c b/graphics/src/vulkan_pipeline.c index 5e56a088..5c4cac5f 100644 --- a/graphics/src/vulkan_pipeline.c +++ b/graphics/src/vulkan_pipeline.c @@ -3,6 +3,7 @@ #include "locale_vulkan.h" #include "utilities/file_utils.h" #include "utilities/logger.h" +#include "utilities/rse_errors_common.h" #include "vulkan_errors.h" #include "mesh_controller.h" #include "rse_vulkan_image.h" @@ -31,35 +32,10 @@ VkShaderModule g_shader_modules[SHADER_MODULES_COUNT]; const char* g_shader_paths[] = { -/* TODO: When changing to release and install, move those files*/ "../graphics/shaders/shader.vert.num", "../graphics/shaders/shader.frag.num", }; -VkShaderModule create_shader_module(const char* binary_data, size_t data_size); - -static uint8_t create_swapchain(); -static uint8_t create_swapchain_image_views(); -static uint8_t create_render_pass(); -static uint8_t create_descriptor_set_layout(); -static uint8_t create_pipeline_layout(); -static uint8_t create_graphics_pipeline(); -static uint8_t create_framebuffers(); - -static uint8_t fill_shader_stages(VkPipelineShaderStageCreateInfo* shader_stages); -static void fill_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state); -static void free_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state); -static void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info); -static void free_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info); -static void fill_input_assembly_info(VkPipelineInputAssemblyStateCreateInfo* input_assembly); -static void fill_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state); -static void free_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state); -static void fill_rasterization_info(VkPipelineRasterizationStateCreateInfo* rasterizer); -static void fill_multisampling_state_info(VkPipelineMultisampleStateCreateInfo* multisampling); -static void fill_color_blend_state_info(VkPipelineColorBlendStateCreateInfo* color_blending); -static void free_color_blend_info(VkPipelineColorBlendStateCreateInfo* color_blending); - - static VkVertexInputBindingDescription get_binding_description() { VkVertexInputBindingDescription binding_description; @@ -98,11 +74,10 @@ static VkVertexInputAttributeDescription* get_attribute_descriptions() * @brief Creates shader module * * @param binary_data Shader compiled code - * @return std::optional Handle to compiled shader module or nullopt + * @return rse_err_t RSE_ERROR_NO_ERROR on success */ -VkShaderModule create_shader_module(const char* binary_data, size_t data_size) +static rse_err_t create_shader_module(const char* binary_data, size_t data_size, VkShaderModule* shader_module) { - VkShaderModule shader_module; VkShaderModuleCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; @@ -111,22 +86,21 @@ VkShaderModule create_shader_module(const char* binary_data, size_t data_size) create_info.codeSize = data_size; create_info.pCode = (const uint32_t*)(binary_data); - if (VK_SUCCESS != vkCreateShaderModule(g_vulkan_state.device, &create_info, NULL, &shader_module)) { - LOGF(vulkan_error_messages[VULKAN_SHADER_UNABLE_TO_CREATE_SHADER]); - // TODO: Add error handling - return shader_module; + if (VK_SUCCESS != vkCreateShaderModule(g_vulkan_state.device, &create_info, NULL, shader_module)) { + LOGF(vulkan_messages[VULKAN_SHADER_UNABLE_TO_CREATE_SHADER]); + return VULKAN_ERROR_SHADER_CREATION_FAILED; } - return shader_module; + return RSE_ERROR_NO_ERROR; } /** * @brief Create a Swapchain * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED */ -uint8_t create_swapchain() +static rse_err_t create_swapchain() { VkSwapchainCreateInfoKHR create_info; VkSurfaceCapabilitiesKHR physical_device_surface_capabilities; @@ -150,22 +124,22 @@ uint8_t create_swapchain() create_info.flags = 0U; create_info.surface = g_vulkan_state.surface; create_info.minImageCount = SWAP_BUFFER_COUNT + 1; - create_info.imageFormat = IMAGE_FORMAT; /* TODO: Check for supported formats */ - create_info.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; /* TODO: Check for supported color space */ + create_info.imageFormat = IMAGE_FORMAT; + create_info.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; create_info.imageExtent = g_vulkan_state.swapchain_extent; create_info.imageArrayLayers = 1U; /* For non-stereoscopic-3D applications, this value is 1. */ - create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; /* TODO: Probably change later? Dunno */ + create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; /* Using only one queue family, so this is ok */ create_info.queueFamilyIndexCount = 1U; create_info.pQueueFamilyIndices = g_vulkan_state.queue_family_indices; create_info.preTransform = physical_device_surface_capabilities.currentTransform; create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; /* TODO: Choose present mode from VkPresentModeKHR */ + create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; create_info.clipped = VK_TRUE; create_info.oldSwapchain = VK_NULL_HANDLE; if (VK_SUCCESS != vkCreateSwapchainKHR(g_vulkan_state.device, &create_info, NULL, &g_vulkan_state.swapchain)) { - LOGF(vulkan_error_messages[VULKAN_SWAPCHAIN_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_SWAPCHAIN_CREATION_FAILED]); return VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED; } @@ -174,15 +148,15 @@ uint8_t create_swapchain() g_swapchain_images = (VkImage*)malloc(sizeof(VkImage) * g_swapchain_images_count); vkGetSwapchainImagesKHR(g_vulkan_state.device, g_vulkan_state.swapchain, &g_swapchain_images_count, g_swapchain_images); - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Create a Swapchain Image Views * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: */ -uint8_t create_swapchain_image_views() +static rse_err_t create_swapchain_image_views() { g_vulkan_state.swapchain_image_views = malloc(sizeof(VkImageView) * g_swapchain_images_count); for (size_t i = 0; i < g_swapchain_images_count; i++) { @@ -205,22 +179,23 @@ uint8_t create_swapchain_image_views() create_info.subresourceRange.layerCount = 1U; if (VK_SUCCESS != vkCreateImageView(g_vulkan_state.device, &create_info, NULL, &g_vulkan_state.swapchain_image_views[i])) { - LOGF(vulkan_error_messages[VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED]); return VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED; } } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Create a Render Pass * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_RENDERPASS_CREATION_FAILED */ -uint8_t create_render_pass() +static rse_err_t create_render_pass() { + rse_err_t status = RSE_ERROR_NO_ERROR; VkAttachmentDescription attachments[2] = {}; VkAttachmentDescription color_attachment = {}; VkAttachmentReference color_attachment_ref = {}; @@ -230,7 +205,8 @@ uint8_t create_render_pass() VkAttachmentReference depth_attachment_ref = {}; VkSubpassDependency dependency = {}; - depth_attachment.format = find_depth_format(); + STATUS_CHECK(find_depth_format(&depth_attachment.format)); + depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT; depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; @@ -280,19 +256,19 @@ uint8_t create_render_pass() renderpass_info.pDependencies = &dependency; if (VK_SUCCESS != vkCreateRenderPass(g_vulkan_state.device, &renderpass_info, NULL, &g_vulkan_state.render_pass)) { - LOGF(vulkan_error_messages[VULKAN_RENDERPASS_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_RENDERPASS_CREATION_FAILED]); return VULKAN_ERROR_RENDERPASS_CREATION_FAILED; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Create a Descriptor Set Layout * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. */ -uint8_t create_descriptor_set_layout() +static rse_err_t create_descriptor_set_layout() { VkDescriptorSetLayoutCreateInfo layout_info = {}; VkDescriptorSetLayoutCreateInfo layout_info_bindless = {}; @@ -328,7 +304,7 @@ uint8_t create_descriptor_set_layout() layout_info.pBindings = &bindings[0]; if (vkCreateDescriptorSetLayout(g_vulkan_state.device, &layout_info, NULL, &g_vulkan_state.descriptor_set_layout) != VK_SUCCESS) { - LOGF(vulkan_error_messages[VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED]); return VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED; } @@ -338,19 +314,19 @@ uint8_t create_descriptor_set_layout() layout_info_bindless.pBindings = &bindings[1]; if (vkCreateDescriptorSetLayout(g_vulkan_state.device, &layout_info_bindless, NULL, &g_vulkan_state.descriptor_set_layout_bindless) != VK_SUCCESS) { - LOGF(vulkan_error_messages[VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED]); return VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED; } - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** * @brief Create a Pipeline Layout * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED */ -uint8_t create_pipeline_layout() +static rse_err_t create_pipeline_layout() { VkDescriptorSetLayout set_layouts[2] = {g_vulkan_state.descriptor_set_layout, g_vulkan_state.descriptor_set_layout_bindless}; VkPipelineLayoutCreateInfo create_info = {}; @@ -363,161 +339,24 @@ uint8_t create_pipeline_layout() create_info.pPushConstantRanges = NULL; if (VK_SUCCESS != vkCreatePipelineLayout(g_vulkan_state.device, &create_info, NULL, &g_vulkan_state.pipeline_layout)) { - LOGF(vulkan_error_messages[VULKAN_PIPELAYOUT_CREATION_FAILED]); + LOGF(vulkan_messages[VULKAN_PIPELAYOUT_CREATION_FAILED]); return VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED; } - return VULKAN_ERROR_NO_ERROR; -} - -/** - * @brief Create Graphics Pipeline - * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: - * VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED - */ -uint8_t create_graphics_pipeline() -{ - uint8_t status = VULKAN_ERROR_NO_ERROR; - - VkPipelineShaderStageCreateInfo shader_stages[SHADER_MODULES_COUNT]; - VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; - VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; - VkPipelineViewportStateCreateInfo viewport_state = {}; - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - VkPipelineMultisampleStateCreateInfo multisampling = {}; - VkPipelineColorBlendStateCreateInfo color_blending = {}; - VkPipelineDynamicStateCreateInfo dynamic_state = {}; - VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; - - STATUS_CHECK(fill_shader_stages(shader_stages)); - fill_vertex_input_info(&vertex_input_info); - fill_input_assembly_info(&input_assembly); - fill_viewport_state_info(&viewport_state); - fill_rasterization_info(&rasterizer); - fill_multisampling_state_info(&multisampling); - fill_color_blend_state_info(&color_blending); - fill_dynamic_pipeline_state_info(&dynamic_state); - - //TODO: Move to another function - depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depth_stencil.depthTestEnable = VK_TRUE; - depth_stencil.depthWriteEnable = VK_TRUE; - depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; - depth_stencil.depthBoundsTestEnable = VK_FALSE; - depth_stencil.minDepthBounds = 0.0f; // Optional - depth_stencil.maxDepthBounds = 1.0f; // Optional - depth_stencil.stencilTestEnable = VK_FALSE; - // depth_stencil.front = {0}; // Optional - // depth_stencil.back = {0}; // Optional - - VkGraphicsPipelineCreateInfo pipeline_info = {}; - pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_info.pNext = NULL; - pipeline_info.flags = 0U; - pipeline_info.stageCount = SHADER_MODULES_COUNT; - pipeline_info.pStages = shader_stages; - pipeline_info.pVertexInputState = &vertex_input_info; - pipeline_info.pInputAssemblyState = &input_assembly; - pipeline_info.pTessellationState = NULL; - pipeline_info.pViewportState = &viewport_state; - pipeline_info.pRasterizationState = &rasterizer; - pipeline_info.pMultisampleState = &multisampling; - pipeline_info.pDepthStencilState = &depth_stencil; - pipeline_info.pColorBlendState = &color_blending; - pipeline_info.pDynamicState = &dynamic_state; - pipeline_info.layout = g_vulkan_state.pipeline_layout; - pipeline_info.renderPass = g_vulkan_state.render_pass; - pipeline_info.subpass = 0; - pipeline_info.basePipelineHandle = VK_NULL_HANDLE; - pipeline_info.basePipelineIndex = -1; - - if (VK_SUCCESS != - vkCreateGraphicsPipelines(g_vulkan_state.device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &g_vulkan_state.graphics_pipeline)) { - LOGF(vulkan_error_messages[VULKAN_GRAPHICSPIPELINE_CREATION_FAILED]); - status = VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED; - } - - free_dynamic_pipeline_state_info(&dynamic_state); - free_color_blend_info(&color_blending); - free_viewport_state_info(&viewport_state); - free_vertex_input_info(&vertex_input_info); - - return status; -} - -/** - * @brief Create Frambuffers - * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: - */ -uint8_t create_framebuffers() -{ - g_vulkan_state.swapchain_framebuffers = malloc(sizeof(VkFramebuffer) * g_swapchain_images_count); - - for (size_t i = 0; i < g_swapchain_images_count; i++) { - VkImageView attachments[] = {g_vulkan_state.swapchain_image_views[i], rse_get_depth_image_view()}; - - VkFramebufferCreateInfo framebufferInfo = {}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = g_vulkan_state.render_pass; - framebufferInfo.attachmentCount = 2; - framebufferInfo.pAttachments = attachments; - framebufferInfo.width = g_vulkan_state.swapchain_extent.width; - framebufferInfo.height = g_vulkan_state.swapchain_extent.height; - framebufferInfo.layers = 1; - - if (vkCreateFramebuffer(g_vulkan_state.device, &framebufferInfo, NULL, &g_vulkan_state.swapchain_framebuffers[i]) != VK_SUCCESS) { - LOGF(vulkan_error_messages[VULKAN_FRAMEBUFFERS_CREATION_FAILED]); - return VULKAN_ERROR_FRAMEBUFFERS_CREATION_FAILED; - } - } - - return VULKAN_ERROR_NO_ERROR; -} - - -/** - * @brief Recreate swapchain - * - */ -void recreate_swapchain() -{ - cleanup_swapchain(); - create_swapchain(); - create_swapchain_image_views(); - create_framebuffers(); -} - -/** - * @brief Cleanup swapchain - * - */ -void cleanup_swapchain() -{ - size_t i; - vkDeviceWaitIdle(g_vulkan_state.device); - for (i = 0; i < g_swapchain_images_count; i++) { - vkDestroyFramebuffer(g_vulkan_state.device, g_vulkan_state.swapchain_framebuffers[i], NULL); - } - - for (i = 0; i < g_swapchain_images_count; i++) { - vkDestroyImageView(g_vulkan_state.device, g_vulkan_state.swapchain_image_views[i], NULL); - } - - vkDestroySwapchainKHR(g_vulkan_state.device, g_vulkan_state.swapchain, NULL); + return RSE_ERROR_NO_ERROR; } /** * @brief Creates shader stages from hardcoded shader paths. Changes input * * @param shader_stages Empty vector, that will be filled with data - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_SHADER_FILE_OPEN_FAILED * VULKAN_ERROR_SHADER_CREATION_FAILED */ -static uint8_t fill_shader_stages(VkPipelineShaderStageCreateInfo* shader_stages) +static rse_err_t fill_shader_stages(VkPipelineShaderStageCreateInfo* shader_stages) { + rse_err_t status = RSE_ERROR_NO_ERROR; char* buffer; long buffer_size; VkShaderModule vertex_shader_module; @@ -529,18 +368,16 @@ static uint8_t fill_shader_stages(VkPipelineShaderStageCreateInfo* shader_stages buffer = malloc(buffer_size); rse_read_file(g_shader_paths[VERTEX], &buffer_size, buffer); - vertex_shader_module = create_shader_module(buffer, buffer_size); + STATUS_CHECK(create_shader_module(buffer, buffer_size, &vertex_shader_module)); free(buffer); rse_read_file(g_shader_paths[FRAGMENTS], &buffer_size, NULL); buffer = malloc(buffer_size); rse_read_file(g_shader_paths[FRAGMENTS], &buffer_size, buffer); - fragments_shader_module = create_shader_module(buffer, buffer_size); + STATUS_CHECK(create_shader_module(buffer, buffer_size, &fragments_shader_module)); free(buffer); - //TODO: Shader creation might have failed. Add error handling - /* Vertex Shader Pipeline Stage */ vert_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vert_shader_stage_info.pNext = NULL; @@ -565,7 +402,7 @@ static uint8_t fill_shader_stages(VkPipelineShaderStageCreateInfo* shader_stages memcpy(&g_shader_modules[0], &vertex_shader_module, sizeof(VkShaderModule)); memcpy(&g_shader_modules[1], &fragments_shader_module, sizeof(VkShaderModule)); - return VULKAN_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } /** @@ -573,7 +410,7 @@ static uint8_t fill_shader_stages(VkPipelineShaderStageCreateInfo* shader_stages * * @param dynamic_state structure to be filled */ -void fill_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state) +static void fill_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state) { VkDynamicState* dynamic_states; /* @@ -601,7 +438,7 @@ void fill_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_ * * @param dynamic_state structure to be freed */ -void free_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state) +static void free_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state) { free((VkDynamicState*)dynamic_state->pDynamicStates); } @@ -611,7 +448,7 @@ void free_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_ * * @param vertex_input_info structure to be filled */ -void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info) +static void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info) { const size_t binding_descriptions_count = 2; const size_t attribute_descriptions_count = 7; @@ -627,7 +464,7 @@ void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_i binding_descriptions[0] = vertex_binding_description; binding_descriptions[1].binding = 1; - binding_descriptions[1].stride = sizeof(struct rse_instance_data_t); //TODO: change + binding_descriptions[1].stride = sizeof(struct rse_instance_data_t); binding_descriptions[1].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; memcpy(attribute_descriptions, vertex_attribute_descriptions, sizeof(VkVertexInputAttributeDescription) * 3); @@ -668,7 +505,7 @@ void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_i * * @param vertex_input_info structure to be freed */ -void free_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info) +static void free_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info) { free((VkVertexInputBindingDescription*)vertex_input_info->pVertexBindingDescriptions); free((VkVertexInputAttributeDescription*)vertex_input_info->pVertexAttributeDescriptions); @@ -679,14 +516,13 @@ void free_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_i * * @param input_assembly structure to be filled */ -void fill_input_assembly_info(VkPipelineInputAssemblyStateCreateInfo* input_assembly) +static void fill_input_assembly_info(VkPipelineInputAssemblyStateCreateInfo* input_assembly) { input_assembly->sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; input_assembly->pNext = NULL; input_assembly->flags = 0U; - input_assembly->topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // TODO: Change to _STRIP - input_assembly->primitiveRestartEnable = VK_FALSE; /* If I want to break lines during _STRIP, - * I must set this to VK_TRUE */ + input_assembly->topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + input_assembly->primitiveRestartEnable = VK_FALSE; } /** @@ -694,7 +530,7 @@ void fill_input_assembly_info(VkPipelineInputAssemblyStateCreateInfo* input_asse * * @param viewport_state structure to be filled */ -void fill_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state) +static void fill_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state) { VkViewport* viewport = malloc(sizeof(VkViewport)); VkRect2D* scissor = malloc(sizeof(VkRect2D)); @@ -723,7 +559,7 @@ void fill_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state) * * @param viewport_state structure to be freed */ -void free_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state) +static void free_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state) { free((VkViewport*)viewport_state->pViewports); free((VkRect2D*)viewport_state->pScissors); @@ -734,7 +570,7 @@ void free_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state) * * @param rasterizer */ -void fill_rasterization_info(VkPipelineRasterizationStateCreateInfo* rasterizer) +static void fill_rasterization_info(VkPipelineRasterizationStateCreateInfo* rasterizer) { rasterizer->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rasterizer->pNext = NULL; @@ -756,7 +592,7 @@ void fill_rasterization_info(VkPipelineRasterizationStateCreateInfo* rasterizer) * * @param multisampling structure to be filled */ -void fill_multisampling_state_info(VkPipelineMultisampleStateCreateInfo* multisampling) +static void fill_multisampling_state_info(VkPipelineMultisampleStateCreateInfo* multisampling) { multisampling->sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling->pNext = NULL; @@ -774,7 +610,7 @@ void fill_multisampling_state_info(VkPipelineMultisampleStateCreateInfo* multisa * * @param color_blending structure to be filled */ -void fill_color_blend_state_info(VkPipelineColorBlendStateCreateInfo* color_blending) +static void fill_color_blend_state_info(VkPipelineColorBlendStateCreateInfo* color_blending) { VkPipelineColorBlendAttachmentState* color_blend_attachment = malloc(sizeof(VkPipelineColorBlendAttachmentState)); @@ -806,14 +642,155 @@ void fill_color_blend_state_info(VkPipelineColorBlendStateCreateInfo* color_blen * * @param color_blending Structure to be freed */ -void free_color_blend_info(VkPipelineColorBlendStateCreateInfo* color_blending) +static void free_color_blend_info(VkPipelineColorBlendStateCreateInfo* color_blending) { free((VkPipelineColorBlendAttachmentState*)color_blending->pAttachments); } -uint8_t create_pipeline() +static void fill_depth_stencil_info(VkPipelineDepthStencilStateCreateInfo* depth_stencil) { - uint8_t status = VULKAN_ERROR_NO_ERROR; + depth_stencil->sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depth_stencil->depthTestEnable = VK_TRUE; + depth_stencil->depthWriteEnable = VK_TRUE; + depth_stencil->depthCompareOp = VK_COMPARE_OP_LESS; + depth_stencil->depthBoundsTestEnable = VK_FALSE; + depth_stencil->minDepthBounds = 0.0f; // Optional + depth_stencil->maxDepthBounds = 1.0f; // Optional + depth_stencil->stencilTestEnable = VK_FALSE; + // depth_stencil.front = {0}; // Optional + // depth_stencil.back = {0}; // Optional +} + +/** + * @brief Create Graphics Pipeline + * + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: + * VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED + */ +static rse_err_t create_graphics_pipeline() +{ + rse_err_t status = RSE_ERROR_NO_ERROR; + + VkPipelineShaderStageCreateInfo shader_stages[SHADER_MODULES_COUNT]; + VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; + VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; + VkPipelineViewportStateCreateInfo viewport_state = {}; + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + VkPipelineMultisampleStateCreateInfo multisampling = {}; + VkPipelineColorBlendStateCreateInfo color_blending = {}; + VkPipelineDynamicStateCreateInfo dynamic_state = {}; + VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; + + STATUS_CHECK(fill_shader_stages(shader_stages)); + fill_vertex_input_info(&vertex_input_info); + fill_input_assembly_info(&input_assembly); + fill_viewport_state_info(&viewport_state); + fill_rasterization_info(&rasterizer); + fill_multisampling_state_info(&multisampling); + fill_color_blend_state_info(&color_blending); + fill_dynamic_pipeline_state_info(&dynamic_state); + fill_depth_stencil_info(&depth_stencil); + + VkGraphicsPipelineCreateInfo pipeline_info = {}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.pNext = NULL; + pipeline_info.flags = 0U; + pipeline_info.stageCount = SHADER_MODULES_COUNT; + pipeline_info.pStages = shader_stages; + pipeline_info.pVertexInputState = &vertex_input_info; + pipeline_info.pInputAssemblyState = &input_assembly; + pipeline_info.pTessellationState = NULL; + pipeline_info.pViewportState = &viewport_state; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pDepthStencilState = &depth_stencil; + pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_state; + pipeline_info.layout = g_vulkan_state.pipeline_layout; + pipeline_info.renderPass = g_vulkan_state.render_pass; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_info.basePipelineIndex = -1; + + if (VK_SUCCESS != + vkCreateGraphicsPipelines(g_vulkan_state.device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &g_vulkan_state.graphics_pipeline)) { + LOGF(vulkan_messages[VULKAN_GRAPHICSPIPELINE_CREATION_FAILED]); + status = VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED; + } + + free_dynamic_pipeline_state_info(&dynamic_state); + free_color_blend_info(&color_blending); + free_viewport_state_info(&viewport_state); + free_vertex_input_info(&vertex_input_info); + + return status; +} + +/** + * @brief Create Frambuffers + * + * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: + */ +static rse_err_t create_framebuffers() +{ + g_vulkan_state.swapchain_framebuffers = malloc(sizeof(VkFramebuffer) * g_swapchain_images_count); + + for (size_t i = 0; i < g_swapchain_images_count; i++) { + VkImageView attachments[] = {g_vulkan_state.swapchain_image_views[i], rse_get_depth_image_view()}; + + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = g_vulkan_state.render_pass; + framebufferInfo.attachmentCount = 2; + framebufferInfo.pAttachments = attachments; + framebufferInfo.width = g_vulkan_state.swapchain_extent.width; + framebufferInfo.height = g_vulkan_state.swapchain_extent.height; + framebufferInfo.layers = 1; + + if (vkCreateFramebuffer(g_vulkan_state.device, &framebufferInfo, NULL, &g_vulkan_state.swapchain_framebuffers[i]) != VK_SUCCESS) { + LOGF(vulkan_messages[VULKAN_FRAMEBUFFERS_CREATION_FAILED]); + return VULKAN_ERROR_FRAMEBUFFERS_CREATION_FAILED; + } + } + + return RSE_ERROR_NO_ERROR; +} + + +/** + * @brief Recreate swapchain + * + */ +void recreate_swapchain() +{ + cleanup_swapchain(); + create_swapchain(); + create_swapchain_image_views(); + create_framebuffers(); +} + +/** + * @brief Cleanup swapchain + * + */ +void cleanup_swapchain() +{ + size_t i; + vkDeviceWaitIdle(g_vulkan_state.device); + for (i = 0; i < g_swapchain_images_count; i++) { + vkDestroyFramebuffer(g_vulkan_state.device, g_vulkan_state.swapchain_framebuffers[i], NULL); + } + + for (i = 0; i < g_swapchain_images_count; i++) { + vkDestroyImageView(g_vulkan_state.device, g_vulkan_state.swapchain_image_views[i], NULL); + } + + vkDestroySwapchainKHR(g_vulkan_state.device, g_vulkan_state.swapchain, NULL); +} + +rse_err_t create_pipeline() +{ + rse_err_t status = RSE_ERROR_NO_ERROR; STATUS_CHECK(create_swapchain()); STATUS_CHECK(create_swapchain_image_views()); diff --git a/graphics/src/vulkan_pipeline.h b/graphics/src/vulkan_pipeline.h index 395438be..8f09e186 100644 --- a/graphics/src/vulkan_pipeline.h +++ b/graphics/src/vulkan_pipeline.h @@ -2,35 +2,32 @@ #define RSE_VULKAN_PIPELINE_H #include "vulkan_commons.h" +#include "utilities/rse_commons.h" #include /** * @brief Create a graphics pipeline * - * @param vulkan_state - * @return uint8_t + * @return rse_err_t RSE_ERROR_NO_ERROR on success */ -uint8_t create_pipeline(void); +rse_err_t create_pipeline(void); /** * @brief Cleanup swapchain * - * @param vulkan_state */ void cleanup_swapchain(void); /** * @brief Recreates swapchain * - * @param vulkan_state */ void recreate_swapchain(void); /** * @brief Destroy all vulkan pipeline objects * - * @param vulkan_state */ void destroy_pipeline(void); diff --git a/graphics/src/window.c b/graphics/src/window.c index 04fc5e14..9805dcfd 100644 --- a/graphics/src/window.c +++ b/graphics/src/window.c @@ -13,16 +13,9 @@ #include "locale_window.h" #include "utilities/logger.h" +#include "utilities/rse_errors_common.h" #include "vulkan_base.h" -/* Error codes */ -typedef enum { - WINDOW_ERROR_NO_ERROR = 0U, - WINDOW_ERROR_GLFW_INIT_FAILED, - WINDOW_ERROR_VULKAN_NOT_LOADED, - WINDOW_ERROR_WINDOW_NOT_CREATED -} WINDOW_ERROR; - GLFWwindow *g_window_handle = NULL; /** @@ -58,7 +51,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, } -uint16_t window_init() +rse_err_t window_init() { /* Initiliaze GLFW AP */ if (GLFW_TRUE != glfwInit()) @@ -89,17 +82,17 @@ uint16_t window_init() glfwSetKeyCallback(g_window_handle, key_callback); - return WINDOW_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } -uint16_t window_loop() +rse_err_t window_loop() { while (!glfwWindowShouldClose(g_window_handle)) { glfwPollEvents(); draw_frame(); } - return WINDOW_ERROR_NO_ERROR; + return RSE_ERROR_NO_ERROR; } void window_terminate() diff --git a/graphics/src/window.h b/graphics/src/window.h index bd69de87..491b55cb 100644 --- a/graphics/src/window.h +++ b/graphics/src/window.h @@ -17,23 +17,26 @@ /* Vulkan header MUST be included before glfw */ #include +#include "rse_window_errors.h" +#include "utilities/rse_commons.h" + /** * @brief Initialize window * - * @return uint16_t WINDOW_SUCCESS on success. Possible errors: + * @return rse_err_t WINDOW_SUCCESS on success. Possible errors: * WINDOW_VULKAN_NOT_LOADED * WINDOW_WINDOW_NOT_CREATED * */ -uint16_t window_init(); +rse_err_t window_init(); /** * @brief Main window loop * * @param vulkan_state - * @return uint16_t WINDOW_SUCCESS or error code + * @return rse_err_t WINDOW_SUCCESS or error code */ -uint16_t window_loop(); +rse_err_t window_loop(); /** * @brief Closes window and terminates GLFW diff --git a/utilities/locale_common.h b/utilities/locale_common.h index a240b43f..2cc5e841 100644 --- a/utilities/locale_common.h +++ b/utilities/locale_common.h @@ -14,14 +14,14 @@ #include "localization.h" -#define vulkan_error_messages vulkan_error_messages_nolocale[SELECTED_LANGUAGE] +#define common_messages common_messages_nolocale[SELECTED_LANGUAGE] -enum vulkan_errors_t { - COMMON_MEMORY_ALLOCATION_FAILED, - LAST_MESSAGE +enum common_errors_t { + COMMON_ERROR_MEMORY_ALLOCATION_FAILED, + COMMON_ERROR_LAST_MESSAGE }; -static const char vulkan_error_messages_nolocale[LAST_LANGUAGE][LAST_MESSAGE][MAX_MESSAGE_LENGHT] = { +static const char common_messages_nolocale[LAST_LANGUAGE][COMMON_ERROR_LAST_MESSAGE][MAX_MESSAGE_LENGHT] = { {/* EN_US */ /* COMMON_MEMORY_ALLOCATION_FAILED */ "Unable to allocate memory" diff --git a/utilities/logger.h b/utilities/logger.h index 1f7ed2ef..6a30e44e 100644 --- a/utilities/logger.h +++ b/utilities/logger.h @@ -34,7 +34,7 @@ * @brief Log level. Is not an enum class, because level is being compared to enable prints * */ -typedef enum +enum log_level_t { LOGLEVEL_TRACE, LOGLEVEL_DEBUG, @@ -42,7 +42,7 @@ typedef enum LOGLEVEL_WARNING, LOGLEVEL_ERROR, LOGLEVEL_FATAL -} LogLevel; +}; void _log_log(unsigned int level, const char* file, int line, const char* fmt, ...); diff --git a/utilities/rse_commons.h b/utilities/rse_commons.h new file mode 100644 index 00000000..aeabae13 --- /dev/null +++ b/utilities/rse_commons.h @@ -0,0 +1,34 @@ +/** + * @file rse_commons.h + * @author Piotr Krygier (everyonecancode@gmail.com) + * @brief Common functionality for all modules + * @version 0.1 + * @date 2023-10-05 + * + * @copyright Copyright (c) 2023 + * + */ + +#ifndef RSE_COMMONS_H +#define RSE_COMMONS_H + +#include + +/** + * @brief Macro for allocating memory and checking it on the same line + * + */ +#define rse_malloc(ptr, size) \ +ptr = malloc(size); \ +if (ptr == NULL) { \ + LOGF(common_messages[COMMON_ERROR_MEMORY_ALLOCATION_FAILED]); \ + return RSE_COMMON_ERROR_MALLLOC_FAILED; \ +} + +/** + * @brief Error type for RSE + * + */ +typedef uint32_t rse_err_t; + +#endif /* RSE_COMMONS_H */ \ No newline at end of file diff --git a/utilities/rse_errors_common.h b/utilities/rse_errors_common.h new file mode 100644 index 00000000..0982b877 --- /dev/null +++ b/utilities/rse_errors_common.h @@ -0,0 +1,30 @@ +/** + * @file rse_errors_common.h + * @author Piotr Krygier (everyonecancode@gmail.com) + * @brief Common error messages, that can appear in any module + * @version 0.1 + * @date 2023-10-05 + * + * @copyright Copyright (c) 2023 + * + */ + +#ifndef RSE_ERRORS_COMMON_H + +/* Macro for checking status of function execution in initVulkan. Created to avoid writing boilerplate code */ +#define STATUS_CHECK(FUNC) \ + status = FUNC; \ + if (RSE_ERROR_NO_ERROR != status) { \ + return status; \ + } + +#define RSE_COMMON_MODULE_ID 0x0100U + +enum rse_common_error_t +{ + RSE_ERROR_NO_ERROR = RSE_COMMON_MODULE_ID, + RSE_COMMON_ERROR_MALLLOC_FAILED, +}; + +#define RSE_ERRORS_COMMON_H +#endif /* RSE_ERRORS_COMMON_H */ \ No newline at end of file