[WIP] Refactor project
There are many problems with the way the current version is provided and maintained. This commit or series of commits will fix this.
This commit is contained in:
1 parent
f5ab5f3f27
commit
173a82b9d1
63 files changed
+2663
-2239
No files matched your search
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
BasedOnStyle: Google
|
BasedOnStyle: Google
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
|
|
||||||
# Add missing namespace comment on the closing bracket
|
# Add missing namespace comment on the closing bracket
|
||||||
FixNamespaceComments: true
|
FixNamespaceComments: true
|
||||||
|
|
||||||
# Do not indent everything in namespace
|
# Do not indent everything in namespace
|
||||||
@@ -25,8 +25,8 @@ BraceWrapping:
|
|||||||
BeforeCatch: false
|
BeforeCatch: false
|
||||||
BeforeElse: false
|
BeforeElse: false
|
||||||
|
|
||||||
ColumnLimit: 120
|
ColumnLimit: 80
|
||||||
|
|
||||||
# Pointer star next to type, not variable name
|
# Pointer star next to type, not variable name
|
||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: false
|
||||||
PointerAlignment: Left
|
PointerAlignment: Left
|
||||||
+2
-1
@@ -11,4 +11,5 @@ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
|||||||
add_subdirectory(red_scarf_engine)
|
add_subdirectory(red_scarf_engine)
|
||||||
add_subdirectory(utilities)
|
add_subdirectory(utilities)
|
||||||
add_subdirectory(graphics)
|
add_subdirectory(graphics)
|
||||||
add_subdirectory(tests)
|
# Enable later
|
||||||
|
# add_subdirectory(tests)
|
||||||
@@ -1,2 +1,14 @@
|
|||||||
# Red Scarf Engine
|
# Red Scarf Engine
|
||||||
|
|
||||||
|
Graphics/Game engine written in Vulkan. More of a science project than the actual engine that will be used anywhere.
|
||||||
|
|
||||||
|
# Running
|
||||||
|
There are couple of usefull scripts to build and run this project.
|
||||||
|
|
||||||
|
## prepare_env.py
|
||||||
|
[WIP] This python script will download all project dependencies that are present in dependencies.dep file. It can be
|
||||||
|
either git repo link or an archive to be downloaded.
|
||||||
|
|
||||||
|
## run.sh
|
||||||
|
Sice we wan to use Vulkan version that is bind to this project, couple of environment variables need to be added to be
|
||||||
|
able to run this project. run.sh script will set those variables and run the executable.
|
||||||
+10
-10
@@ -28,7 +28,7 @@ function(compile_shader)
|
|||||||
endforeach()
|
endforeach()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
compile_shader(rse_graphics
|
compile_shader(graphics
|
||||||
ENV opengl
|
ENV opengl
|
||||||
FORMAT num
|
FORMAT num
|
||||||
SOURCES
|
SOURCES
|
||||||
@@ -37,12 +37,12 @@ shaders/solid_objects.frag
|
|||||||
shaders/on_screen_text.frag
|
shaders/on_screen_text.frag
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(rse_graphics SHARED
|
add_library(graphics SHARED
|
||||||
shaders/shader.vert.num
|
shaders/shader.vert.num
|
||||||
shaders/solid_objects.frag.num
|
shaders/solid_objects.frag.num
|
||||||
shaders/on_screen_text.frag.num
|
shaders/on_screen_text.frag.num
|
||||||
)
|
)
|
||||||
target_include_directories(rse_graphics PRIVATE
|
target_include_directories(graphics PRIVATE
|
||||||
${PROJECT_SOURCE_DIR}
|
${PROJECT_SOURCE_DIR}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_SOURCE_DIR}
|
${CMAKE_SOURCE_DIR}
|
||||||
@@ -53,24 +53,24 @@ ${CMAKE_SOURCE_DIR}
|
|||||||
${FreeType_INCLUDE_DIR}
|
${FreeType_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_sources(rse_graphics PRIVATE
|
target_sources(graphics PRIVATE
|
||||||
src/vma_port.cpp
|
src/vma_port.cpp
|
||||||
src/window.c
|
src/window.c
|
||||||
src/vulkan_base.c
|
src/vulkan_base.c
|
||||||
src/vulkan_pipeline.c
|
src/vulkan_pipeline.c
|
||||||
src/rse_vulkan_commands.c
|
src/vulkan_commands.c
|
||||||
src/vulkan_buffers.c
|
src/vulkan_buffers.c
|
||||||
src/vulkan_descriptors.c
|
src/vulkan_descriptors.c
|
||||||
src/rse_graphics.c
|
src/rse_graphics.c
|
||||||
src/rse_math.c
|
src/math.c
|
||||||
src/mesh_controller.c
|
src/mesh_controller.c
|
||||||
src/vulkan_commons.c
|
src/vulkan_commons.c
|
||||||
src/rse_vulkan_image.c
|
src/vulkan_image.c
|
||||||
src/rse_text_renderer.c
|
src/text_renderer.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(rse_graphics PRIVATE
|
target_link_libraries(graphics PRIVATE
|
||||||
rse_utilities
|
utilities
|
||||||
${Vulkan_LIBRARIES}
|
${Vulkan_LIBRARIES}
|
||||||
${glfw}
|
${glfw}
|
||||||
${freetype}
|
${freetype}
|
||||||
|
|||||||
@@ -1,28 +1,31 @@
|
|||||||
#ifndef RSE_GRAPHICS_H
|
#ifndef RSE_GRAPHICS_H
|
||||||
#define RSE_GRAPHICS_H
|
#define RSE_GRAPHICS_H
|
||||||
|
|
||||||
#include "utilities/rse_commons.h"
|
#include "utilities/commons.h"
|
||||||
|
|
||||||
|
struct rse_graphics_context_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes graphics backend. This has to be called before any new mesh, texture or any other object is
|
* @brief Initializes graphics backend. This has to be called before any new mesh, texture or any other object is
|
||||||
* added
|
* added
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle. Must be NULL!
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||||
*/
|
*/
|
||||||
rse_err_t rse_graphics_init(void);
|
rse_err_t rse_graphics_init(struct rse_graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Runs graphics engine. This has to be called after all objects are added to the scene
|
* @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
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||||
*/
|
*/
|
||||||
rse_err_t rse_graphics_run(void);
|
rse_err_t rse_graphics_run(struct rse_graphics_context_t* context);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Custom function for testing engine. Remove it whe releasing
|
* @brief Custom function for testing engine. TODO: Remove it whe releasing
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void rse_graphics_test_function(void);
|
void rse_graphics_test_function(struct rse_graphics_context_t* context);
|
||||||
|
|
||||||
#endif /* RSE_GRAPHICS_H */
|
#endif /* RSE_GRAPHICS_H */
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
/* Each time texture count is changed this value also need to change. I have to fix it somehow. */
|
|
||||||
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
#extension GL_EXT_nonuniform_qualifier : enable
|
||||||
|
|
||||||
layout(set = 1, binding = 1) uniform sampler2D texSampler[];
|
layout(set = 1, binding = 1) uniform sampler2D texSampler[];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file rse_font_errors.h
|
* @file font_errors.h
|
||||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
* @brief
|
* @brief
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
@@ -9,13 +9,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_FONT_ERRORS_H
|
#ifndef FONT_ERRORS_H
|
||||||
#define RSE_FONT_ERRORS_H
|
#define FONT_ERRORS_H
|
||||||
|
|
||||||
#define RSE_FONT_MODULE_ID 0x0400U
|
#define RSE_FONT_MODULE_ID 0x0400U
|
||||||
|
|
||||||
/* Error codes */
|
/* Error codes */
|
||||||
enum rse_window_error_t {
|
enum window_error_t {
|
||||||
FONT_ERROR_INIT_FAILED = RSE_FONT_MODULE_ID,
|
FONT_ERROR_INIT_FAILED = RSE_FONT_MODULE_ID,
|
||||||
FONT_ERROR_LOAD_FAILED,
|
FONT_ERROR_LOAD_FAILED,
|
||||||
FONT_ERROR_CHANGE_SIZE_FAILED,
|
FONT_ERROR_CHANGE_SIZE_FAILED,
|
||||||
@@ -23,4 +23,4 @@ enum rse_window_error_t {
|
|||||||
FONT_ERROR_RENDER_GLYPH_FAILED
|
FONT_ERROR_RENDER_GLYPH_FAILED
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* RSE_WINDOW_ERRORS_H */
|
#endif /* WINDOW_ERRORS_H */
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
* @file graphics_context.h
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief Graphics context for Red Scarf Engine
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-05-22
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GRAPHICS_CONTEXT_H
|
||||||
|
#define GRAPHICS_CONTEXT_H
|
||||||
|
|
||||||
|
#include "vulkan/vulkan_core.h"
|
||||||
|
#include "vulkan_commons.h"
|
||||||
|
#include "utilities/linked_list.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#define MAX_MESH_NUMBER 256
|
||||||
|
#define MAX_INSTANCE_NUMBER 256
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Maximum number of textures that can be loaded
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define RSE_MAX_IMAGE_COUNT 256
|
||||||
|
|
||||||
|
#define MAX_DESCRIPTOR_SETS 16
|
||||||
|
#define MAX_PIPELINE_COUNT 16
|
||||||
|
|
||||||
|
RSE_LINKED_LIST_DEFINE(shader_module_list_t, VkShaderModule);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Represents data within vertex or instance buffer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct buffer_data_t
|
||||||
|
{
|
||||||
|
size_t count;
|
||||||
|
size_t buffer_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wrapper for Vulkan buffer. Holds allocation data;
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct vulkan_image_t
|
||||||
|
{
|
||||||
|
uint8_t id_taken;
|
||||||
|
size_t allocated_size;
|
||||||
|
VkImage image;
|
||||||
|
VkImageView image_view;
|
||||||
|
VmaAllocation allocation;
|
||||||
|
VmaAllocationInfo allocation_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Represents instance of a mesh and shows where it's located in instance buffer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct internal_instance_data_t
|
||||||
|
{
|
||||||
|
uint8_t instance_taken;
|
||||||
|
uint8_t instance_buffer_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mesh data, with unique id and dynamic arrays holding vertices and indices.
|
||||||
|
* One mesh can have multiple instances.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct mesh_t
|
||||||
|
{
|
||||||
|
uint8_t is_mesh_id_taken;
|
||||||
|
uint32_t unique_id;
|
||||||
|
uint8_t instance_count;
|
||||||
|
struct buffer_data_t vertex_data;
|
||||||
|
struct buffer_data_t index_data;
|
||||||
|
struct internal_instance_data_t instance_data[MAX_INSTANCE_NUMBER];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pipeline_internal_t
|
||||||
|
{
|
||||||
|
size_t pipelines_count;
|
||||||
|
size_t descriptor_set_layouts_count;
|
||||||
|
VkPipeline pipelines[MAX_PIPELINE_COUNT];
|
||||||
|
VkPipelineLayout pipeline_layout;
|
||||||
|
VkDescriptorSetLayout descriptor_set_layouts[MAX_DESCRIPTOR_SETS];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct graphics_context_t
|
||||||
|
{
|
||||||
|
GLFWwindow* window_handle;
|
||||||
|
VkDevice device;
|
||||||
|
VkSurfaceKHR surface;
|
||||||
|
VkInstance instance;
|
||||||
|
VkQueue graphics_queue;
|
||||||
|
VmaAllocator allocator;
|
||||||
|
VkSampler sampler;
|
||||||
|
VkPhysicalDevice physical_device;
|
||||||
|
VkCommandPool command_pool;
|
||||||
|
VkCommandBuffer command_buffers[SWAP_BUFFER_COUNT];
|
||||||
|
VkDescriptorSet descriptor_sets[SWAP_BUFFER_COUNT];
|
||||||
|
VkDescriptorSet descriptor_sets_bindless;
|
||||||
|
VkImageView* swapchain_image_views;
|
||||||
|
VkExtent2D swapchain_extent;
|
||||||
|
VkRenderPass render_pass;
|
||||||
|
VkFramebuffer* swapchain_framebuffers;
|
||||||
|
VkSwapchainKHR swapchain;
|
||||||
|
uint32_t swapchain_images_count;
|
||||||
|
VkImage* swapchain_images;
|
||||||
|
VkQueue present_queue;
|
||||||
|
VkSemaphore image_available_semaphores[SWAP_BUFFER_COUNT];
|
||||||
|
VkSemaphore render_finished_semaphores[SWAP_BUFFER_COUNT];
|
||||||
|
VkFence in_flight_fences[SWAP_BUFFER_COUNT];
|
||||||
|
VkDescriptorPool descriptor_pool;
|
||||||
|
VkDescriptorPool descriptor_pool_bindless;
|
||||||
|
struct pipeline_internal_t pipelines_data;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
VkDebugUtilsMessengerEXT debug_messenger;
|
||||||
|
#endif // !NDEBUG
|
||||||
|
bool is_framebuffer_resized; //TODO: Consider moving this to heap
|
||||||
|
uint32_t current_frame;
|
||||||
|
uint32_t queue_family_indices[1];
|
||||||
|
struct vulkan_buffer_t uniform_buffers[SWAP_BUFFER_COUNT];
|
||||||
|
/* GPU visible buffer */
|
||||||
|
size_t vertex_offset;
|
||||||
|
struct vulkan_buffer_t vertex_buffer;
|
||||||
|
struct vulkan_buffer_t index_buffer;
|
||||||
|
struct vulkan_buffer_t instance_buffers[MAX_MESH_NUMBER];
|
||||||
|
struct vulkan_buffer_t draw_indirect_command_buffer;
|
||||||
|
struct vulkan_image_t texture_images[RSE_MAX_IMAGE_COUNT];
|
||||||
|
struct vulkan_image_t depth_image;
|
||||||
|
struct vulkan_image_t color_image;
|
||||||
|
struct shader_module_list_t* shader_modules;
|
||||||
|
struct mesh_t meshes[MAX_MESH_NUMBER];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* GRAPHICS_CONTEXT_H */
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
|
|
||||||
/**
|
|
||||||
* @file locale_fonts.h
|
|
||||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
|
||||||
* @brief Error messages for font handlers
|
|
||||||
* @version 0.1
|
|
||||||
* @date 2022-05-13
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2022
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef RSE_LOCALE_FONTS_H
|
|
||||||
#define RSE_LOCALE_FONTS_H
|
|
||||||
|
|
||||||
#include "utilities/localization.h"
|
|
||||||
|
|
||||||
#define font_messages font_messages_nolocale[SELECTED_LANGUAGE]
|
|
||||||
|
|
||||||
enum font_messages_t {
|
|
||||||
FONT_INITIALIZATION_FAILED,
|
|
||||||
FONT_LOAD_FONT_FAILED,
|
|
||||||
FONT_CHANGE_SIZE_FAILED,
|
|
||||||
FONT_LOAD_GLYPH_FAILED,
|
|
||||||
FONT_RENDER_GLYPH_FAILED,
|
|
||||||
FONT_LAST_MESSAGE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static const char font_messages_nolocale[LAST_LANGUAGE][FONT_LAST_MESSAGE][MAX_MESSAGE_LENGHT] = {
|
|
||||||
{/* EN_US */
|
|
||||||
/* FONT_INITIALIZATION_FAILED */
|
|
||||||
"Font initialization failed\n",
|
|
||||||
/* FONT_LOAD_FONT_FAILED */
|
|
||||||
"Failed to load new font\n",
|
|
||||||
/* FONT_CHANGE_SIZE_FAILED */
|
|
||||||
"Failed to change font size\n",
|
|
||||||
/* FONT_LOAD_GLYPH_FAILED */
|
|
||||||
"Failed to load glyph into memeory\n",
|
|
||||||
/* FONT_RENDER_GLYPH_FAILED */
|
|
||||||
"Failed to render glypth into bitmap\n"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // RSE_LOCALE_FONTS_H
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file locale_vulkan.h
|
|
||||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
|
||||||
* @brief Error messages for Vulkan initializers
|
|
||||||
* @version 0.1
|
|
||||||
* @date 2022-05-13
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2022
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RSE_LOCALE_VULKAN_H
|
|
||||||
#define RSE_LOCALE_VULKAN_H
|
|
||||||
|
|
||||||
#include "utilities/localization.h"
|
|
||||||
|
|
||||||
#define vulkan_messages vulkan_messages_nolocale[SELECTED_LANGUAGE]
|
|
||||||
|
|
||||||
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,
|
|
||||||
VULKAN_COMMAND_POOL_CREATION_FAILED,
|
|
||||||
VULKAN_BUFFER_CREATION_FAILED,
|
|
||||||
VULKAN_VERTEX_BUFFER_MAPPING_FAILED,
|
|
||||||
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,
|
|
||||||
VULKAN_PIPELAYOUT_CREATION_FAILED,
|
|
||||||
VULKAN_RENDERPASS_CREATION_FAILED,
|
|
||||||
VULKAN_DESCRIPTOR_POOL_CREATION_FAILED,
|
|
||||||
VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED,
|
|
||||||
VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED,
|
|
||||||
VULKAN_GRAPHICSPIPELINE_CREATION_FAILED,
|
|
||||||
VULKAN_FRAMEBUFFERS_CREATION_FAILED,
|
|
||||||
VULKAN_RECORD_COMMAND_BEGIN_FAILED,
|
|
||||||
VULKAN_RECORD_COMMAND_BUFFER_FAILED,
|
|
||||||
VULKAN_SYNCOBJCTS_CREATION_FAILED,
|
|
||||||
VULKAN_MESH_NO_FREE,
|
|
||||||
VULKAN_MESH_INSTANCE_NO_FREE,
|
|
||||||
VULAKN_DRAW_FAILED,
|
|
||||||
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_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 */
|
|
||||||
"Selected extension is not supported: %s\n",
|
|
||||||
/* VULKAN_INTANCE_INIT_FAILED */
|
|
||||||
"Vulkan instance initialization failed\n",
|
|
||||||
/* VULKAN_NO_PHYSICAL_DEVICES */
|
|
||||||
"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 */
|
|
||||||
"Failed to create logical device\n",
|
|
||||||
/* VULKAN_ALLOCATOR_CREATION_FAILED */
|
|
||||||
"Failed to create Vulkan Memory Allocator\n",
|
|
||||||
/* VULKAN_COMMAND_POOL_CREATION_FAILED */
|
|
||||||
"Failed to create command pool\n",
|
|
||||||
/* VULKAN_BUFFER_CREATION_FAILED */
|
|
||||||
"Failed to create a vertex buffer\n",
|
|
||||||
/* VULKAN_VERTEX_BUFFER_MAPPING_FAILED */
|
|
||||||
"Failed to map vulkan memory buffer\n",
|
|
||||||
/* VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED */
|
|
||||||
"Failed to allocate command buffers\n",
|
|
||||||
/* VULKAN_SURFACE_CREATION_FAILED */
|
|
||||||
"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 */
|
|
||||||
"Failed to open a file containing shader code\n",
|
|
||||||
/* VULKAN_SHADER_UNABLE_TO_CREATE_SHADER */
|
|
||||||
"Failed to create a shader\n",
|
|
||||||
/* VULKAN_PIPELAYOUT_CREATION_FAILED */
|
|
||||||
"Failed to create pipeline layout\n",
|
|
||||||
/* VULKAN_RENDERPASS_CREATION_FAILED */
|
|
||||||
"Failed to create render pass\n",
|
|
||||||
/* VULKAN_DESCRIPTOR_POOL_CREATION_FAILED */
|
|
||||||
"Failed to create descriptor pool\n",
|
|
||||||
/* VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED */
|
|
||||||
"Failed to allocate descriptor sets\n",
|
|
||||||
/* VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED */
|
|
||||||
"Failed to create descriptor set layout\n",
|
|
||||||
/* VULKAN_GRAPHICSPIPELINE_CREATION_FAILED */
|
|
||||||
"Failed to create graphics pipeline\n",
|
|
||||||
/* VULKAN_FRAMEBUFFERS_CREATION_FAILED */
|
|
||||||
"Failed to create framebuffer\n",
|
|
||||||
/* VULKAN_RECORD_COMMAND_BEGIN_FAILED */
|
|
||||||
"Failed to start recording command buffer\n",
|
|
||||||
/* VULKAN_RECORD_COMMAND_BUFFER_FAILED */
|
|
||||||
"Failed to record command buffer. Validate your commands.\n",
|
|
||||||
/* VULKAN_SYNCOBJCTS_CREATION_FAILED */
|
|
||||||
"Failed to create sync objects.\n",
|
|
||||||
/* VULKAN_MESH_NO_FREE */
|
|
||||||
"Could not allocate new mesh, reached maximum.\n",
|
|
||||||
/* VULKAN_MESH_INSTANCE_NO_FREE */
|
|
||||||
"Could not allocate new mesh instance\n",
|
|
||||||
/* VULAKN_DRAW_FAILED */
|
|
||||||
"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",
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* RSE_LOCALE_VULKAN_H */
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file locale_window.h
|
|
||||||
* @author Piotr Krygier (everyonencancode@gmail.com)
|
|
||||||
* @brief Error messages
|
|
||||||
* @version 0.1
|
|
||||||
* @date 2022-02-15
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2022
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LOCALE_WINDOW_H
|
|
||||||
#define LOCALE_WINDOW_H
|
|
||||||
|
|
||||||
#include "utilities/localization.h"
|
|
||||||
|
|
||||||
#define window_error_messages window_error_messages_nolocale[SELECTED_LANGUAGE]
|
|
||||||
|
|
||||||
enum window_messages_t
|
|
||||||
{
|
|
||||||
WINDOW_GLFW_INIT_FAILED,
|
|
||||||
WINDOW_VULKAN_NOT_SUPPORTED,
|
|
||||||
WINDOW_NOT_CREATED,
|
|
||||||
WINDOW_LAST_MESSAGE
|
|
||||||
};
|
|
||||||
|
|
||||||
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",
|
|
||||||
/* WINDOW_VULKAN_NOT_SUPPORTED */
|
|
||||||
"Unable to load Vulkan\n",
|
|
||||||
/*WINDOW_NOT_CREATED*/
|
|
||||||
"Window context creation failed\n"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* LOCALE_WINDOW_H */
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "rse_math.h"
|
#include "math.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
@@ -29,12 +29,12 @@ static float scalar_cross_vec3(const struct vec3_t* vec1, const struct vec3_t* v
|
|||||||
+(vec1->z * vec2->z);
|
+(vec1->z * vec2->z);
|
||||||
}
|
}
|
||||||
|
|
||||||
float rse_math_deg_to_radians(float degrees)
|
float math_deg_to_radians(float degrees)
|
||||||
{
|
{
|
||||||
return degrees * (PI/180.0f);
|
return degrees * (PI/180.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vec3_t rse_math_cross_vec3(const struct vec3_t* vec1, const struct vec3_t* vec2)
|
struct vec3_t math_cross_vec3(const struct vec3_t* vec1, const struct vec3_t* vec2)
|
||||||
{
|
{
|
||||||
struct vec3_t result;
|
struct vec3_t result;
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ struct vec3_t rse_math_cross_vec3(const struct vec3_t* vec1, const struct vec3_t
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vec3_t rse_math_normalize_vec3(const struct vec3_t* vec)
|
struct vec3_t math_normalize_vec3(const struct vec3_t* vec)
|
||||||
{
|
{
|
||||||
struct vec3_t result = {0};
|
struct vec3_t result = {0};
|
||||||
float vec_length = 0.0f;
|
float vec_length = 0.0f;
|
||||||
@@ -58,7 +58,7 @@ struct vec3_t rse_math_normalize_vec3(const struct vec3_t* vec)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mat4_t rse_math_uniform_mat4()
|
struct mat4_t math_uniform_mat4()
|
||||||
{
|
{
|
||||||
struct mat4_t result= {0.0f};
|
struct mat4_t result= {0.0f};
|
||||||
result.x_1 = 1.0f;
|
result.x_1 = 1.0f;
|
||||||
@@ -69,7 +69,7 @@ struct mat4_t rse_math_uniform_mat4()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mat4_t rse_math_perspective(float fovy, float aspect_ratio, float z_near, float z_far)
|
struct mat4_t math_perspective(float fovy, float aspect_ratio, float z_near, float z_far)
|
||||||
{
|
{
|
||||||
float tan_half_fovy = 0;
|
float tan_half_fovy = 0;
|
||||||
struct mat4_t result = {0};
|
struct mat4_t result = {0};
|
||||||
@@ -85,7 +85,7 @@ struct mat4_t rse_math_perspective(float fovy, float aspect_ratio, float z_near,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mat4_t rse_math_look_at(const struct vec3_t* eye, const struct vec3_t* center, const struct vec3_t* up)
|
struct mat4_t math_look_at(const struct vec3_t* eye, const struct vec3_t* center, const struct vec3_t* up)
|
||||||
{
|
{
|
||||||
struct mat4_t result = {0.0f};
|
struct mat4_t result = {0.0f};
|
||||||
struct vec3_t forward_vec = {0};
|
struct vec3_t forward_vec = {0};
|
||||||
@@ -94,12 +94,12 @@ struct mat4_t rse_math_look_at(const struct vec3_t* eye, const struct vec3_t* ce
|
|||||||
|
|
||||||
struct vec3_t tmp = substract_vec3(eye, center);
|
struct vec3_t tmp = substract_vec3(eye, center);
|
||||||
|
|
||||||
forward_vec = rse_math_normalize_vec3(&tmp);
|
forward_vec = math_normalize_vec3(&tmp);
|
||||||
|
|
||||||
tmp = rse_math_cross_vec3(up, &forward_vec);
|
tmp = math_cross_vec3(up, &forward_vec);
|
||||||
right_vec = rse_math_normalize_vec3(&tmp);
|
right_vec = math_normalize_vec3(&tmp);
|
||||||
|
|
||||||
up_vec = rse_math_cross_vec3(&forward_vec, &right_vec);
|
up_vec = math_cross_vec3(&forward_vec, &right_vec);
|
||||||
|
|
||||||
result.x_1 = right_vec.x;
|
result.x_1 = right_vec.x;
|
||||||
result.x_2 = right_vec.y;
|
result.x_2 = right_vec.y;
|
||||||
@@ -125,9 +125,9 @@ struct mat4_t rse_math_look_at(const struct vec3_t* eye, const struct vec3_t* ce
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mat4_t rse_math_rotate(struct mat4_t matrix, float radians, struct vec3_t rotation_vector)
|
struct mat4_t math_rotate(struct mat4_t matrix, float radians, struct vec3_t rotation_vector)
|
||||||
{
|
{
|
||||||
struct mat4_t result = rse_math_uniform_mat4();
|
struct mat4_t result = math_uniform_mat4();
|
||||||
float cos = cosf(radians);
|
float cos = cosf(radians);
|
||||||
float sin = sinf(radians);
|
float sin = sinf(radians);
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file rse_math.h
|
* @file math.h
|
||||||
* @author Piotr Krygier (piotr.krygier@)
|
* @author Piotr Krygier (piotr.krygier@)
|
||||||
* @brief RedScarfEngine math operations
|
* @brief RedScarfEngine math operations
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_MATH_H
|
#ifndef MATH_H
|
||||||
#define RSE_MATH_H
|
#define MATH_H
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Simple representation of vector
|
* @brief Simple representation of vector
|
||||||
@@ -62,14 +62,14 @@ struct mat4_t {
|
|||||||
* @param degrees degrees
|
* @param degrees degrees
|
||||||
* @return float radians
|
* @return float radians
|
||||||
*/
|
*/
|
||||||
float rse_math_deg_to_radians(float degrees);
|
float math_deg_to_radians(float degrees);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create an uniform matrix, the one with ones on diagonal
|
* @brief Create an uniform matrix, the one with ones on diagonal
|
||||||
*
|
*
|
||||||
* @return struct mat4_t Diagonal matrix
|
* @return struct mat4_t Diagonal matrix
|
||||||
*/
|
*/
|
||||||
struct mat4_t rse_math_uniform_mat4();
|
struct mat4_t math_uniform_mat4();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Normalizes provided vector. Changes the values inside the vector to range 0.0...1.0
|
* @brief Normalizes provided vector. Changes the values inside the vector to range 0.0...1.0
|
||||||
@@ -77,7 +77,7 @@ struct mat4_t rse_math_uniform_mat4();
|
|||||||
* @param vec Vector to normalize
|
* @param vec Vector to normalize
|
||||||
* @return struct vec3_t Normalized vector
|
* @return struct vec3_t Normalized vector
|
||||||
*/
|
*/
|
||||||
struct vec3_t rse_math_normalize_vec3(const struct vec3_t* vec);
|
struct vec3_t math_normalize_vec3(const struct vec3_t* vec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates vector cross product, a vector, using right hand rule. Note, that order of vectors is important
|
* @brief Creates vector cross product, a vector, using right hand rule. Note, that order of vectors is important
|
||||||
@@ -86,7 +86,7 @@ struct vec3_t rse_math_normalize_vec3(const struct vec3_t* vec);
|
|||||||
* @param vec2 Input vector
|
* @param vec2 Input vector
|
||||||
* @return struct vec3_t Resulting cross product vector
|
* @return struct vec3_t Resulting cross product vector
|
||||||
*/
|
*/
|
||||||
struct vec3_t rse_math_cross_vec3(const struct vec3_t* vec1, const struct vec3_t* vec2);
|
struct vec3_t math_cross_vec3(const struct vec3_t* vec1, const struct vec3_t* vec2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Calculates transformation matrix for viewing object from and eye cooridinates
|
* @brief Calculates transformation matrix for viewing object from and eye cooridinates
|
||||||
@@ -96,7 +96,7 @@ struct vec3_t rse_math_cross_vec3(const struct vec3_t* vec1, const struct vec3_t
|
|||||||
* @param up Where "up" is located. Usually (0, 1, 0), since Y is up in most cases
|
* @param up Where "up" is located. Usually (0, 1, 0), since Y is up in most cases
|
||||||
* @return struct mat4_t Resulting lootAtMatrix
|
* @return struct mat4_t Resulting lootAtMatrix
|
||||||
*/
|
*/
|
||||||
struct mat4_t rse_math_look_at(const struct vec3_t* eye, const struct vec3_t* center, const struct vec3_t* up);
|
struct mat4_t math_look_at(const struct vec3_t* eye, const struct vec3_t* center, const struct vec3_t* up);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates perspective matrix, used in projection
|
* @brief Creates perspective matrix, used in projection
|
||||||
@@ -107,7 +107,7 @@ struct mat4_t rse_math_look_at(const struct vec3_t* eye, const struct vec3_t* ce
|
|||||||
* @param z_far How far objects we can see
|
* @param z_far How far objects we can see
|
||||||
* @return struct mat4_t Resulting perspective matrix
|
* @return struct mat4_t Resulting perspective matrix
|
||||||
*/
|
*/
|
||||||
struct mat4_t rse_math_perspective(float fovy_rad, float aspect_ratio, float z_near, float z_far);
|
struct mat4_t math_perspective(float fovy_rad, float aspect_ratio, float z_near, float z_far);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Rotate matrix around vector for radians degrees
|
* @brief Rotate matrix around vector for radians degrees
|
||||||
@@ -117,6 +117,6 @@ struct mat4_t rse_math_perspective(float fovy_rad, float aspect_ratio, float z_n
|
|||||||
* @param rotation_vector Rotation vector
|
* @param rotation_vector Rotation vector
|
||||||
* @return struct mat4_t resulting matrix
|
* @return struct mat4_t resulting matrix
|
||||||
*/
|
*/
|
||||||
struct mat4_t rse_math_rotate(struct mat4_t matrix, float radians, struct vec3_t rotation_vector);
|
struct mat4_t math_rotate(struct mat4_t matrix, float radians, struct vec3_t rotation_vector);
|
||||||
|
|
||||||
#endif /* RSE_MATH_H */
|
#endif /* MATH_H */
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#include "vulkan_buffers.h"
|
#include "vulkan_buffers.h"
|
||||||
#include "vulkan_errors.h"
|
#include "vulkan_errors.h"
|
||||||
#include "utilities/rse_errors_common.h"
|
#include "utilities/errors_common.h"
|
||||||
#include "locale_vulkan.h"
|
|
||||||
#include "utilities/logger.h"
|
#include "utilities/logger.h"
|
||||||
|
#include "utilities/localization.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -12,34 +12,8 @@
|
|||||||
#define MESH_ID_FREE 0
|
#define MESH_ID_FREE 0
|
||||||
#define MESH_ID_TAKEN 1
|
#define MESH_ID_TAKEN 1
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Represents instance of a mesh and shows where it's located in instance buffer
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
struct rse_internal_instance_data_t
|
|
||||||
{
|
|
||||||
uint8_t instance_taken;
|
|
||||||
uint8_t instance_buffer_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
uint16_t create_mesh(struct graphics_context_t* context, struct vertex_t* vertices,
|
||||||
* @brief Mesh data, with unique id and dynamic arrays holding vertices and indices.
|
|
||||||
* One mesh can have multiple instances.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
struct rse_mesh_t
|
|
||||||
{
|
|
||||||
uint8_t is_mesh_id_taken;
|
|
||||||
uint32_t unique_id;
|
|
||||||
uint8_t instance_count;
|
|
||||||
struct rse_buffer_data_t vertex_data;
|
|
||||||
struct rse_buffer_data_t index_data;
|
|
||||||
struct rse_internal_instance_data_t instance_data[MAX_INSTANCE_NUMBER];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rse_mesh_t g_meshes[MAX_MESH_NUMBER] = {MESH_ID_FREE};
|
|
||||||
|
|
||||||
uint16_t create_mesh(struct rse_vertex_t* vertices,
|
|
||||||
uint16_t* indices,
|
uint16_t* indices,
|
||||||
size_t vertices_count,
|
size_t vertices_count,
|
||||||
size_t indices_count)
|
size_t indices_count)
|
||||||
@@ -47,71 +21,71 @@ uint16_t create_mesh(struct rse_vertex_t* vertices,
|
|||||||
size_t iter = 0U;
|
size_t iter = 0U;
|
||||||
|
|
||||||
for(iter = 0U; iter < MAX_MESH_NUMBER; ++iter) {
|
for(iter = 0U; iter < MAX_MESH_NUMBER; ++iter) {
|
||||||
if(g_meshes[iter].is_mesh_id_taken == MESH_ID_FREE) {
|
if(context->meshes[iter].is_mesh_id_taken == MESH_ID_FREE) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(iter >= MAX_MESH_NUMBER) {
|
if(iter >= MAX_MESH_NUMBER) {
|
||||||
LOGE(vulkan_messages[VULKAN_MESH_NO_FREE]);
|
LOGE(_("Could not allocate new mesh, reached maximum.\n"));
|
||||||
return MAX_MESH_NUMBER;
|
return MAX_MESH_NUMBER;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_meshes[iter].is_mesh_id_taken = MESH_ID_TAKEN;
|
context->meshes[iter].is_mesh_id_taken = MESH_ID_TAKEN;
|
||||||
g_meshes[iter].unique_id = iter;
|
context->meshes[iter].unique_id = iter;
|
||||||
g_meshes[iter].vertex_data.count = vertices_count;
|
context->meshes[iter].vertex_data.count = vertices_count;
|
||||||
g_meshes[iter].index_data.count = indices_count;
|
context->meshes[iter].index_data.count = indices_count;
|
||||||
g_meshes[iter].instance_count = 0;
|
context->meshes[iter].instance_count = 0;
|
||||||
memset(g_meshes[iter].instance_data, 0, sizeof(struct rse_internal_instance_data_t) * MAX_INSTANCE_NUMBER);
|
memset(context->meshes[iter].instance_data, 0, sizeof(struct internal_instance_data_t) * MAX_INSTANCE_NUMBER);
|
||||||
|
|
||||||
rse_add_vertices(iter, vertices, indices, &g_meshes[iter].vertex_data, &g_meshes[iter].index_data);
|
add_vertices(context, iter, vertices, indices, &context->meshes[iter].vertex_data, &context->meshes[iter].index_data);
|
||||||
|
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t create_mesh_instance(uint16_t mesh_id,
|
rse_err_t create_mesh_instance(struct graphics_context_t* context, uint16_t mesh_id,
|
||||||
struct rse_instance_data_t instance_data)
|
struct instance_data_t instance_data)
|
||||||
{
|
{
|
||||||
size_t iter = 0U;
|
size_t iter = 0U;
|
||||||
|
|
||||||
for(iter = 0U; iter < MAX_INSTANCE_NUMBER; ++iter) {
|
for(iter = 0U; iter < MAX_INSTANCE_NUMBER; ++iter) {
|
||||||
if(g_meshes[mesh_id].instance_data[iter].instance_taken == MESH_ID_FREE) {
|
if(context->meshes[mesh_id].instance_data[iter].instance_taken == MESH_ID_FREE) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(iter >= MAX_INSTANCE_NUMBER) {
|
if(iter >= MAX_INSTANCE_NUMBER) {
|
||||||
LOGE(vulkan_messages[VULKAN_MESH_NO_FREE]);
|
LOGE(_("Could not allocate new mesh, reached maximum.\n"));
|
||||||
return VULKAN_ERROR_MAX_INSTANCE_COUNT_REACHED;
|
return VULKAN_ERROR_MAX_INSTANCE_COUNT_REACHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_meshes[mesh_id].instance_data[iter].instance_taken = MESH_ID_TAKEN;
|
context->meshes[mesh_id].instance_data[iter].instance_taken = MESH_ID_TAKEN;
|
||||||
|
|
||||||
if(iter >= g_meshes[mesh_id].instance_count) {
|
if(iter >= context->meshes[mesh_id].instance_count) {
|
||||||
g_meshes[mesh_id].instance_count++;
|
context->meshes[mesh_id].instance_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_mesh_instances(mesh_id, &instance_data);
|
update_mesh_instances(context, mesh_id, &instance_data);
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t get_vertices_count(uint16_t mesh_id)
|
size_t get_vertices_count(struct graphics_context_t* context, uint16_t mesh_id)
|
||||||
{
|
{
|
||||||
return g_meshes[mesh_id].vertex_data.count;
|
return context->meshes[mesh_id].vertex_data.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t get_indices_count(uint16_t mesh_id)
|
size_t get_indices_count(struct graphics_context_t* context, uint16_t mesh_id)
|
||||||
{
|
{
|
||||||
return g_meshes[mesh_id].index_data.count;
|
return context->meshes[mesh_id].index_data.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t get_instances_count(uint16_t mesh_id)
|
size_t get_instances_count(struct graphics_context_t* context, uint16_t mesh_id)
|
||||||
{
|
{
|
||||||
return g_meshes[mesh_id].instance_count;
|
return context->meshes[mesh_id].instance_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t get_vertex_offset(uint16_t mesh_id)
|
size_t get_vertex_offset(struct graphics_context_t* context, uint16_t mesh_id)
|
||||||
{
|
{
|
||||||
return g_meshes[mesh_id].vertex_data.buffer_offset;
|
return context->meshes[mesh_id].vertex_data.buffer_offset;
|
||||||
}
|
}
|
||||||
@@ -9,11 +9,12 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_MESH_CONTROLLER_H
|
#ifndef MESH_CONTROLLER_H
|
||||||
#define RSE_MESH_CONTROLLER_H
|
#define MESH_CONTROLLER_H
|
||||||
|
|
||||||
#include "vulkan_commons.h"
|
#include "vulkan_commons.h"
|
||||||
#include "utilities/rse_commons.h"
|
#include "graphics_context.h"
|
||||||
|
#include "utilities/commons.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new mesh for provided vertices and indices.
|
* @brief Create a new mesh for provided vertices and indices.
|
||||||
@@ -24,7 +25,7 @@
|
|||||||
* @param indices_num indices count
|
* @param indices_num indices count
|
||||||
* @return uint16_t Mesh identifier. Can be useful for getting vertices, indices and instances
|
* @return uint16_t Mesh identifier. Can be useful for getting vertices, indices and instances
|
||||||
*/
|
*/
|
||||||
uint16_t create_mesh(struct rse_vertex_t* vertices,
|
uint16_t create_mesh(struct graphics_context_t* context, struct vertex_t* vertices,
|
||||||
uint16_t* indices,
|
uint16_t* indices,
|
||||||
size_t vertices_num,
|
size_t vertices_num,
|
||||||
size_t indices_num);
|
size_t indices_num);
|
||||||
@@ -34,8 +35,8 @@ uint16_t create_mesh(struct rse_vertex_t* vertices,
|
|||||||
* @param mesh_id Mesh id
|
* @param mesh_id Mesh id
|
||||||
* @param instance_data Transformation info
|
* @param instance_data Transformation info
|
||||||
*/
|
*/
|
||||||
rse_err_t create_mesh_instance(uint16_t mesh_id,
|
rse_err_t create_mesh_instance(struct graphics_context_t* context, uint16_t mesh_id,
|
||||||
struct rse_instance_data_t instance_data);
|
struct instance_data_t instance_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the vertex count for mesh with mesh_id ID
|
* @brief Get the vertex count for mesh with mesh_id ID
|
||||||
@@ -43,7 +44,7 @@ rse_err_t create_mesh_instance(uint16_t mesh_id,
|
|||||||
* @param mesh_id Mesh identifier
|
* @param mesh_id Mesh identifier
|
||||||
* @return size_t Number of vertices
|
* @return size_t Number of vertices
|
||||||
*/
|
*/
|
||||||
size_t get_vertices_count(uint16_t mesh_id);
|
size_t get_vertices_count(struct graphics_context_t* context, uint16_t mesh_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the index count for mesh with mesh_id ID
|
* @brief Get the index count for mesh with mesh_id ID
|
||||||
@@ -51,7 +52,7 @@ size_t get_vertices_count(uint16_t mesh_id);
|
|||||||
* @param mesh_id Mesh identifier
|
* @param mesh_id Mesh identifier
|
||||||
* @return size_t Number of indices
|
* @return size_t Number of indices
|
||||||
*/
|
*/
|
||||||
size_t get_indices_count(uint16_t mesh_id);
|
size_t get_indices_count(struct graphics_context_t* context, uint16_t mesh_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the instance count for mesh with mesh_id ID
|
* @brief Get the instance count for mesh with mesh_id ID
|
||||||
@@ -59,7 +60,7 @@ size_t get_indices_count(uint16_t mesh_id);
|
|||||||
* @param mesh_id Mesh identifier
|
* @param mesh_id Mesh identifier
|
||||||
* @return size_t Number of instances
|
* @return size_t Number of instances
|
||||||
*/
|
*/
|
||||||
size_t get_instances_count(uint16_t mesh_id);
|
size_t get_instances_count(struct graphics_context_t* context, uint16_t mesh_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get vertex offset in vertex buffer for selected mesh
|
* @brief Get vertex offset in vertex buffer for selected mesh
|
||||||
@@ -67,6 +68,6 @@ size_t get_instances_count(uint16_t mesh_id);
|
|||||||
* @param mesh_id Mesh identifies
|
* @param mesh_id Mesh identifies
|
||||||
* @return size_t Offset
|
* @return size_t Offset
|
||||||
*/
|
*/
|
||||||
size_t get_vertex_offset(uint16_t mesh_id);
|
size_t get_vertex_offset(struct graphics_context_t* context, uint16_t mesh_id);
|
||||||
|
|
||||||
#endif /* RSE_MESH_CONTROLLER_H */
|
#endif /* MESH_CONTROLLER_H */
|
||||||
@@ -0,0 +1,859 @@
|
|||||||
|
/**
|
||||||
|
* @file pipeline_builder.c
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-03-01
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pipeline_builder.h"
|
||||||
|
|
||||||
|
#include "utilities/commons.h"
|
||||||
|
#include "utilities/errors_common.h"
|
||||||
|
#include "utilities/file_utils.h"
|
||||||
|
#include "utilities/linked_list.h"
|
||||||
|
#include "utilities/localization.h"
|
||||||
|
#include "vulkan/vulkan_core.h"
|
||||||
|
#include "vulkan_errors.h"
|
||||||
|
#include "vulkan_image.h"
|
||||||
|
|
||||||
|
#define MAX_BINDLESS_RESOURCES 1000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates shader module
|
||||||
|
*
|
||||||
|
* @param binary_data Shader compiled code
|
||||||
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||||
|
*/
|
||||||
|
static rse_err_t create_shader_module(struct graphics_context_t* context,
|
||||||
|
struct pipeline_t* pipeline,
|
||||||
|
const char* binary_data, size_t data_size)
|
||||||
|
{
|
||||||
|
VkShaderModuleCreateInfo create_info = {};
|
||||||
|
|
||||||
|
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
create_info.pNext = NULL;
|
||||||
|
create_info.flags = 0U;
|
||||||
|
create_info.codeSize = data_size;
|
||||||
|
create_info.pCode = (const uint32_t*)(binary_data);
|
||||||
|
|
||||||
|
RSE_LINKED_LIST_PUSH_FRONT(context->shader_modules, (VkShaderModule){0});
|
||||||
|
|
||||||
|
if (VK_SUCCESS != vkCreateShaderModule(
|
||||||
|
context->device, &create_info, NULL,
|
||||||
|
&RSE_LINKED_LIST_FRONT(context->shader_modules))) {
|
||||||
|
LOGF(_("Failed to create a shader\n"));
|
||||||
|
return VULKAN_ERROR_SHADER_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rse_err_t pipeline_add_input_assembly(struct pipeline_t* pipeline)
|
||||||
|
{
|
||||||
|
/* For now input assebly is hardcoded */
|
||||||
|
pipeline->input_assembly.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
pipeline->input_assembly.pNext = NULL;
|
||||||
|
pipeline->input_assembly.flags = 0U;
|
||||||
|
pipeline->input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
pipeline->input_assembly.primitiveRestartEnable = VK_FALSE;
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rse_err_t pipeline_add_viewport_state(struct pipeline_t* pipeline)
|
||||||
|
{
|
||||||
|
/* For now viewport is hardcoded */
|
||||||
|
pipeline->viewport_state.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
pipeline->viewport_state.pNext = NULL;
|
||||||
|
pipeline->viewport_state.flags = 0U;
|
||||||
|
pipeline->viewport_state.viewportCount = 1U;
|
||||||
|
pipeline->viewport_state.pViewports =
|
||||||
|
NULL; /* This is set during rendering */
|
||||||
|
pipeline->viewport_state.scissorCount = 1U;
|
||||||
|
pipeline->viewport_state.pScissors =
|
||||||
|
NULL; /* This is set during rendering */
|
||||||
|
|
||||||
|
if (pipeline->viewport_state.pViewports == NULL ||
|
||||||
|
pipeline->viewport_state.viewportCount == 0U) {
|
||||||
|
RSE_STACK_PUSH(pipeline->required_dynamic_states,
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeline->viewport_state.pScissors == NULL ||
|
||||||
|
pipeline->viewport_state.scissorCount == 0U) {
|
||||||
|
RSE_STACK_PUSH(pipeline->required_dynamic_states,
|
||||||
|
VK_DYNAMIC_STATE_SCISSOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rse_err_t pipeline_add_rasterizer(struct pipeline_t* pipeline)
|
||||||
|
{
|
||||||
|
/* For now rasterizer is hardcoded */
|
||||||
|
pipeline->rasterizer.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
pipeline->rasterizer.pNext = NULL;
|
||||||
|
pipeline->rasterizer.flags = 0U;
|
||||||
|
pipeline->rasterizer.depthClampEnable =
|
||||||
|
VK_FALSE; /* VK_TRUE to play with shadow maps */
|
||||||
|
pipeline->rasterizer.rasterizerDiscardEnable =
|
||||||
|
VK_FALSE; /* Disable/Enable output to framebuffer*/
|
||||||
|
pipeline->rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
pipeline->rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
|
pipeline->rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
pipeline->rasterizer.depthBiasEnable = VK_FALSE;
|
||||||
|
pipeline->rasterizer.depthBiasConstantFactor = 0.0f;
|
||||||
|
pipeline->rasterizer.depthBiasClamp = 0.0f;
|
||||||
|
pipeline->rasterizer.depthBiasSlopeFactor = 0.0f;
|
||||||
|
pipeline->rasterizer.lineWidth = 1.0f;
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rse_err_t pipeline_add_multisampling(struct pipeline_t* pipeline)
|
||||||
|
{
|
||||||
|
/* For now multisampling is hardcoded */
|
||||||
|
pipeline->multisampling.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
pipeline->multisampling.pNext = NULL;
|
||||||
|
pipeline->multisampling.flags = 0U;
|
||||||
|
pipeline->multisampling.rasterizationSamples = VK_SAMPLE_COUNT_16_BIT;
|
||||||
|
pipeline->multisampling.sampleShadingEnable = VK_FALSE;
|
||||||
|
pipeline->multisampling.minSampleShading = 1.0f;
|
||||||
|
pipeline->multisampling.pSampleMask = NULL;
|
||||||
|
pipeline->multisampling.alphaToCoverageEnable = VK_FALSE;
|
||||||
|
pipeline->multisampling.alphaToOneEnable = VK_FALSE;
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rse_err_t pipeline_add_color_blending(struct pipeline_t* pipeline)
|
||||||
|
{
|
||||||
|
/* For now color blending is hardcoded */
|
||||||
|
pipeline->color_blend_attachment.colorWriteMask =
|
||||||
|
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||||
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||||
|
pipeline->color_blend_attachment.blendEnable = VK_TRUE;
|
||||||
|
pipeline->color_blend_attachment.srcColorBlendFactor =
|
||||||
|
VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
pipeline->color_blend_attachment.dstColorBlendFactor =
|
||||||
|
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
pipeline->color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
pipeline->color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
pipeline->color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||||
|
pipeline->color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
|
||||||
|
pipeline->color_blending.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
pipeline->color_blending.pNext = NULL;
|
||||||
|
pipeline->color_blending.flags = 0U;
|
||||||
|
pipeline->color_blending.logicOpEnable = VK_FALSE;
|
||||||
|
pipeline->color_blending.logicOp = VK_LOGIC_OP_COPY;
|
||||||
|
pipeline->color_blending.attachmentCount = 1U;
|
||||||
|
pipeline->color_blending.pAttachments = &pipeline->color_blend_attachment;
|
||||||
|
pipeline->color_blending.blendConstants[0] = 0.0f;
|
||||||
|
pipeline->color_blending.blendConstants[1] = 0.0f;
|
||||||
|
pipeline->color_blending.blendConstants[2] = 0.0f;
|
||||||
|
pipeline->color_blending.blendConstants[3] = 0.0f;
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rse_err_t pipeline_add_depth_stencil(struct pipeline_t* pipeline)
|
||||||
|
{
|
||||||
|
/* For now depth stencil is hardcoded */
|
||||||
|
pipeline->depth_stencil.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||||
|
pipeline->depth_stencil.pNext = NULL;
|
||||||
|
pipeline->depth_stencil.flags = 0U;
|
||||||
|
pipeline->depth_stencil.depthTestEnable = VK_TRUE;
|
||||||
|
pipeline->depth_stencil.depthWriteEnable = VK_TRUE;
|
||||||
|
pipeline->depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS;
|
||||||
|
pipeline->depth_stencil.depthBoundsTestEnable = VK_FALSE;
|
||||||
|
pipeline->depth_stencil.stencilTestEnable = VK_FALSE;
|
||||||
|
pipeline->depth_stencil.minDepthBounds = 0.0f;
|
||||||
|
pipeline->depth_stencil.maxDepthBounds = 1.0f;
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Pipeline Layout
|
||||||
|
*
|
||||||
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED
|
||||||
|
*/
|
||||||
|
static rse_err_t create_pipeline_layout(struct graphics_context_t* context)
|
||||||
|
{
|
||||||
|
VkPipelineLayoutCreateInfo create_info = {};
|
||||||
|
create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
create_info.pNext = NULL;
|
||||||
|
create_info.flags = 0U;
|
||||||
|
create_info.setLayoutCount =
|
||||||
|
context->pipelines_data.descriptor_set_layouts_count;
|
||||||
|
create_info.pSetLayouts = context->pipelines_data.descriptor_set_layouts;
|
||||||
|
create_info.pushConstantRangeCount = 0U;
|
||||||
|
create_info.pPushConstantRanges = NULL;
|
||||||
|
|
||||||
|
if (VK_SUCCESS !=
|
||||||
|
vkCreatePipelineLayout(context->device, &create_info, NULL,
|
||||||
|
&context->pipelines_data.pipeline_layout)) {
|
||||||
|
LOGF(_("Failed to create pipeline layout\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Render Pass
|
||||||
|
*
|
||||||
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_RENDERPASS_CREATION_FAILED
|
||||||
|
*/
|
||||||
|
static rse_err_t create_render_pass(struct graphics_context_t* context)
|
||||||
|
{
|
||||||
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
VkAttachmentDescription attachments[3] = {};
|
||||||
|
VkAttachmentDescription color_attachment = {};
|
||||||
|
VkAttachmentReference color_attachment_ref = {};
|
||||||
|
VkAttachmentDescription color_attachment_resolve = {};
|
||||||
|
VkAttachmentReference color_attachment_resolve_ref = {};
|
||||||
|
VkSubpassDescription subpass = {};
|
||||||
|
VkRenderPassCreateInfo renderpass_info = {};
|
||||||
|
VkAttachmentDescription depth_attachment = {};
|
||||||
|
VkAttachmentReference depth_attachment_ref = {};
|
||||||
|
VkSubpassDependency dependency = {};
|
||||||
|
|
||||||
|
STATUS_CHECK(find_depth_format(context, &depth_attachment.format));
|
||||||
|
|
||||||
|
depth_attachment.samples = VK_SAMPLE_COUNT_16_BIT;
|
||||||
|
depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
depth_attachment.finalLayout =
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
depth_attachment_ref.attachment = 1;
|
||||||
|
depth_attachment_ref.layout =
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
color_attachment.flags = 0U;
|
||||||
|
color_attachment.format = IMAGE_FORMAT;
|
||||||
|
color_attachment.samples = VK_SAMPLE_COUNT_16_BIT;
|
||||||
|
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
color_attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
color_attachment_ref.attachment = 0;
|
||||||
|
color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
color_attachment_resolve.format = IMAGE_FORMAT;
|
||||||
|
color_attachment_resolve.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
color_attachment_resolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
color_attachment_resolve.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
color_attachment_resolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
color_attachment_resolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
color_attachment_resolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
color_attachment_resolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
|
||||||
|
color_attachment_resolve_ref.attachment = 2;
|
||||||
|
color_attachment_resolve_ref.layout =
|
||||||
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
subpass.colorAttachmentCount = 1;
|
||||||
|
subpass.pColorAttachments = &color_attachment_ref;
|
||||||
|
subpass.pDepthStencilAttachment = &depth_attachment_ref;
|
||||||
|
subpass.pResolveAttachments = &color_attachment_resolve_ref;
|
||||||
|
|
||||||
|
attachments[0] = color_attachment;
|
||||||
|
attachments[1] = depth_attachment;
|
||||||
|
attachments[2] = color_attachment_resolve;
|
||||||
|
|
||||||
|
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||||
|
dependency.dstSubpass = 0;
|
||||||
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||||
|
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||||
|
dependency.srcAccessMask = 0;
|
||||||
|
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||||
|
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||||
|
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||||
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
|
|
||||||
|
renderpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
renderpass_info.attachmentCount = 3;
|
||||||
|
renderpass_info.pAttachments = attachments;
|
||||||
|
renderpass_info.subpassCount = 1;
|
||||||
|
renderpass_info.pSubpasses = &subpass;
|
||||||
|
renderpass_info.dependencyCount = 1;
|
||||||
|
renderpass_info.pDependencies = &dependency;
|
||||||
|
|
||||||
|
if (VK_SUCCESS != vkCreateRenderPass(context->device, &renderpass_info,
|
||||||
|
NULL, &context->render_pass)) {
|
||||||
|
LOGF(_("Failed to create render pass\n"));
|
||||||
|
return VULKAN_ERROR_RENDERPASS_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clean up pipeline builder. This function should be called after all
|
||||||
|
* pipelines are built and no more pipelines are needed. It frees all resources
|
||||||
|
* used by pipeline builder.
|
||||||
|
*
|
||||||
|
* @param[in/out] pipelines List of pipelines to clean up
|
||||||
|
*/
|
||||||
|
static void pipeline_builder_cleanup(struct pipeline_infos_list_t* pipelines)
|
||||||
|
{
|
||||||
|
size_t pipeline_count = RSE_LINKED_LIST_SIZE(pipelines);
|
||||||
|
VkVertexInputBindingDescription* vertex_bindings = NULL;
|
||||||
|
VkVertexInputAttributeDescription* shader_attributes = NULL;
|
||||||
|
VkDynamicState* dynamic_states = NULL;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pipeline_count; i++) {
|
||||||
|
VkGraphicsPipelineCreateInfo* pipeline_info =
|
||||||
|
&RSE_LINKED_LIST_FRONT(pipelines);
|
||||||
|
if (pipeline_info != NULL) {
|
||||||
|
vertex_bindings =
|
||||||
|
(VkVertexInputBindingDescription*)pipeline_info
|
||||||
|
->pVertexInputState->pVertexBindingDescriptions;
|
||||||
|
|
||||||
|
shader_attributes =
|
||||||
|
(VkVertexInputAttributeDescription*)pipeline_info
|
||||||
|
->pVertexInputState->pVertexAttributeDescriptions;
|
||||||
|
|
||||||
|
dynamic_states =
|
||||||
|
(VkDynamicState*)pipeline_info->pDynamicState->pDynamicStates;
|
||||||
|
|
||||||
|
rse_free(vertex_bindings);
|
||||||
|
rse_free(shader_attributes);
|
||||||
|
rse_free(dynamic_states);
|
||||||
|
}
|
||||||
|
RSE_LINKED_LIST_POP_FRONT(pipelines);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RSE_LINKED_LIST_IS_EMPTY(pipelines) == 0) {
|
||||||
|
LOGF(_("Failed to clean up pipelines\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Descriptor Pool
|
||||||
|
*
|
||||||
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED
|
||||||
|
*/
|
||||||
|
static rse_err_t create_descriptor_pool(struct graphics_context_t* context, struct binding_info_t* binding_infos, size_t binding_count)
|
||||||
|
{
|
||||||
|
VkDescriptorPoolSize pool_sizes[2] = {};
|
||||||
|
VkDescriptorPoolCreateInfo pool_info = {};
|
||||||
|
|
||||||
|
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
pool_sizes[0].descriptorCount = (uint32_t)(SWAP_BUFFER_COUNT);
|
||||||
|
|
||||||
|
pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
pool_sizes[1].descriptorCount = MAX_BINDLESS_RESOURCES;
|
||||||
|
|
||||||
|
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
pool_info.poolSizeCount = 1;
|
||||||
|
pool_info.pPoolSizes = &pool_sizes[0];
|
||||||
|
|
||||||
|
pool_info.maxSets = (uint32_t)(SWAP_BUFFER_COUNT);
|
||||||
|
if (vkCreateDescriptorPool(context->device, &pool_info, NULL,
|
||||||
|
&context->descriptor_pool) != VK_SUCCESS) {
|
||||||
|
LOGF(_("Failed to create descriptor pool\n"));
|
||||||
|
return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT;
|
||||||
|
pool_info.maxSets = MAX_BINDLESS_RESOURCES * 2;
|
||||||
|
pool_info.pPoolSizes = &pool_sizes[1];
|
||||||
|
|
||||||
|
if (vkCreateDescriptorPool(context->device, &pool_info, NULL,
|
||||||
|
&context->descriptor_pool_bindless) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
|
LOGF(_("Failed to create descriptor pool\n"));
|
||||||
|
return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Descriptor Sets
|
||||||
|
*
|
||||||
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED */
|
||||||
|
static rse_err_t create_descriptor_sets(struct graphics_context_t* context)
|
||||||
|
{
|
||||||
|
uint32_t max_binding = MAX_BINDLESS_RESOURCES - 1;
|
||||||
|
VkDescriptorSetLayout layouts[SWAP_BUFFER_COUNT] = {
|
||||||
|
context->descriptor_set_layout, context->descriptor_set_layout};
|
||||||
|
VkDescriptorSetLayout layouts_bindless[SWAP_BUFFER_COUNT] = {
|
||||||
|
context->descriptor_set_layout_bindless,
|
||||||
|
context->descriptor_set_layout_bindless};
|
||||||
|
VkDescriptorSetAllocateInfo allocInfo = {};
|
||||||
|
VkDescriptorSetAllocateInfo allocInfo_bindless = {};
|
||||||
|
VkDescriptorSetVariableDescriptorCountAllocateInfoEXT count_info = {};
|
||||||
|
|
||||||
|
count_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT;
|
||||||
|
count_info.descriptorSetCount = 1;
|
||||||
|
count_info.pDescriptorCounts = &max_binding;
|
||||||
|
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
allocInfo.descriptorPool = context->descriptor_pool;
|
||||||
|
allocInfo.descriptorSetCount = (uint32_t)(SWAP_BUFFER_COUNT);
|
||||||
|
allocInfo.pSetLayouts = layouts;
|
||||||
|
|
||||||
|
allocInfo_bindless = allocInfo;
|
||||||
|
allocInfo_bindless.descriptorPool = context->descriptor_pool_bindless;
|
||||||
|
allocInfo_bindless.pSetLayouts = layouts_bindless;
|
||||||
|
allocInfo_bindless.pNext = &count_info;
|
||||||
|
allocInfo_bindless.descriptorSetCount = 1;
|
||||||
|
|
||||||
|
if (vkAllocateDescriptorSets(context->device, &allocInfo,
|
||||||
|
context->descriptor_sets) != VK_SUCCESS) {
|
||||||
|
LOGF(_("Failed to allocate descriptor sets\n"));
|
||||||
|
return VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vkAllocateDescriptorSets(context->device, &allocInfo_bindless,
|
||||||
|
&context->descriptor_sets_bindless) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
|
LOGF(_("Failed to allocate descriptor sets\n"));
|
||||||
|
return VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) {
|
||||||
|
VkDescriptorBufferInfo buffer_info = {};
|
||||||
|
VkWriteDescriptorSet descriptor_writes[2] = {};
|
||||||
|
VkDescriptorImageInfo image_infos[RSE_MAX_IMAGE_COUNT] = {};
|
||||||
|
size_t image_iterator = 0U;
|
||||||
|
size_t image_info_iterator = 0U;
|
||||||
|
|
||||||
|
buffer_info.buffer = context->uniform_buffers[i].buffer;
|
||||||
|
buffer_info.offset = 0;
|
||||||
|
buffer_info.range = sizeof(struct uniform_buffer_object_t);
|
||||||
|
|
||||||
|
for (image_iterator = 0U; image_iterator < RSE_MAX_IMAGE_COUNT;
|
||||||
|
++image_iterator) {
|
||||||
|
if (image_exists(context, image_iterator)) {
|
||||||
|
image_infos[image_info_iterator].imageLayout =
|
||||||
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
image_infos[image_info_iterator].imageView =
|
||||||
|
context->swapchain_image_views[image_iterator];
|
||||||
|
image_infos[image_info_iterator].sampler = context->sampler;
|
||||||
|
image_info_iterator++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
descriptor_writes[0].dstSet = context->descriptor_sets[i];
|
||||||
|
descriptor_writes[0].dstBinding = 0;
|
||||||
|
descriptor_writes[0].dstArrayElement = 0;
|
||||||
|
descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
descriptor_writes[0].descriptorCount = 1;
|
||||||
|
descriptor_writes[0].pBufferInfo = &buffer_info;
|
||||||
|
|
||||||
|
descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
descriptor_writes[1].dstSet = context->descriptor_sets_bindless;
|
||||||
|
descriptor_writes[1].dstBinding = 1;
|
||||||
|
descriptor_writes[1].dstArrayElement = 0;
|
||||||
|
descriptor_writes[1].descriptorType =
|
||||||
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
descriptor_writes[1].descriptorCount = image_info_iterator;
|
||||||
|
descriptor_writes[1].pImageInfo = image_infos;
|
||||||
|
|
||||||
|
vkUpdateDescriptorSets(context->device, 2, descriptor_writes, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_err_t pipeline_add_dynamic_state(struct pipeline_t* pipeline,
|
||||||
|
VkDynamicState dynamic_state)
|
||||||
|
{
|
||||||
|
if (dynamic_state >= VK_DYNAMIC_STATE_MAX_ENUM) {
|
||||||
|
LOGF(_("Invalid dynamic state in pipeline\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_INVALID_DYNAMIC_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
RSE_LINKED_LIST_PUSH_FRONT(pipeline->dynamic_states, dynamic_state);
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_err_t pipeline_builder_init(struct pipeline_t* pipeline)
|
||||||
|
{
|
||||||
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
|
||||||
|
if (pipeline != NULL) {
|
||||||
|
LOGF(
|
||||||
|
_("Pipeline is not NULL. This function will initialize everything "
|
||||||
|
"for you, no need for manual allocation\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_ALREADY_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_malloc(pipeline, sizeof(struct pipeline_t));
|
||||||
|
rse_memset(pipeline, 0, sizeof(struct pipeline_t));
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_err_t pipeline_add_shader_stage(struct graphics_context_t* context,
|
||||||
|
struct pipeline_t* pipeline,
|
||||||
|
const char* shader_path,
|
||||||
|
const VkShaderStageFlagBits shader_stage)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
char* buffer = NULL;
|
||||||
|
size_t buffer_size = 0U;
|
||||||
|
|
||||||
|
/* Check if we have enough space for new shader stages */
|
||||||
|
if (pipeline->shader_stages_count + 1 > MAX_SHADER_STAGES) {
|
||||||
|
LOGF(_("Too many shader stages in pipeline\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_TOO_MANY_SHADER_STAGES;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = pipeline->shader_stages_count++;
|
||||||
|
|
||||||
|
/* Check if shader module is valid */
|
||||||
|
if (shader_stage >= VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM) {
|
||||||
|
LOGF(_("Invalid shader stage in pipeline\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_INVALID_SHADER_STAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read shader file */
|
||||||
|
read_file(shader_path, &buffer_size, NULL);
|
||||||
|
rse_malloc(buffer, buffer_size);
|
||||||
|
read_file(shader_path, &buffer_size, buffer);
|
||||||
|
|
||||||
|
STATUS_CHECK(create_shader_module(context, pipeline, buffer, buffer_size));
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
pipeline->shader_stages[i].sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
pipeline->shader_stages[i].pNext = NULL;
|
||||||
|
pipeline->shader_stages[i].flags = 0U;
|
||||||
|
pipeline->shader_stages[i].stage = shader_stage;
|
||||||
|
pipeline->shader_stages[i].module = RSE_LINKED_LIST_FRONT(
|
||||||
|
context->shader_modules); /* This is automatically updated during
|
||||||
|
shader module creation */
|
||||||
|
pipeline->shader_stages[i].pName = "main";
|
||||||
|
pipeline->shader_stages[i].pSpecializationInfo = NULL;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_err_t pipeline_add_vertex_input_binding(struct pipeline_t* pipeline,
|
||||||
|
const uint8_t binding,
|
||||||
|
const uint8_t stride,
|
||||||
|
const VkVertexInputRate input_rate)
|
||||||
|
{
|
||||||
|
VkVertexInputBindingDescription binding_pipeline_description = {};
|
||||||
|
if (input_rate >= VK_VERTEX_INPUT_RATE_MAX_ENUM) {
|
||||||
|
LOGF(_("Invalid vertex input rate\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_INVALID_VERTEX_INPUT_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
binding_pipeline_description.binding = binding;
|
||||||
|
binding_pipeline_description.stride = stride;
|
||||||
|
binding_pipeline_description.inputRate = input_rate;
|
||||||
|
|
||||||
|
RSE_LINKED_LIST_PUSH_FRONT(pipeline->vertex_bindings,
|
||||||
|
binding_pipeline_description);
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_err_t pipeline_add_vertex_input_attribute(struct pipeline_t* pipeline,
|
||||||
|
const uint8_t binding,
|
||||||
|
const uint8_t location,
|
||||||
|
const VkFormat format,
|
||||||
|
const uint8_t offset)
|
||||||
|
{
|
||||||
|
VkVertexInputAttributeDescription attribute_description = {};
|
||||||
|
if (binding >= 16U) {
|
||||||
|
LOGF(_("Invalid binding in pipeline attribute description\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_INVALID_BINDING;
|
||||||
|
}
|
||||||
|
if (format >= VK_FORMAT_MAX_ENUM) {
|
||||||
|
LOGF(_("Invalid format in pipeline attribute description\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_INVALID_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_description.binding = binding;
|
||||||
|
attribute_description.location = location;
|
||||||
|
attribute_description.format = format;
|
||||||
|
attribute_description.offset = offset;
|
||||||
|
|
||||||
|
RSE_LINKED_LIST_PUSH_FRONT(pipeline->shader_attributes,
|
||||||
|
attribute_description);
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_err_t pipeline_add_descriptor_layout(struct graphics_context_t* context,
|
||||||
|
struct binding_info_t* binding_infos,
|
||||||
|
size_t binding_count,
|
||||||
|
size_t* descriptor_set_index)
|
||||||
|
{
|
||||||
|
VkDescriptorSetLayoutCreateInfo layout_info = {};
|
||||||
|
VkDescriptorSetLayoutBinding* bindings = NULL;
|
||||||
|
VkDescriptorSetLayoutBindingFlagsCreateInfoEXT extended_info = {0};
|
||||||
|
VkDescriptorBindingFlags bindless_flags =
|
||||||
|
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT |
|
||||||
|
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT |
|
||||||
|
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT;
|
||||||
|
|
||||||
|
if (binding_count == 0) {
|
||||||
|
LOGF(_("No bindings in descriptor set layout\n"));
|
||||||
|
return VULKAN_ERROR_DESCRIPTORSETLAYOUT_NO_BINDINGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->pipelines_data.descriptor_set_layouts_count + 1 >
|
||||||
|
MAX_DESCRIPTOR_SETS) {
|
||||||
|
LOGF(_("Too many descriptor sets\n"));
|
||||||
|
return VULKAN_ERROR_DESCRIPTORSETLAYOUT_TOO_MANY;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_malloc(bindings, sizeof(VkDescriptorSetLayoutBinding) * binding_count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < binding_count; i++) {
|
||||||
|
bindings[i].binding = binding_infos[i].binding;
|
||||||
|
bindings[i].descriptorType = binding_infos[i].descriptor_type;
|
||||||
|
bindings[i].descriptorCount = 1;
|
||||||
|
bindings[i].stageFlags = binding_infos[i].stage_flags;
|
||||||
|
bindings[i].pImmutableSamplers = NULL;
|
||||||
|
|
||||||
|
if (bindings[i].descriptorType ==
|
||||||
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
|
||||||
|
bindings[i].pImmutableSamplers = NULL;
|
||||||
|
bindings[i].descriptorCount = MAX_BINDLESS_RESOURCES;
|
||||||
|
|
||||||
|
extended_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT;
|
||||||
|
extended_info.bindingCount++;
|
||||||
|
extended_info.pBindingFlags = &bindless_flags;
|
||||||
|
|
||||||
|
layout_info.pNext = &extended_info;
|
||||||
|
layout_info.flags =
|
||||||
|
VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
layout_info.bindingCount = (uint32_t)binding_count;
|
||||||
|
layout_info.pBindings = bindings;
|
||||||
|
|
||||||
|
if (vkCreateDescriptorSetLayout(
|
||||||
|
context->device, &layout_info, NULL,
|
||||||
|
&context->pipelines_data.descriptor_set_layouts
|
||||||
|
[context->pipelines_data.descriptor_set_layouts_count]) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
|
LOGF(_("Failed to create descriptor set layout\n"));
|
||||||
|
return VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
*descriptor_set_index =
|
||||||
|
context->pipelines_data.descriptor_set_layouts_count;
|
||||||
|
context->pipelines_data.descriptor_set_layouts_count++;
|
||||||
|
|
||||||
|
rse_free(bindings);
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rse_err_t build_pipelines(struct graphics_context_t* context,
|
||||||
|
struct pipeline_infos_list_t* pipelines)
|
||||||
|
{
|
||||||
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
size_t pipelines_count = RSE_LINKED_LIST_SIZE(pipelines);
|
||||||
|
VkGraphicsPipelineCreateInfo* pipeline_infos = NULL;
|
||||||
|
|
||||||
|
context->pipelines_data.pipelines_count = pipelines_count;
|
||||||
|
|
||||||
|
create_pipeline_layout(context);
|
||||||
|
create_render_pass(context);
|
||||||
|
create_descriptor_pool(context, NULL, 0);
|
||||||
|
|
||||||
|
rse_malloc(pipeline_infos,
|
||||||
|
sizeof(VkGraphicsPipelineCreateInfo) * pipelines_count);
|
||||||
|
|
||||||
|
RSE_LINKED_LIST_TO_ARRAY(pipelines, pipeline_infos);
|
||||||
|
|
||||||
|
if (VK_SUCCESS !=
|
||||||
|
vkCreateGraphicsPipelines(context->device, VK_NULL_HANDLE,
|
||||||
|
pipelines_count, pipeline_infos, NULL,
|
||||||
|
context->pipelines_data.pipelines)) {
|
||||||
|
LOGF(_("Failed to create graphics pipelines\n"));
|
||||||
|
status = VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_free(pipeline_infos);
|
||||||
|
pipeline_builder_cleanup(pipelines);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_err_t add_pipeline(const struct graphics_context_t* context,
|
||||||
|
struct pipeline_t* pipeline,
|
||||||
|
struct pipeline_infos_list_t* pipelines)
|
||||||
|
{
|
||||||
|
/* Check for send and required dynamic states */
|
||||||
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
VkGraphicsPipelineCreateInfo pipeline_info = {};
|
||||||
|
|
||||||
|
size_t vertex_bindings_count = 0U;
|
||||||
|
VkVertexInputBindingDescription* vertex_bindings = NULL;
|
||||||
|
|
||||||
|
size_t shader_attributes_count = 0U;
|
||||||
|
VkVertexInputAttributeDescription* shader_attributes = NULL;
|
||||||
|
|
||||||
|
size_t dynamic_states_count = 0U;
|
||||||
|
VkDynamicState* dynamic_states = NULL;
|
||||||
|
|
||||||
|
uint8_t dynamic_state_found = 0;
|
||||||
|
while (RSE_STACK_IS_EMPTY(pipeline->required_dynamic_states) == 0) {
|
||||||
|
dynamic_state_found = 0;
|
||||||
|
VkDynamicState dynamic_state =
|
||||||
|
RSE_STACK_POP(pipeline->required_dynamic_states);
|
||||||
|
RSE_LINKED_LIST_FOREACH(pipeline->dynamic_states, dynamic_state_ptr)
|
||||||
|
{
|
||||||
|
if (dynamic_state_ptr->data == dynamic_state) {
|
||||||
|
dynamic_state_found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dynamic_state_found == 0) {
|
||||||
|
LOGF(_("Missing dynamic state in pipeline\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_MISSING_DYNAMIC_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for shader modules */
|
||||||
|
if (RSE_LINKED_LIST_IS_EMPTY(context->shader_modules) == 1) {
|
||||||
|
LOGF(_("Missing shader modules in pipeline\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_MISSING_SHADER_MODULES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for required shader stages */
|
||||||
|
if (pipeline->shader_stages_count == 0) {
|
||||||
|
LOGF(
|
||||||
|
_("Missing shader stages in pipeline. There must be at least "
|
||||||
|
"one.\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_MISSING_SHADER_STAGES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for required vertex bindings */
|
||||||
|
if (pipeline->vertex_bindings == NULL) {
|
||||||
|
LOGF(_("Missing vertex bindings in pipeline\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_MISSING_VERTEX_BINDINGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for required shader attributes */
|
||||||
|
if (pipeline->shader_attributes == NULL) {
|
||||||
|
LOGF(_("Missing shader attributes in pipeline\n"));
|
||||||
|
return VULKAN_ERROR_PIPELINE_MISSING_SHADER_ATTRIBUTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert linked list to array */
|
||||||
|
vertex_bindings_count =
|
||||||
|
RSE_LINKED_LIST_TO_ARRAY(pipeline->vertex_bindings, vertex_bindings);
|
||||||
|
shader_attributes_count = RSE_LINKED_LIST_TO_ARRAY(
|
||||||
|
pipeline->shader_attributes, shader_attributes);
|
||||||
|
dynamic_states_count =
|
||||||
|
RSE_LINKED_LIST_TO_ARRAY(pipeline->dynamic_states, dynamic_states);
|
||||||
|
|
||||||
|
/* Build constant pipeline. TODO: Some parts may be customizable */
|
||||||
|
pipeline_add_input_assembly(pipeline);
|
||||||
|
pipeline_add_viewport_state(pipeline);
|
||||||
|
pipeline_add_rasterizer(pipeline);
|
||||||
|
pipeline_add_multisampling(pipeline);
|
||||||
|
pipeline_add_color_blending(pipeline);
|
||||||
|
pipeline_add_depth_stencil(pipeline);
|
||||||
|
|
||||||
|
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
pipeline_info.pNext = NULL;
|
||||||
|
pipeline_info.flags = 0U;
|
||||||
|
pipeline_info.stageCount = pipeline->shader_stages_count;
|
||||||
|
pipeline_info.pStages = pipeline->shader_stages;
|
||||||
|
pipeline_info.pVertexInputState = &(VkPipelineVertexInputStateCreateInfo){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.flags = 0U,
|
||||||
|
.vertexBindingDescriptionCount = vertex_bindings_count,
|
||||||
|
.pVertexBindingDescriptions = vertex_bindings,
|
||||||
|
.vertexAttributeDescriptionCount = shader_attributes_count,
|
||||||
|
.pVertexAttributeDescriptions = shader_attributes,
|
||||||
|
};
|
||||||
|
pipeline_info.pInputAssemblyState = &pipeline->input_assembly;
|
||||||
|
pipeline_info.pTessellationState = NULL;
|
||||||
|
pipeline_info.pViewportState = &pipeline->viewport_state;
|
||||||
|
pipeline_info.pRasterizationState = &pipeline->rasterizer;
|
||||||
|
pipeline_info.pMultisampleState = &pipeline->multisampling;
|
||||||
|
pipeline_info.pDepthStencilState = &pipeline->depth_stencil;
|
||||||
|
pipeline_info.pColorBlendState = &pipeline->color_blending;
|
||||||
|
pipeline_info.pDynamicState = &(VkPipelineDynamicStateCreateInfo){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.flags = 0U,
|
||||||
|
.dynamicStateCount = dynamic_states_count,
|
||||||
|
.pDynamicStates = dynamic_states,
|
||||||
|
};
|
||||||
|
pipeline_info.layout = context->pipelines_data.pipeline_layout;
|
||||||
|
pipeline_info.renderPass = context->render_pass;
|
||||||
|
pipeline_info.subpass = 0;
|
||||||
|
pipeline_info.basePipelineHandle =
|
||||||
|
VK_NULL_HANDLE; // TODO: Add possiblity do derive from another pipeline
|
||||||
|
pipeline_info.basePipelineIndex = -1;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_pipelines(struct graphics_context_t* context)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
size_t shader_modules_count = RSE_LINKED_LIST_SIZE(context->shader_modules);
|
||||||
|
vkDestroyRenderPass(context->device, context->render_pass, NULL);
|
||||||
|
for (i = 0; i < context->pipelines_data.pipelines_count; i++) {
|
||||||
|
if (context->pipelines_data.pipelines[i] != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipeline(context->device,
|
||||||
|
context->pipelines_data.pipelines[i], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < context->pipelines_data.descriptor_set_layouts_count; i++) {
|
||||||
|
if (context->pipelines_data.descriptor_set_layouts[i] !=
|
||||||
|
VK_NULL_HANDLE) {
|
||||||
|
vkDestroyDescriptorSetLayout(
|
||||||
|
context->device,
|
||||||
|
context->pipelines_data.descriptor_set_layouts[i], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < shader_modules_count; i++) {
|
||||||
|
if (RSE_LINKED_LIST_FRONT(context->shader_modules) != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyShaderModule(
|
||||||
|
context->device,
|
||||||
|
RSE_LINKED_LIST_FRONT(context->shader_modules), NULL);
|
||||||
|
}
|
||||||
|
RSE_LINKED_LIST_POP_FRONT(context->shader_modules);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/**
|
||||||
|
* @file pipeline_builder.h
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief Builder for vulkan pipeline
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-03-01
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PIPELINE_BUILDER_H
|
||||||
|
#define PIPELINE_BUILDER_H
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include "graphics_context.h"
|
||||||
|
#include "utilities/commons.h"
|
||||||
|
#include "utilities/linked_list.h"
|
||||||
|
#include "utilities/stack.h"
|
||||||
|
|
||||||
|
#define MAX_SHADER_STAGES 12U
|
||||||
|
|
||||||
|
RSE_LINKED_LIST_DEFINE(vertex_bindinlist_t, VkVertexInputBindingDescription);
|
||||||
|
RSE_LINKED_LIST_DEFINE(shader_attribute_list_t,
|
||||||
|
VkVertexInputAttributeDescription);
|
||||||
|
RSE_LINKED_LIST_DEFINE(dynamic_state_list_t, VkDynamicState);
|
||||||
|
RSE_LINKED_LIST_DEFINE(pipeline_infos_list_t, VkGraphicsPipelineCreateInfo);
|
||||||
|
|
||||||
|
RSE_STACK_DEFINE(required_dynamic_states_t, VkDynamicState, 16U);
|
||||||
|
|
||||||
|
|
||||||
|
struct binding_info_t {
|
||||||
|
uint32_t binding;
|
||||||
|
VkDescriptorType descriptor_type;
|
||||||
|
VkShaderStageFlags stage_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pipeline_t {
|
||||||
|
VkPipeline pipeline;
|
||||||
|
uint8_t id;
|
||||||
|
/* Shader stages */
|
||||||
|
size_t shader_stages_count;
|
||||||
|
VkPipelineShaderStageCreateInfo shader_stages[MAX_SHADER_STAGES];
|
||||||
|
/* Input assembly */
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo input_assembly;
|
||||||
|
/* Viewport state */
|
||||||
|
VkPipelineViewportStateCreateInfo viewport_state;
|
||||||
|
/* Rasterizer */
|
||||||
|
VkPipelineRasterizationStateCreateInfo rasterizer;
|
||||||
|
/* Multisampling */
|
||||||
|
VkPipelineMultisampleStateCreateInfo multisampling;
|
||||||
|
/* Color blending */
|
||||||
|
VkPipelineColorBlendAttachmentState color_blend_attachment;
|
||||||
|
VkPipelineColorBlendStateCreateInfo color_blending;
|
||||||
|
/* Depth stencil */
|
||||||
|
VkPipelineDepthStencilStateCreateInfo depth_stencil;
|
||||||
|
struct vertex_bindinlist_t* vertex_bindings;
|
||||||
|
struct shader_attribute_list_t* shader_attributes;
|
||||||
|
struct dynamic_state_list_t* dynamic_states;
|
||||||
|
struct required_dynamic_states_t required_dynamic_states;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize pipeline builder
|
||||||
|
*
|
||||||
|
* @param[out] pipeline Pipeline to initialize. Must be NULL
|
||||||
|
* @return RSE_SUCCESS on success, error code otherwise
|
||||||
|
*/
|
||||||
|
rse_err_t pipeline_builder_init(struct pipeline_t* pipeline);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add shader stages to pipeline
|
||||||
|
*
|
||||||
|
* @param[in] context Graphics context handle
|
||||||
|
* @param[in] pipeline Pipeline to build
|
||||||
|
* @param[in] shader_path Path to the shader file
|
||||||
|
* @param[in] shader_stage Shader stage to add
|
||||||
|
* @return RSE_SUCCESS on success, error code otherwise
|
||||||
|
*/
|
||||||
|
rse_err_t pipeline_add_shader_stage(struct graphics_context_t* context, struct pipeline_t* pipeline, const char* shader_path, const VkShaderStageFlagBits shader_stage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add vertex input binding to pipeline
|
||||||
|
*
|
||||||
|
* @param[in] pipeline Pipeline to build
|
||||||
|
* @param[in] binding Binding point for vertex data
|
||||||
|
* @param[in] stride Stride between vertex data elements in bytes
|
||||||
|
* @param[in] input_rate Input rate for vertex data
|
||||||
|
* @return RSE_SUCCESS on success, error code otherwise
|
||||||
|
*/
|
||||||
|
rse_err_t pipeline_add_vertex_input_binding(struct pipeline_t* pipeline, const uint8_t binding, const uint8_t stride,
|
||||||
|
const VkVertexInputRate input_rate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add vertex attribute to shader in pipeline
|
||||||
|
*
|
||||||
|
* @param[in] pipeline Pipeline to build
|
||||||
|
* @param[in] binding Binding point for vertex data
|
||||||
|
* @param[in] location Location of the attribute in shader
|
||||||
|
* @param[in] format Format of the attribute
|
||||||
|
* @param[in] offset Offset of the attribute in bytes
|
||||||
|
* @return RSE_SUCCESS on success, error code otherwise
|
||||||
|
*/
|
||||||
|
rse_err_t pipeline_add_vertex_input_attribute(struct pipeline_t* pipeline, const uint8_t binding,
|
||||||
|
const uint8_t location,
|
||||||
|
const VkFormat format,
|
||||||
|
const uint8_t offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add dynamic state to pipeline
|
||||||
|
*
|
||||||
|
* @param[in] pipeline Pipeline to build
|
||||||
|
* @param[in] dynamic_state Dynamic state to add
|
||||||
|
* @return RSE_SUCCESS on success, error code otherwise
|
||||||
|
*/
|
||||||
|
rse_err_t pipeline_add_dynamic_state(struct pipeline_t* pipeline, const VkDynamicState dynamic_state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add required dynamic state to pipeline
|
||||||
|
*
|
||||||
|
* @param[in] context Graphics context handle
|
||||||
|
* @param[in] binding_infos Binding infos to add
|
||||||
|
* @param[in] binding_count Number of binding infos
|
||||||
|
* @param[out] descriptor_set_index Index of descriptor set
|
||||||
|
* @return RSE_SUCCESS on success, error code otherwise
|
||||||
|
*/
|
||||||
|
rse_err_t pipeline_add_descriptor_layout(struct graphics_context_t* context,
|
||||||
|
struct binding_info_t* binding_infos,
|
||||||
|
size_t binding_count,
|
||||||
|
size_t* descriptor_set_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Build pipeline from added components. This function should be called after adding all necessary components. After call, pipeline is ready to be used and all added components are cleared, ready for next pipeline to be built.
|
||||||
|
*
|
||||||
|
* param[in/out] context Graphics context handle
|
||||||
|
* @param[in] pipeline Pipelines list to build
|
||||||
|
* @return RSE_SUCCESS on success, error code otherwise
|
||||||
|
*/
|
||||||
|
rse_err_t build_pipelines(struct graphics_context_t* context,
|
||||||
|
struct pipeline_infos_list_t* pipelines);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add pipeline to list of pipelines
|
||||||
|
*
|
||||||
|
* @param[in] context Graphics context handle
|
||||||
|
* @param[in] pipeline Pipeline to add
|
||||||
|
* @param[out] pipelines List of pipelines
|
||||||
|
* @return RSE_SUCCESS on success, error code otherwise
|
||||||
|
*/
|
||||||
|
rse_err_t add_pipeline(const struct graphics_context_t* context, struct pipeline_t* pipeline, struct pipeline_infos_list_t* pipelines);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy all pipelines
|
||||||
|
*
|
||||||
|
* @param[in] context Graphics context handle
|
||||||
|
*/
|
||||||
|
void destroy_pipelines(struct graphics_context_t* context);
|
||||||
|
|
||||||
|
#endif /* PIPELINE_BUILDER_H */
|
||||||
+89
-43
@@ -1,57 +1,65 @@
|
|||||||
#include "rse_graphics.h"
|
#include "rse_graphics.h"
|
||||||
#include "src/rse_text_renderer.h"
|
#include "utilities/localization.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "vulkan_base.h"
|
#include "vulkan_base.h"
|
||||||
|
|
||||||
#include "mesh_controller.h"
|
#include "mesh_controller.h"
|
||||||
#include "vulkan_commons.h"
|
#include "vulkan_commons.h"
|
||||||
#include "rse_vulkan_image.h"
|
#include "pipeline_builder.h"
|
||||||
#include "utilities/logger.h"
|
#include "utilities/logger.h"
|
||||||
#include "utilities/rse_commons.h"
|
#include "utilities/commons.h"
|
||||||
#include "utilities/rse_errors_common.h"
|
#include "utilities/errors_common.h"
|
||||||
|
#include "graphics_context.h"
|
||||||
|
|
||||||
#include "rse_math.h"
|
#include "math.h"
|
||||||
|
|
||||||
extern struct rse_vulkan_state_t g_vulkan_state;
|
struct rse_graphics_context_t {
|
||||||
|
struct graphics_context_t* context;
|
||||||
|
};
|
||||||
|
|
||||||
|
rse_err_t rse_graphics_init(struct rse_graphics_context_t* context)
|
||||||
rse_err_t rse_graphics_init(void)
|
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
g_vulkan_state.graphics_queue = VK_NULL_HANDLE;
|
if (context != NULL) {
|
||||||
g_vulkan_state.physical_device = VK_NULL_HANDLE;
|
LOGF(_("Graphics already initialized!\n"));
|
||||||
g_vulkan_state.current_frame = 0U;
|
return RSE_ERROR_ALREADY_INITIALIZED;
|
||||||
g_vulkan_state.render_pass = VK_NULL_HANDLE;
|
}
|
||||||
g_vulkan_state.descriptor_set_layout = VK_NULL_HANDLE;
|
|
||||||
g_vulkan_state.graphics_pipeline = VK_NULL_HANDLE;
|
|
||||||
g_vulkan_state.pipeline_layout = VK_NULL_HANDLE;
|
|
||||||
g_vulkan_state.swapchain = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
STATUS_CHECK(window_init());
|
rse_malloc(context, sizeof(struct rse_graphics_context_t));
|
||||||
STATUS_CHECK(preinit_vulkan());
|
rse_malloc(context->context, sizeof(struct graphics_context_t));
|
||||||
|
rse_memset(context->context, 0, sizeof(struct graphics_context_t));
|
||||||
|
|
||||||
|
STATUS_CHECK(window_init(context->context->window_handle, &context->context->is_framebuffer_resized));
|
||||||
|
STATUS_CHECK(init_vulkan(context->context));
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rse_graphics_test_function(void)
|
void rse_graphics_test_function(struct rse_graphics_context_t* rse_context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
struct graphics_context_t* context = rse_context->context;
|
||||||
|
// rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
uint16_t tex_id_2 = 0;
|
uint16_t tex_id_2 = 0;
|
||||||
|
size_t ubo_index = 0;
|
||||||
|
size_t sampler_index = 0;
|
||||||
|
struct pipeline_t* pipeline = NULL;
|
||||||
|
struct binding_info_t binding_infos[2] = {0};
|
||||||
|
struct pipeline_infos_list_t* pipeline_infos = NULL;
|
||||||
|
|
||||||
status = rse_load_texture_from_file("../../test_image.jpg", &tex_id_2);
|
// status = load_texture_from_file("../../test_image.jpg", &tex_id_2);
|
||||||
if (status != RSE_ERROR_NO_ERROR) {
|
// if (status != RSE_ERROR_NO_ERROR) {
|
||||||
LOGE("Failed to do something. Check error messages. Error: %d", status);
|
// LOGE("Failed to do something. Check error messages. Error: %d", status);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
rse_fonts_initialize();
|
// fonts_initialize();
|
||||||
|
|
||||||
// FIXME: Temporary array of vertices, for testing purposes
|
// 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}},
|
struct vertex_t vertices[] = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
||||||
{{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
{{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
||||||
{{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
{{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
||||||
{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}};
|
{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}};
|
||||||
|
|
||||||
struct rse_vertex_t vertices2[] = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}},
|
struct vertex_t vertices2[] = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}},
|
||||||
{{0.5f, -0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}},
|
{{0.5f, -0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}},
|
||||||
{{0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
|
{{0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
|
||||||
{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}};
|
{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}};
|
||||||
@@ -59,43 +67,81 @@ void rse_graphics_test_function(void)
|
|||||||
// FIXME: Temporary array of vertices, for testing purposes
|
// FIXME: Temporary array of vertices, for testing purposes
|
||||||
uint16_t indices[] = {0, 1, 2, 2, 3, 0};
|
uint16_t indices[] = {0, 1, 2, 2, 3, 0};
|
||||||
|
|
||||||
uint16_t mesh_id = create_mesh(vertices, indices, 6, 6);
|
uint16_t mesh_id = create_mesh(context, vertices, indices, 6, 6);
|
||||||
create_mesh_instance(mesh_id, (struct rse_instance_data_t){
|
create_mesh_instance(context, mesh_id, (struct instance_data_t){
|
||||||
{0.0f, 0.0f, 2.4f},
|
{0.0f, 0.0f, 2.4f},
|
||||||
{0.0f, 0.0f, rse_math_deg_to_radians(45.0f)},
|
{0.0f, 0.0f, math_deg_to_radians(45.0f)},
|
||||||
1.0f,
|
1.0f,
|
||||||
tex_id_2
|
tex_id_2
|
||||||
});
|
});
|
||||||
|
|
||||||
create_mesh_instance(mesh_id, (struct rse_instance_data_t){
|
create_mesh_instance(context, mesh_id, (struct instance_data_t){
|
||||||
{-0.5f, 0.0f, -1.0f},
|
{-0.5f, 0.0f, -1.0f},
|
||||||
{0.0f, 0.0f, rse_math_deg_to_radians(10.0f)},
|
{0.0f, 0.0f, math_deg_to_radians(10.0f)},
|
||||||
1.0f,
|
1.0f,
|
||||||
tex_id_2
|
tex_id_2
|
||||||
});
|
});
|
||||||
|
|
||||||
mesh_id = create_mesh(vertices2, indices, 6, 6);
|
mesh_id = create_mesh(context, vertices2, indices, 6, 6);
|
||||||
create_mesh_instance(mesh_id, (struct rse_instance_data_t){
|
create_mesh_instance(context, mesh_id, (struct instance_data_t){
|
||||||
{2.0f, 1.0f, 0.0f},
|
{2.0f, 1.0f, 0.0f},
|
||||||
{0.0f, 0.0f, rse_math_deg_to_radians(0.0f)},
|
{0.0f, 0.0f, math_deg_to_radians(0.0f)},
|
||||||
1.0f,
|
1.0f,
|
||||||
tex_id_2
|
tex_id_2
|
||||||
});
|
});
|
||||||
|
|
||||||
rse_fonts_load_from_file("/usr/share/fonts/JetBrainsMonoNerdFont/JetBrainsMonoNerdFont-Medium.ttf");
|
// fonts_load_from_file("/usr/share/fonts/JetBrainsMonoNerdFont/JetBrainsMonoNerdFont-Medium.ttf");
|
||||||
rse_print_text("Hello World!", (struct vec3_t){-1.0f, 0.0f, 0.9f}, 0.3f);
|
// print_text("Hello World!", (struct vec3_t){-1.0f, 0.0f, 0.9f}, 0.3f);
|
||||||
|
|
||||||
|
/* Initialize pipeline */
|
||||||
|
pipeline_builder_init(pipeline);
|
||||||
|
pipeline_add_shader_stage(context, pipeline, "../graphics/shaders/shader.vert.num", VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
|
pipeline_add_shader_stage(context, pipeline, "../graphics/shaders/solid_objects.frag.num", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
|
||||||
|
pipeline_add_vertex_input_binding(pipeline, 0, sizeof(struct vertex_t), VK_VERTEX_INPUT_RATE_VERTEX);
|
||||||
|
|
||||||
|
pipeline_add_vertex_input_attribute(pipeline, 0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct vertex_t, pos));
|
||||||
|
pipeline_add_vertex_input_attribute(pipeline, 1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct vertex_t, color));
|
||||||
|
pipeline_add_vertex_input_attribute(pipeline, 2, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(struct vertex_t, tex_coords));
|
||||||
|
pipeline_add_vertex_input_attribute(pipeline, 3, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct instance_data_t, pos));
|
||||||
|
pipeline_add_vertex_input_attribute(pipeline, 4, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct instance_data_t, rot));
|
||||||
|
pipeline_add_vertex_input_attribute(pipeline, 5, 1, VK_FORMAT_R32_SFLOAT, offsetof(struct instance_data_t, scale));
|
||||||
|
pipeline_add_vertex_input_attribute(pipeline, 6, 1, VK_FORMAT_R32_SFLOAT, offsetof(struct instance_data_t, texture_id));
|
||||||
|
|
||||||
|
pipeline_add_dynamic_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT);
|
||||||
|
pipeline_add_dynamic_state(pipeline, VK_DYNAMIC_STATE_SCISSOR);
|
||||||
|
|
||||||
|
binding_infos[0].binding = 0;
|
||||||
|
binding_infos[0].descriptor_type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
binding_infos[0].stage_flags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
|
||||||
|
binding_infos[1].binding = 1;
|
||||||
|
binding_infos[1].descriptor_type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
binding_infos[1].stage_flags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
|
||||||
|
pipeline_add_descriptor_layout(context, &binding_infos[0], 1, &ubo_index);
|
||||||
|
pipeline_add_descriptor_layout(context, &binding_infos[1], 1, &sampler_index);
|
||||||
|
|
||||||
|
add_pipeline(context, pipeline, pipeline_infos);
|
||||||
|
|
||||||
|
build_pipelines(context, pipeline_infos);
|
||||||
|
|
||||||
|
//TODO: Add a shader for text rendering
|
||||||
|
// pipeline_add_shader_stage("../graphics/shaders/on_screen_text.frag.num", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t rse_graphics_run(void)
|
rse_err_t rse_graphics_run(struct rse_graphics_context_t* rse_context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
STATUS_CHECK(init_vulkan());
|
struct graphics_context_t* context = rse_context->context;
|
||||||
|
|
||||||
STATUS_CHECK(window_loop());
|
STATUS_CHECK(init_vulkan(context));
|
||||||
|
|
||||||
deinit_vulkan();
|
STATUS_CHECK(window_loop(context));
|
||||||
|
|
||||||
window_terminate();
|
deinit_vulkan(context);
|
||||||
|
|
||||||
|
window_terminate(context->window_handle);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
|
|
||||||
/**
|
|
||||||
* @file rse_text_renderer.h
|
|
||||||
* @author Piotr Krygier (piotr.krygier@meshsystems.com)
|
|
||||||
* @brief Load and render text on screen or in space
|
|
||||||
* @version 0.1
|
|
||||||
* @date 2024-02-02
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef RSE_TEXT_RENDERER_H
|
|
||||||
#define RSE_TEXT_RENDERER_H
|
|
||||||
|
|
||||||
#include "utilities/rse_commons.h"
|
|
||||||
#include "rse_math.h"
|
|
||||||
|
|
||||||
rse_err_t rse_fonts_initialize(void);
|
|
||||||
rse_err_t rse_fonts_load_from_file(const char* file_path);
|
|
||||||
rse_err_t rse_print_text(const char* text, struct vec3_t position, float font_size);
|
|
||||||
|
|
||||||
#endif // !RSE_TEXT_RENDERER_H_
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file rse_vulkan_image.h
|
|
||||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
|
||||||
* @brief Library for loading and handling textures
|
|
||||||
* @version 0.1
|
|
||||||
* @date 2023-09-27
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef RSE_TEXTURE_H
|
|
||||||
#define RSE_TEXTURE_H
|
|
||||||
|
|
||||||
#include "utilities/file_utils.h"
|
|
||||||
#include "utilities/rse_commons.h"
|
|
||||||
|
|
||||||
#include "vulkan/vulkan_core.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Maximum number of textures that can be loaded
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define RSE_MAX_IMAGE_COUNT 256
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initialize vulkan with image views and stuff
|
|
||||||
*
|
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
|
||||||
*/
|
|
||||||
rse_err_t init_vulkan_images(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Loads image from file, for later to be used as a texture
|
|
||||||
*
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
rse_err_t rse_load_texture_from_bitmat(const unsigned char* pixel_buffer, int width, int height, uint16_t* texture_id, VkFormat color_format);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Loads image from file, for later to be used as a texture
|
|
||||||
*
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
rse_err_t rse_load_texture_from_file(const char* file_path, uint16_t* texture_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Destroy all loaded textures. Usefull for closing application or just clearing.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void rse_destroy_textures(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns image view for provided image id
|
|
||||||
*
|
|
||||||
* @param image_id image id
|
|
||||||
* @return VkImageView Found image view.
|
|
||||||
*/
|
|
||||||
VkImageView rse_get_image_view(size_t image_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns sampler
|
|
||||||
*
|
|
||||||
* @return VkSampler Sampler object
|
|
||||||
*/
|
|
||||||
VkSampler rse_get_texture_sampler();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if image exists for provided image ID.
|
|
||||||
*
|
|
||||||
* @param image_id Image ID
|
|
||||||
* @return uint8_t 1 on success, 0 on failure
|
|
||||||
*/
|
|
||||||
uint8_t image_exists(uint8_t image_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns number of loaded texture
|
|
||||||
*
|
|
||||||
* @return size_t Texture count
|
|
||||||
*/
|
|
||||||
size_t get_textures_count(void);
|
|
||||||
|
|
||||||
rse_err_t find_depth_format(VkFormat* found_format);
|
|
||||||
|
|
||||||
VkImageView rse_get_depth_image_view(void);
|
|
||||||
|
|
||||||
VkImageView rse_get_color_image_view(void);
|
|
||||||
|
|
||||||
rse_err_t rse_create_color_resource(void);
|
|
||||||
void rse_destroy_color_resource(void);
|
|
||||||
|
|
||||||
rse_err_t rse_create_depth_resources(void);
|
|
||||||
void rse_destroy_depth_resource(void);
|
|
||||||
|
|
||||||
#endif /* RSE_TEXTURE_H */
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
#include "rse_text_renderer.h"
|
#include "text_renderer.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
|
||||||
#include "freetype/fttypes.h"
|
#include "freetype/fttypes.h"
|
||||||
#include "locale_fonts.h"
|
#include "locale_fonts.h"
|
||||||
#include "rse_font_errors.h"
|
#include "font_errors.h"
|
||||||
#include "src/mesh_controller.h"
|
#include "src/mesh_controller.h"
|
||||||
#include "src/rse_math.h"
|
#include "src/math.h"
|
||||||
#include "src/vulkan_commons.h"
|
#include "src/vulkan_commons.h"
|
||||||
#include "utilities/logger.h"
|
#include "utilities/logger.h"
|
||||||
#include "utilities/rse_commons.h"
|
#include "utilities/commons.h"
|
||||||
#include "utilities/rse_errors_common.h"
|
#include "utilities/errors_common.h"
|
||||||
#include "rse_vulkan_image.h"
|
#include "vulkan_image.h"
|
||||||
|
|
||||||
#include "vulkan/vulkan_core.h"
|
#include "vulkan/vulkan_core.h"
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
@@ -37,7 +37,7 @@ struct font_data_t {
|
|||||||
struct font_data_t g_fonts_data[FONT_CHARACTERS_COUNT];
|
struct font_data_t g_fonts_data[FONT_CHARACTERS_COUNT];
|
||||||
|
|
||||||
FT_Library g_library;
|
FT_Library g_library;
|
||||||
rse_err_t rse_fonts_initialize()
|
rse_err_t fonts_initialize()
|
||||||
{
|
{
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
|
|
||||||
@@ -45,26 +45,26 @@ rse_err_t rse_fonts_initialize()
|
|||||||
error = FT_Init_FreeType(&g_library);
|
error = FT_Init_FreeType(&g_library);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
LOGF(font_messages[FONT_INITIALIZATION_FAILED]);
|
LOGF(_("Font initialization failed\n"));
|
||||||
return FONT_ERROR_INIT_FAILED;
|
return FONT_ERROR_INIT_FAILED;
|
||||||
}
|
}
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rse_err_t rse_fonts_load_from_file(const char* file_path)
|
rse_err_t fonts_load_from_file(const char* file_path)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
size_t iter = 0U;
|
size_t iter = 0U;
|
||||||
struct rse_vertex_t font_vertices[4];
|
struct vertex_t font_vertices[4];
|
||||||
uint16_t font_indices[] = {0, 1, 2, 2, 3, 0};
|
uint16_t font_indices[] = {0, 1, 2, 2, 3, 0};
|
||||||
|
|
||||||
error = FT_New_Face(g_library, file_path, 0, &face);
|
error = FT_New_Face(g_library, file_path, 0, &face);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
LOGF(font_messages[FONT_LOAD_FONT_FAILED]);
|
LOGF(_("Failed to load new font\n"));
|
||||||
return FONT_ERROR_LOAD_FAILED;
|
return FONT_ERROR_LOAD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ rse_err_t rse_fonts_load_from_file(const char* file_path)
|
|||||||
error = FT_Set_Pixel_Sizes(face, 0, FONT_SIZE);
|
error = FT_Set_Pixel_Sizes(face, 0, FONT_SIZE);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
LOGF(font_messages[FONT_CHANGE_SIZE_FAILED]);
|
LOGF(_("Failed to change font size\n"));
|
||||||
return FONT_ERROR_CHANGE_SIZE_FAILED;
|
return FONT_ERROR_CHANGE_SIZE_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ rse_err_t rse_fonts_load_from_file(const char* file_path)
|
|||||||
error = FT_Load_Char(face, iter + FONT_START_CHARACTER, FT_LOAD_RENDER);
|
error = FT_Load_Char(face, iter + FONT_START_CHARACTER, FT_LOAD_RENDER);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
LOGF(font_messages[FONT_LOAD_GLYPH_FAILED]);
|
LOGF(_("Failed to load glyph into memeory\n"));
|
||||||
return FONT_ERROR_LOAD_GLYPH_FAILED;
|
return FONT_ERROR_LOAD_GLYPH_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,22 +97,22 @@ rse_err_t rse_fonts_load_from_file(const char* file_path)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
font_vertices[0] = (struct rse_vertex_t) {
|
font_vertices[0] = (struct vertex_t) {
|
||||||
{g_fonts_data[iter].bearing_x, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}
|
{g_fonts_data[iter].bearing_x, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}
|
||||||
};
|
};
|
||||||
font_vertices[1] = (struct rse_vertex_t) {
|
font_vertices[1] = (struct vertex_t) {
|
||||||
{g_fonts_data[iter].bearing_x + g_fonts_data[iter].width, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}
|
{g_fonts_data[iter].bearing_x + g_fonts_data[iter].width, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}
|
||||||
};
|
};
|
||||||
font_vertices[2] = (struct rse_vertex_t) {
|
font_vertices[2] = (struct vertex_t) {
|
||||||
{g_fonts_data[iter].bearing_x + g_fonts_data[iter].width, g_fonts_data[iter].height, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}
|
{g_fonts_data[iter].bearing_x + g_fonts_data[iter].width, g_fonts_data[iter].height, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}
|
||||||
};
|
};
|
||||||
font_vertices[3] = (struct rse_vertex_t) {
|
font_vertices[3] = (struct vertex_t) {
|
||||||
{g_fonts_data[iter].bearing_x, g_fonts_data[iter].height, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}
|
{g_fonts_data[iter].bearing_x, g_fonts_data[iter].height, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}
|
||||||
};
|
};
|
||||||
|
|
||||||
g_fonts_data[iter].mesh_id = create_mesh(font_vertices, font_indices, 8, 6);
|
g_fonts_data[iter].mesh_id = create_mesh(font_vertices, font_indices, 8, 6);
|
||||||
|
|
||||||
STATUS_CHECK(rse_load_texture_from_bitmat(face->glyph->bitmap.buffer,
|
STATUS_CHECK(load_texture_from_bitmat(face->glyph->bitmap.buffer,
|
||||||
face->glyph->bitmap.width,
|
face->glyph->bitmap.width,
|
||||||
face->glyph->bitmap.rows,
|
face->glyph->bitmap.rows,
|
||||||
&g_fonts_data[iter].texture_id, VK_FORMAT_R8_SRGB));
|
&g_fonts_data[iter].texture_id, VK_FORMAT_R8_SRGB));
|
||||||
@@ -121,7 +121,7 @@ rse_err_t rse_fonts_load_from_file(const char* file_path)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t rse_print_text(const char* text, struct vec3_t position, float font_size)
|
rse_err_t print_text(const char* text, struct vec3_t position, float font_size)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
size_t iter = 0U;
|
size_t iter = 0U;
|
||||||
@@ -140,9 +140,9 @@ rse_err_t rse_print_text(const char* text, struct vec3_t position, float font_si
|
|||||||
|
|
||||||
x_pos = position.x + advance - (g_fonts_data[charactet_code].bearing_x * scale);
|
x_pos = position.x + advance - (g_fonts_data[charactet_code].bearing_x * scale);
|
||||||
y_pos = position.y - (g_fonts_data[charactet_code].bearing_y * scale);
|
y_pos = position.y - (g_fonts_data[charactet_code].bearing_y * scale);
|
||||||
create_mesh_instance(g_fonts_data[charactet_code].mesh_id, (struct rse_instance_data_t){
|
create_mesh_instance(g_fonts_data[charactet_code].mesh_id, (struct instance_data_t){
|
||||||
{x_pos, y_pos, 0.0f},
|
{x_pos, y_pos, 0.0f},
|
||||||
{0.0f, 0.0f, rse_math_deg_to_radians(0.0f)},
|
{0.0f, 0.0f, math_deg_to_radians(0.0f)},
|
||||||
FONT_SCALING * font_size,
|
FONT_SCALING * font_size,
|
||||||
g_fonts_data[charactet_code].texture_id
|
g_fonts_data[charactet_code].texture_id
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* @file text_renderer.h
|
||||||
|
* @author Piotr Krygier (piotr.krygier@meshsystems.com)
|
||||||
|
* @brief Load and render text on screen or in space
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-02-02
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TEXT_RENDERER_H
|
||||||
|
#define TEXT_RENDERER_H
|
||||||
|
|
||||||
|
#include "utilities/commons.h"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
rse_err_t fonts_initialize(void);
|
||||||
|
rse_err_t fonts_load_from_file(const char* file_path);
|
||||||
|
rse_err_t print_text(const char* text, struct vec3_t position, float font_size);
|
||||||
|
|
||||||
|
#endif // !TEXT_RENDERER_H_
|
||||||
+145
-164
@@ -23,22 +23,20 @@
|
|||||||
// #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
// #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||||
// #pragma GCC diagnostic ignored "-Wswitch"
|
// #pragma GCC diagnostic ignored "-Wswitch"
|
||||||
// #pragma GCC diagnostic ignored "-Wparentheses"
|
// #pragma GCC diagnostic ignored "-Wparentheses"
|
||||||
|
#include "utilities/localization.h"
|
||||||
#include "vk_mem_alloc.h"
|
#include "vk_mem_alloc.h"
|
||||||
// #pragma GCC diagnostic pop
|
// #pragma GCC diagnostic pop
|
||||||
|
|
||||||
#include "locale_vulkan.h"
|
#include "utilities/errors_common.h"
|
||||||
#include "utilities/rse_errors_common.h"
|
|
||||||
#include "utilities/logger.h"
|
#include "utilities/logger.h"
|
||||||
#include "vulkan/vulkan_core.h"
|
#include "vulkan/vulkan_core.h"
|
||||||
#include "vulkan_errors.h"
|
#include "vulkan_errors.h"
|
||||||
#include "window.h"
|
|
||||||
|
|
||||||
#include "vulkan_commons.h"
|
#include "vulkan_commons.h"
|
||||||
#include "rse_vulkan_commands.h"
|
#include "vulkan_commands.h"
|
||||||
#include "vulkan_buffers.h"
|
#include "vulkan_buffers.h"
|
||||||
#include "vulkan_descriptors.h"
|
#include "vulkan_descriptors.h"
|
||||||
#include "vulkan_pipeline.h"
|
#include "vulkan_image.h"
|
||||||
#include "rse_vulkan_image.h"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -47,37 +45,7 @@
|
|||||||
#define APPLICATION_NAME "RedScarfEngine PoC"
|
#define APPLICATION_NAME "RedScarfEngine PoC"
|
||||||
#define ENGINE_NAME "RedScarf Engine"
|
#define ENGINE_NAME "RedScarf Engine"
|
||||||
|
|
||||||
/* Define Validation Layers for debug build */
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define ENABLED_EXTENSIONS_COUT 4
|
|
||||||
#define ENABLED_INSTANCE_LAYERS_COUNT 1
|
|
||||||
const char* g_enabled_instance_layers_names[] = {"VK_LAYER_KHRONOS_validation"};
|
|
||||||
#else
|
|
||||||
#define ENABLED_EXTENSIONS_COUT 3
|
|
||||||
#define ENABLED_INSTANCE_LAYERS_COUNT 0
|
|
||||||
const char* g_enabled_instance_layers_names[] = {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char* g_enabled_instance_extensions_names[ENABLED_EXTENSIONS_COUT] = {};
|
|
||||||
|
|
||||||
#define ENABLED_DEVICE_EXTENSIONS_COUT 1
|
|
||||||
const char* g_enabled_device_extensions_names[] = {
|
|
||||||
"VK_KHR_swapchain",
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
VkInstance g_vulkan_instance = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
VkDebugUtilsMessengerEXT g_debug_messenger = VK_NULL_HANDLE;
|
|
||||||
VkQueue g_present_queue;
|
|
||||||
|
|
||||||
VkSemaphore g_image_available_semaphores[SWAP_BUFFER_COUNT] = {};
|
|
||||||
VkSemaphore g_render_finished_semaphores[SWAP_BUFFER_COUNT] = {};
|
|
||||||
VkFence g_in_flight_fences[SWAP_BUFFER_COUNT] = {};
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Calback for debug messenger
|
* @brief Calback for debug messenger
|
||||||
*
|
*
|
||||||
@@ -142,8 +110,10 @@ static VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugU
|
|||||||
/**
|
/**
|
||||||
* @brief Setup debugging system for Vulkan API
|
* @brief Setup debugging system for Vulkan API
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
static rse_err_t setup_debug_messenger()
|
static rse_err_t setup_debug_messenger(VkInstance instance, VkDebugUtilsMessengerEXT* messenger)
|
||||||
{
|
{
|
||||||
VkDebugUtilsMessengerCreateInfoEXT create_info = {0};
|
VkDebugUtilsMessengerCreateInfoEXT create_info = {0};
|
||||||
|
|
||||||
@@ -159,8 +129,8 @@ static rse_err_t setup_debug_messenger()
|
|||||||
create_info.pUserData = NULL; // Optional
|
create_info.pUserData = NULL; // Optional
|
||||||
create_info.flags = 0U;
|
create_info.flags = 0U;
|
||||||
|
|
||||||
if (CreateDebugUtilsMessengerEXT(g_vulkan_instance, &create_info, NULL, &g_debug_messenger) != VK_SUCCESS) {
|
if (CreateDebugUtilsMessengerEXT(instance, &create_info, NULL, messenger) != VK_SUCCESS) {
|
||||||
LOGF(vulkan_messages[VULKAN_DEBUG_MESSENGER_SETUP_FAILED]);
|
LOGF(_("Failed to setup debug messenger\n"));
|
||||||
return VULKAN_ERROR_DEBUG_MESSENGER_CREATION_FAILED;
|
return VULKAN_ERROR_DEBUG_MESSENGER_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,46 +156,18 @@ static void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMesse
|
|||||||
|
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enable instance extensions, based on system and requirements
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
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";
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
if (getenv("WAYLAND_DISPLAY") != NULL) {
|
|
||||||
g_enabled_instance_extensions_names[2] = "VK_KHR_wayland_surface";
|
|
||||||
} else {
|
|
||||||
g_enabled_instance_extensions_names[2] = "VK_KHR_xcb_surface";
|
|
||||||
}
|
|
||||||
#elif defined(_WIN32) || defined(WIN32)
|
|
||||||
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
|
* @brief Create the Vulkan Instance object
|
||||||
*
|
*
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
* VULKAN_ERROR_INSTANCE_INIT_FAILED
|
* VULKAN_ERROR_INSTANCE_INIT_FAILED
|
||||||
*/
|
*/
|
||||||
static rse_err_t create_instance()
|
static rse_err_t create_instance(VkInstance* instance)
|
||||||
{
|
{
|
||||||
size_t i = 0U;
|
size_t i = 0U;
|
||||||
size_t j = 0U;
|
size_t j = 0U;
|
||||||
uint8_t supported = 0U;
|
uint8_t supported = 0U;
|
||||||
|
VkResult result = VK_SUCCESS;
|
||||||
uint32_t extensionCount = 0U;
|
uint32_t extensionCount = 0U;
|
||||||
uint32_t layersCount = 0U;
|
uint32_t layersCount = 0U;
|
||||||
VkApplicationInfo application_info = {0};
|
VkApplicationInfo application_info = {0};
|
||||||
@@ -233,6 +175,35 @@ static rse_err_t create_instance()
|
|||||||
VkLayerProperties* layer_properties;
|
VkLayerProperties* layer_properties;
|
||||||
VkExtensionProperties* extensions_properties;
|
VkExtensionProperties* extensions_properties;
|
||||||
|
|
||||||
|
const char* enabled_instance_extensions_names[] = {
|
||||||
|
"VK_KHR_surface",
|
||||||
|
"VK_KHR_device_group_creation",
|
||||||
|
#ifdef __linux__
|
||||||
|
#ifdef WAYLAND
|
||||||
|
"VK_KHR_wayland_surface",
|
||||||
|
#else
|
||||||
|
"VK_KHR_xcb_surface",
|
||||||
|
#endif /* WAYLAND */
|
||||||
|
#elif defined(_WIN32) || defined(WIN32)
|
||||||
|
"VK_KHR_win32_surface",
|
||||||
|
#endif /* _WIN32 || WIN32 */
|
||||||
|
#ifndef NDEBUG
|
||||||
|
"VK_EXT_debug_utils",
|
||||||
|
#endif /* NDEBUG */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
uint32_t enabled_instance_extensions_count = 4;
|
||||||
|
uint32_t enabled_instance_layers_count = 1;
|
||||||
|
const char* enabled_instance_layers_names[] = {
|
||||||
|
"VK_LAYER_KHRONOS_validation",
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
uint32_t enabled_instance_extensions_count = 3;
|
||||||
|
uint32_t enabled_instance_layers_count = 0;
|
||||||
|
const char* enabled_instance_layers_names[] = {};
|
||||||
|
#endif /* NDEBUG */
|
||||||
|
|
||||||
vkEnumerateInstanceLayerProperties(&layersCount, NULL);
|
vkEnumerateInstanceLayerProperties(&layersCount, NULL);
|
||||||
rse_malloc(layer_properties, sizeof(VkLayerProperties) * layersCount);
|
rse_malloc(layer_properties, sizeof(VkLayerProperties) * layersCount);
|
||||||
vkEnumerateInstanceLayerProperties(&layersCount, layer_properties);
|
vkEnumerateInstanceLayerProperties(&layersCount, layer_properties);
|
||||||
@@ -254,35 +225,38 @@ static rse_err_t create_instance()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check if selected layers are supported*/
|
/* Check if selected layers are supported*/
|
||||||
for (i = 0; i < ENABLED_INSTANCE_LAYERS_COUNT; ++i) {
|
for (i = 0; i < enabled_instance_layers_count; ++i) {
|
||||||
for(j = 0; i < layersCount; ++j) {
|
for(j = 0; i < layersCount; ++j) {
|
||||||
if(strcmp(layer_properties[j].layerName, g_enabled_instance_layers_names[i]) == 0) {
|
if(strcmp(layer_properties[j].layerName, enabled_instance_layers_names[i]) == 0) {
|
||||||
supported = 1;
|
supported = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(supported == 0) {
|
if(supported == 0) {
|
||||||
LOGF(vulkan_messages[VULKAN_LAYER_NOT_SUPPORTED], layer_properties[j].layerName);
|
LOGF(_("Selected layer is not supported: %s\n"), layer_properties[j].layerName);
|
||||||
return VULKAN_ERROR_LAYER_NOT_SUPPORTED;
|
return VULKAN_ERROR_LAYER_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
supported = 0;
|
supported = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if selected extensions are supported*/
|
/* Check if selected extensions are supported*/
|
||||||
for (i = 0; i < ENABLED_EXTENSIONS_COUT; ++i) {
|
for (i = 0; i < enabled_instance_extensions_count; ++i) {
|
||||||
for(j = 0; j < extensionCount; ++j) {
|
for(j = 0; j < extensionCount; ++j) {
|
||||||
if(strcmp(extensions_properties[j].extensionName, g_enabled_instance_extensions_names[i]) == 0) {
|
if(strcmp(extensions_properties[j].extensionName, enabled_instance_extensions_names[i]) == 0) {
|
||||||
supported = 1;
|
supported = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(supported == 0) {
|
if(supported == 0) {
|
||||||
LOGF(vulkan_messages[VULKAN_EXTENSION_NOT_SUPPORTED], extensions_properties[j].extensionName);
|
LOGF(_("Selected extension is not supported: %s\n"), extensions_properties[j].extensionName);
|
||||||
return VULKAN_ERROR_EXTENSION_NOT_SUPPORTED;
|
return VULKAN_ERROR_EXTENSION_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
supported = 0;
|
supported = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rse_free(layer_properties);
|
||||||
|
rse_free(extensions_properties);
|
||||||
|
|
||||||
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
application_info.pNext = NULL;
|
application_info.pNext = NULL;
|
||||||
application_info.pApplicationName = APPLICATION_NAME;
|
application_info.pApplicationName = APPLICATION_NAME;
|
||||||
@@ -295,18 +269,18 @@ static rse_err_t create_instance()
|
|||||||
create_info.pNext = NULL;
|
create_info.pNext = NULL;
|
||||||
create_info.flags = 0U;
|
create_info.flags = 0U;
|
||||||
create_info.pApplicationInfo = &application_info;
|
create_info.pApplicationInfo = &application_info;
|
||||||
create_info.enabledLayerCount = ENABLED_INSTANCE_LAYERS_COUNT;
|
create_info.enabledLayerCount = enabled_instance_layers_count;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
create_info.ppEnabledLayerNames = g_enabled_instance_layers_names;
|
create_info.ppEnabledLayerNames = enabled_instance_layers_names;
|
||||||
#else
|
#else
|
||||||
create_info.ppEnabledLayerNames = NULL;
|
create_info.ppEnabledLayerNames = NULL;
|
||||||
#endif
|
#endif
|
||||||
create_info.enabledExtensionCount = ENABLED_EXTENSIONS_COUT;
|
create_info.enabledExtensionCount = enabled_instance_extensions_count;
|
||||||
create_info.ppEnabledExtensionNames = g_enabled_instance_extensions_names;
|
create_info.ppEnabledExtensionNames = enabled_instance_extensions_names;
|
||||||
|
|
||||||
VkResult result = vkCreateInstance(&create_info, NULL, &g_vulkan_instance);
|
result = vkCreateInstance(&create_info, NULL, instance);
|
||||||
if (VK_SUCCESS != result) {
|
if (VK_SUCCESS != result) {
|
||||||
LOGF(vulkan_messages[VULKAN_INTANCE_INIT_FAILED]);
|
LOGF(_("Vulkan instance initialization failed\n"));
|
||||||
return VULKAN_ERROR_INSTANCE_INIT_FAILED;
|
return VULKAN_ERROR_INSTANCE_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,10 +292,10 @@ static rse_err_t create_instance()
|
|||||||
*
|
*
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
*/
|
*/
|
||||||
static rse_err_t create_surface()
|
static rse_err_t create_surface(VkInstance instance, GLFWwindow* window_handle, VkSurfaceKHR* surface)
|
||||||
{
|
{
|
||||||
if (VK_SUCCESS != glfwCreateWindowSurface(g_vulkan_instance, get_window_handle(), NULL, &g_vulkan_state.surface)) {
|
if (VK_SUCCESS != glfwCreateWindowSurface(instance, window_handle, NULL, surface)) {
|
||||||
LOGF(vulkan_messages[VULKAN_SURFACE_CREATION_FAILED]);
|
LOGF(_("Failed to create window surface\n"));
|
||||||
return VULKAN_ERROR_SURFACE_CREATION_FAILED;
|
return VULKAN_ERROR_SURFACE_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
@@ -334,7 +308,7 @@ static rse_err_t create_surface()
|
|||||||
* VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND
|
* VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND
|
||||||
* VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND
|
* VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND
|
||||||
*/
|
*/
|
||||||
static rse_err_t pick_physical_device()
|
static rse_err_t pick_physical_device(VkInstance instance, VkPhysicalDevice* physical_device)
|
||||||
{
|
{
|
||||||
uint32_t physical_device_count = 0U;
|
uint32_t physical_device_count = 0U;
|
||||||
VkPhysicalDevice* physical_devices = NULL;
|
VkPhysicalDevice* physical_devices = NULL;
|
||||||
@@ -342,16 +316,16 @@ static rse_err_t pick_physical_device()
|
|||||||
VkPhysicalDeviceFeatures device_features = {0};
|
VkPhysicalDeviceFeatures device_features = {0};
|
||||||
|
|
||||||
/* Get number of existing physical devices */
|
/* Get number of existing physical devices */
|
||||||
vkEnumeratePhysicalDevices(g_vulkan_instance, &physical_device_count, NULL);
|
vkEnumeratePhysicalDevices(instance, &physical_device_count, NULL);
|
||||||
|
|
||||||
if (0 == physical_device_count) {
|
if (0 == physical_device_count) {
|
||||||
LOGF(vulkan_messages[VULKAN_NO_PHYSICAL_DEVICES]);
|
LOGF(_("No physical graphical physical devices found in system\n"));
|
||||||
return VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND;
|
return VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_malloc(physical_devices, sizeof(VkPhysicalDevice) * physical_device_count);
|
rse_malloc(physical_devices, sizeof(VkPhysicalDevice) * physical_device_count);
|
||||||
|
|
||||||
vkEnumeratePhysicalDevices(g_vulkan_instance, &physical_device_count, physical_devices);
|
vkEnumeratePhysicalDevices(instance, &physical_device_count, physical_devices);
|
||||||
|
|
||||||
/* Check for suitability */
|
/* Check for suitability */
|
||||||
for (size_t physicalDeviceIdx = 0U; physicalDeviceIdx < physical_device_count; ++physicalDeviceIdx) {
|
for (size_t physicalDeviceIdx = 0U; physicalDeviceIdx < physical_device_count; ++physicalDeviceIdx) {
|
||||||
@@ -363,14 +337,14 @@ static rse_err_t pick_physical_device()
|
|||||||
device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
|
device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
|
||||||
/* Application MUST have geometry shader */
|
/* Application MUST have geometry shader */
|
||||||
if (device_features.geometryShader) {
|
if (device_features.geometryShader) {
|
||||||
g_vulkan_state.physical_device = physical_devices[physicalDeviceIdx];
|
*physical_device = physical_devices[physicalDeviceIdx];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VK_NULL_HANDLE == g_vulkan_state.physical_device) {
|
if (VK_NULL_HANDLE == physical_device) {
|
||||||
/* No suitable device found */
|
/* No suitable device found */
|
||||||
LOGF(vulkan_messages[VULKAN_NO_SUITABLE_PHYSICAL_DEVICES]);
|
LOGF(_("No suitable physical device found\n"));
|
||||||
return VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND;
|
return VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +358,7 @@ static rse_err_t pick_physical_device()
|
|||||||
* VULKAN_ERROR_QUEUE_NOT_SUPPORTED
|
* VULKAN_ERROR_QUEUE_NOT_SUPPORTED
|
||||||
* VULKAN_ERROR_DEVICE_CREATION_FAILED
|
* VULKAN_ERROR_DEVICE_CREATION_FAILED
|
||||||
*/
|
*/
|
||||||
static rse_err_t create_device()
|
static rse_err_t create_device(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
size_t device_queues_count = 0;
|
size_t device_queues_count = 0;
|
||||||
uint32_t queue_families_property_count = 0U;
|
uint32_t queue_families_property_count = 0U;
|
||||||
@@ -398,6 +372,11 @@ static rse_err_t create_device()
|
|||||||
VkPhysicalDeviceFeatures2 physical_features2 = {0};
|
VkPhysicalDeviceFeatures2 physical_features2 = {0};
|
||||||
VkPhysicalDeviceDescriptorIndexingFeatures indexing_features = {0};
|
VkPhysicalDeviceDescriptorIndexingFeatures indexing_features = {0};
|
||||||
VkBool32 bindless_supported = VK_FALSE;
|
VkBool32 bindless_supported = VK_FALSE;
|
||||||
|
uint32_t enabled_device_extensions_count = 2;
|
||||||
|
const char* enabled_device_extensions_names[] = {
|
||||||
|
"VK_KHR_swapchain",
|
||||||
|
"VK_EXT_descriptor_indexing",
|
||||||
|
};
|
||||||
|
|
||||||
/* Enable descriptori indexing for bindless textures */
|
/* Enable descriptori indexing for bindless textures */
|
||||||
indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
|
indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
|
||||||
@@ -405,18 +384,18 @@ static rse_err_t create_device()
|
|||||||
physical_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
physical_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||||
physical_features2.pNext = &indexing_features;
|
physical_features2.pNext = &indexing_features;
|
||||||
|
|
||||||
vkGetPhysicalDeviceFeatures2(g_vulkan_state.physical_device, &physical_features2);
|
vkGetPhysicalDeviceFeatures2(context->physical_device, &physical_features2);
|
||||||
|
|
||||||
bindless_supported = indexing_features.descriptorBindingPartiallyBound && indexing_features.runtimeDescriptorArray;
|
bindless_supported = indexing_features.descriptorBindingPartiallyBound && indexing_features.runtimeDescriptorArray;
|
||||||
if (bindless_supported == VK_FALSE) {
|
if (bindless_supported == VK_FALSE) {
|
||||||
LOGF(vulkan_messages[VULKAN_BINDLESS_DESIGN_NOT_SUPPORTED]);
|
LOGF(_("Required features for bindless design not supported\n"));
|
||||||
return VULKAN_ERROR_MISSING_FEATURES_FOR_BINDLESS_DESIGN;
|
return VULKAN_ERROR_MISSING_FEATURES_FOR_BINDLESS_DESIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get information about supported queue families */
|
/* Get information about supported queue families */
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(g_vulkan_state.physical_device, &queue_families_property_count, NULL);
|
vkGetPhysicalDeviceQueueFamilyProperties(context->physical_device, &queue_families_property_count, NULL);
|
||||||
rse_malloc(queue_family_properties, 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,
|
vkGetPhysicalDeviceQueueFamilyProperties(context->physical_device, &queue_families_property_count,
|
||||||
queue_family_properties);
|
queue_family_properties);
|
||||||
|
|
||||||
/* Get queue families that support graphics operations AND have most
|
/* Get queue families that support graphics operations AND have most
|
||||||
@@ -436,7 +415,7 @@ static rse_err_t create_device()
|
|||||||
|
|
||||||
/* Check for family with surface support */
|
/* Check for family with surface support */
|
||||||
VkBool32 presentSupport = VK_FALSE;
|
VkBool32 presentSupport = VK_FALSE;
|
||||||
vkGetPhysicalDeviceSurfaceSupportKHR(g_vulkan_state.physical_device, familyIdx, g_vulkan_state.surface, &presentSupport);
|
vkGetPhysicalDeviceSurfaceSupportKHR(context->physical_device, familyIdx, context->surface, &presentSupport);
|
||||||
if (presentSupport) {
|
if (presentSupport) {
|
||||||
presentation_familiy_idx = familyIdx;
|
presentation_familiy_idx = familyIdx;
|
||||||
/* If this is the same queue family as in graphics family, don't increase queue count */
|
/* If this is the same queue family as in graphics family, don't increase queue count */
|
||||||
@@ -453,11 +432,11 @@ static rse_err_t create_device()
|
|||||||
|
|
||||||
/* This is not magic number ;P. We want to support exact number of required queues flags */
|
/* This is not magic number ;P. We want to support exact number of required queues flags */
|
||||||
if (0 > graphics_family_idx) {
|
if (0 > graphics_family_idx) {
|
||||||
LOGF(vulkan_messages[VULKAN_QUEUE_NOT_SUPPORTED]);
|
LOGF(_("Selected physical device does not support required queue capabilities\n"));
|
||||||
return VULKAN_ERROR_QUEUE_NOT_SUPPORTED;
|
return VULKAN_ERROR_QUEUE_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_vulkan_state.queue_family_indices[0] = graphics_family_idx;
|
context->queue_family_indices[0] = graphics_family_idx;
|
||||||
|
|
||||||
rse_malloc(graphics_familiy_queue_priorities, sizeof(float) * queue_family_properties[graphics_family_idx].queueCount);
|
rse_malloc(graphics_familiy_queue_priorities, sizeof(float) * queue_family_properties[graphics_family_idx].queueCount);
|
||||||
|
|
||||||
@@ -492,17 +471,21 @@ static rse_err_t create_device()
|
|||||||
device_create_info.pQueueCreateInfos = device_queue_createinfos;
|
device_create_info.pQueueCreateInfos = device_queue_createinfos;
|
||||||
device_create_info.enabledLayerCount = 0;
|
device_create_info.enabledLayerCount = 0;
|
||||||
device_create_info.ppEnabledLayerNames = NULL;
|
device_create_info.ppEnabledLayerNames = NULL;
|
||||||
device_create_info.enabledExtensionCount = ENABLED_DEVICE_EXTENSIONS_COUT;
|
device_create_info.enabledExtensionCount = enabled_device_extensions_count;
|
||||||
device_create_info.ppEnabledExtensionNames = g_enabled_device_extensions_names;
|
device_create_info.ppEnabledExtensionNames = enabled_device_extensions_names;
|
||||||
device_create_info.pEnabledFeatures = NULL;
|
device_create_info.pEnabledFeatures = NULL;
|
||||||
|
|
||||||
if (VK_SUCCESS != vkCreateDevice(g_vulkan_state.physical_device, &device_create_info, NULL, &g_vulkan_state.device)) {
|
if (VK_SUCCESS != vkCreateDevice(context->physical_device, &device_create_info, NULL, &context->device)) {
|
||||||
LOGF(vulkan_messages[VULKAN_FAILED_TO_CREATE_DEVICE]);
|
LOGF(_("Failed to create logical device\n"));
|
||||||
return VULKAN_ERROR_DEVICE_CREATION_FAILED;
|
return VULKAN_ERROR_DEVICE_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
vkGetDeviceQueue(g_vulkan_state.device, graphics_family_idx, 0, &g_vulkan_state.graphics_queue);
|
vkGetDeviceQueue(context->device, graphics_family_idx, 0, &context->graphics_queue);
|
||||||
vkGetDeviceQueue(g_vulkan_state.device, presentation_familiy_idx, 0, &g_present_queue);
|
vkGetDeviceQueue(context->device, presentation_familiy_idx, 0, &context->present_queue);
|
||||||
|
|
||||||
|
rse_free(presentation_familiy_queue_priorities);
|
||||||
|
rse_free(graphics_familiy_queue_priorities);
|
||||||
|
rse_free(queue_family_properties);
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
@@ -513,7 +496,7 @@ static rse_err_t create_device()
|
|||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
* VULKAN_ERROR_ALLOCATOR_CREATION_FAILED
|
* VULKAN_ERROR_ALLOCATOR_CREATION_FAILED
|
||||||
*/
|
*/
|
||||||
static rse_err_t create_memory_allocator()
|
static rse_err_t create_memory_allocator(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
VmaVulkanFunctions vulkan_functions = {0};
|
VmaVulkanFunctions vulkan_functions = {0};
|
||||||
vulkan_functions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr;
|
vulkan_functions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr;
|
||||||
@@ -521,13 +504,13 @@ static rse_err_t create_memory_allocator()
|
|||||||
|
|
||||||
VmaAllocatorCreateInfo allocator_create_info = {0};
|
VmaAllocatorCreateInfo allocator_create_info = {0};
|
||||||
allocator_create_info.vulkanApiVersion = VK_API_VERSION_1_3;
|
allocator_create_info.vulkanApiVersion = VK_API_VERSION_1_3;
|
||||||
allocator_create_info.physicalDevice = g_vulkan_state.physical_device;
|
allocator_create_info.physicalDevice = context->physical_device;
|
||||||
allocator_create_info.device = g_vulkan_state.device;
|
allocator_create_info.device = context->device;
|
||||||
allocator_create_info.instance = g_vulkan_instance;
|
allocator_create_info.instance = context->instance;
|
||||||
allocator_create_info.pVulkanFunctions = &vulkan_functions;
|
allocator_create_info.pVulkanFunctions = &vulkan_functions;
|
||||||
|
|
||||||
if (VK_SUCCESS != vmaCreateAllocator(&allocator_create_info, &g_vulkan_state.allocator)) {
|
if (VK_SUCCESS != vmaCreateAllocator(&allocator_create_info, &context->allocator)) {
|
||||||
LOGF(vulkan_messages[VULKAN_ALLOCATOR_CREATION_FAILED]);
|
LOGF(_("Failed to create Vulkan Memory Allocator\n"));
|
||||||
return VULKAN_ERROR_ALLOCATOR_CREATION_FAILED;
|
return VULKAN_ERROR_ALLOCATOR_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,7 +524,7 @@ static rse_err_t create_memory_allocator()
|
|||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
* VULKAN_ERROR_SYNCOBJCTS_CREATION_FAILED
|
* VULKAN_ERROR_SYNCOBJCTS_CREATION_FAILED
|
||||||
*/
|
*/
|
||||||
static rse_err_t create_sync_objects()
|
static rse_err_t create_sync_objects(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
VkSemaphoreCreateInfo semaphore_info = {};
|
VkSemaphoreCreateInfo semaphore_info = {};
|
||||||
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
@@ -551,10 +534,10 @@ static rse_err_t create_sync_objects()
|
|||||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
|
||||||
for (size_t i = 0; i < SWAP_BUFFER_COUNT; ++i) {
|
for (size_t i = 0; i < SWAP_BUFFER_COUNT; ++i) {
|
||||||
if (VK_SUCCESS != vkCreateSemaphore(g_vulkan_state.device, &semaphore_info, NULL, &g_image_available_semaphores[i]) ||
|
if (VK_SUCCESS != vkCreateSemaphore(context->device, &semaphore_info, NULL, &context->image_available_semaphores[i]) ||
|
||||||
VK_SUCCESS != vkCreateSemaphore(g_vulkan_state.device, &semaphore_info, NULL, &g_render_finished_semaphores[i]) ||
|
VK_SUCCESS != vkCreateSemaphore(context->device, &semaphore_info, NULL, &context->render_finished_semaphores[i]) ||
|
||||||
VK_SUCCESS != vkCreateFence(g_vulkan_state.device, &fenceInfo, NULL, &g_in_flight_fences[i])) {
|
VK_SUCCESS != vkCreateFence(context->device, &fenceInfo, NULL, &context->in_flight_fences[i])) {
|
||||||
LOGF(vulkan_messages[VULKAN_SYNCOBJCTS_CREATION_FAILED]);
|
LOGF(_("Failed to create sync objects.\n"));
|
||||||
return VULKAN_ERROR_SYNCOBJCTS_CREATION_FAILED;
|
return VULKAN_ERROR_SYNCOBJCTS_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,40 +546,38 @@ static rse_err_t create_sync_objects()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rse_err_t preinit_vulkan()
|
rse_err_t init_vulkan(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
|
||||||
set_enabled_extension();
|
STATUS_CHECK(create_instance(&context->instance));
|
||||||
STATUS_CHECK(create_instance());
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
STATUS_CHECK(setup_debug_messenger());
|
STATUS_CHECK(setup_debug_messenger(context->instance, &context->debug_messenger));
|
||||||
#endif
|
#endif
|
||||||
STATUS_CHECK(create_surface());
|
STATUS_CHECK(create_surface(context->instance, context->window_handle, &context->surface));
|
||||||
STATUS_CHECK(pick_physical_device());
|
STATUS_CHECK(pick_physical_device(context->instance, &context->physical_device));
|
||||||
STATUS_CHECK(create_device());
|
STATUS_CHECK(create_device(context));
|
||||||
STATUS_CHECK(create_memory_allocator());
|
STATUS_CHECK(create_memory_allocator(context));
|
||||||
STATUS_CHECK(init_commands());
|
STATUS_CHECK(init_commands(context));
|
||||||
STATUS_CHECK(create_buffers());
|
STATUS_CHECK(create_buffers(context));
|
||||||
STATUS_CHECK(init_vulkan_images());
|
STATUS_CHECK(init_vulkan_images(context));
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t init_vulkan()
|
rse_err_t run_vulkan(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
|
||||||
STATUS_CHECK(create_pipeline());
|
STATUS_CHECK(create_descriptors(context));
|
||||||
STATUS_CHECK(create_descriptors());
|
STATUS_CHECK(create_sync_objects(context));
|
||||||
STATUS_CHECK(create_sync_objects());
|
|
||||||
|
|
||||||
rse_init_time();
|
init_time();
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t draw_frame()
|
rse_err_t draw_frame(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
uint32_t image_index = 0U;
|
uint32_t image_index = 0U;
|
||||||
VkResult result = VK_FALSE;
|
VkResult result = VK_FALSE;
|
||||||
@@ -607,46 +588,46 @@ rse_err_t draw_frame()
|
|||||||
VkPresentInfoKHR present_info = {0};
|
VkPresentInfoKHR present_info = {0};
|
||||||
VkSwapchainKHR swap_chains[1];
|
VkSwapchainKHR swap_chains[1];
|
||||||
|
|
||||||
vkWaitForFences(g_vulkan_state.device, 1, &g_in_flight_fences[g_vulkan_state.current_frame], VK_TRUE, UINT64_MAX);
|
vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
|
||||||
|
|
||||||
rse_update_time();
|
update_time();
|
||||||
|
|
||||||
result = vkAcquireNextImageKHR(g_vulkan_state.device, g_vulkan_state.swapchain, UINT64_MAX, g_image_available_semaphores[g_vulkan_state.current_frame],
|
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame],
|
||||||
VK_NULL_HANDLE, &image_index);
|
VK_NULL_HANDLE, &image_index);
|
||||||
|
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||||
recreate_swapchain();
|
recreate_swapchain();
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
|
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
|
||||||
LOGF(vulkan_messages[VULKAN_ACQUIRE_SWAPCHAIN_FAILED]);
|
LOGF(_("Failed to acquire swapchain image\n"));
|
||||||
return VULKAN_ERROR_ACQUIRE_SWAPCHAIN_FAILED;
|
return VULKAN_ERROR_ACQUIRE_SWAPCHAIN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_uniform_buffers();
|
update_uniform_buffers(context);
|
||||||
|
|
||||||
/* Only reset the fence if we are submitting work */
|
/* Only reset the fence if we are submitting work */
|
||||||
vkResetFences(g_vulkan_state.device, 1, &g_in_flight_fences[g_vulkan_state.current_frame]);
|
vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
|
||||||
reset_command_buffer();
|
reset_command_buffer(context);
|
||||||
|
|
||||||
record_command_buffer(image_index);
|
record_command_buffer(context, image_index);
|
||||||
|
|
||||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
|
||||||
wait_semaphores[0] = g_image_available_semaphores[g_vulkan_state.current_frame];
|
wait_semaphores[0] = context->image_available_semaphores[context->current_frame];
|
||||||
wait_stages[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
wait_stages[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
submit_info.waitSemaphoreCount = 1;
|
submit_info.waitSemaphoreCount = 1;
|
||||||
submit_info.pWaitSemaphores = wait_semaphores;
|
submit_info.pWaitSemaphores = wait_semaphores;
|
||||||
submit_info.pWaitDstStageMask = wait_stages;
|
submit_info.pWaitDstStageMask = wait_stages;
|
||||||
|
|
||||||
submit_info.commandBufferCount = 1;
|
submit_info.commandBufferCount = 1;
|
||||||
submit_info.pCommandBuffers = &g_vulkan_state.command_buffers[g_vulkan_state.current_frame];
|
submit_info.pCommandBuffers = &context->command_buffers[context->current_frame];
|
||||||
|
|
||||||
signal_semaphores[0] = g_render_finished_semaphores[g_vulkan_state.current_frame];
|
signal_semaphores[0] = context->render_finished_semaphores[context->current_frame];
|
||||||
submit_info.signalSemaphoreCount = 1;
|
submit_info.signalSemaphoreCount = 1;
|
||||||
submit_info.pSignalSemaphores = signal_semaphores;
|
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) {
|
if (vkQueueSubmit(context->graphics_queue, 1, &submit_info, context->in_flight_fences[context->current_frame]) != VK_SUCCESS) {
|
||||||
LOGF(vulkan_messages[VULAKN_DRAW_FAILED]);
|
LOGF(_("Failed to submit draw command buffer!\n"));
|
||||||
return VULKAN_ERROR_DRAW_FAILED;
|
return VULKAN_ERROR_DRAW_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,49 +636,49 @@ rse_err_t draw_frame()
|
|||||||
present_info.waitSemaphoreCount = 1;
|
present_info.waitSemaphoreCount = 1;
|
||||||
present_info.pWaitSemaphores = signal_semaphores;
|
present_info.pWaitSemaphores = signal_semaphores;
|
||||||
|
|
||||||
swap_chains[0] = g_vulkan_state.swapchain;
|
swap_chains[0] = context->swapchain;
|
||||||
present_info.swapchainCount = 1;
|
present_info.swapchainCount = 1;
|
||||||
present_info.pSwapchains = swap_chains;
|
present_info.pSwapchains = swap_chains;
|
||||||
|
|
||||||
present_info.pImageIndices = &image_index;
|
present_info.pImageIndices = &image_index;
|
||||||
|
|
||||||
result = vkQueuePresentKHR(g_present_queue, &present_info);
|
result = vkQueuePresentKHR(context->present_queue, &present_info);
|
||||||
|
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || is_framebuffer_resized()) {
|
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || context->is_framebuffer_resized) {
|
||||||
reset_framebuffer_resized();
|
context->is_framebuffer_resized = false;
|
||||||
recreate_swapchain();
|
recreate_swapchain();
|
||||||
} else if (result != VK_SUCCESS) {
|
} else if (result != VK_SUCCESS) {
|
||||||
LOGF(vulkan_messages[VULAKN_DRAW_FAILED]);
|
LOGF(_("Failed to submit draw command buffer!\n"));
|
||||||
return VULKAN_ERROR_DRAW_FAILED;
|
return VULKAN_ERROR_DRAW_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_vulkan_state.current_frame = (g_vulkan_state.current_frame + 1) % SWAP_BUFFER_COUNT;
|
context->current_frame = (context->current_frame + 1) % SWAP_BUFFER_COUNT;
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinit_vulkan()
|
void deinit_vulkan(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
cleanup_swapchain();
|
cleanup_swapchain();
|
||||||
destroy_descriptors();
|
destroy_descriptors();
|
||||||
destroy_buffers();
|
destroy_buffers(context);
|
||||||
for (size_t i = 0; i < SWAP_BUFFER_COUNT; ++i) {
|
for (size_t i = 0; i < SWAP_BUFFER_COUNT; ++i) {
|
||||||
vkDestroySemaphore(g_vulkan_state.device, g_image_available_semaphores[i], NULL);
|
vkDestroySemaphore(context->device, context->image_available_semaphores[i], NULL);
|
||||||
vkDestroySemaphore(g_vulkan_state.device, g_render_finished_semaphores[i], NULL);
|
vkDestroySemaphore(context->device, context->render_finished_semaphores[i], NULL);
|
||||||
vkDestroyFence(g_vulkan_state.device, g_in_flight_fences[i], NULL);
|
vkDestroyFence(context->device, context->in_flight_fences[i], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_destroy_textures();
|
destroy_textures();
|
||||||
|
|
||||||
destroy_commands();
|
destroy_commands(context);
|
||||||
|
|
||||||
destroy_pipeline();
|
destroy_pipeline();
|
||||||
|
|
||||||
vmaDestroyAllocator(g_vulkan_state.allocator);
|
vmaDestroyAllocator(context->allocator);
|
||||||
vkDestroyDevice(g_vulkan_state.device, NULL);
|
vkDestroyDevice(context->device, NULL);
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
DestroyDebugUtilsMessengerEXT(g_vulkan_instance, g_debug_messenger, NULL);
|
DestroyDebugUtilsMessengerEXT(context->instance, context->debug_messenger, NULL);
|
||||||
#endif
|
#endif
|
||||||
vkDestroySurfaceKHR(g_vulkan_instance, g_vulkan_state.surface, NULL);
|
vkDestroySurfaceKHR(context->instance, context->surface, NULL);
|
||||||
vkDestroyInstance(g_vulkan_instance, NULL);
|
vkDestroyInstance(context->instance, NULL);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file vulkanBase.h
|
* @file vulkan_base.h
|
||||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
* @brief Vulkan wrapper functions used by other parts of Graphics component
|
* @brief Vulkan wrapper functions used by other parts of Graphics component
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
@@ -9,38 +9,43 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_GRAPHICS_VULKANBASE_H
|
#ifndef GRAPHICS_VULKANBASE_H
|
||||||
#define RSE_GRAPHICS_VULKANBASE_H
|
#define GRAPHICS_VULKANBASE_H
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
#include "utilities/rse_commons.h"
|
#include "utilities/commons.h"
|
||||||
|
#include "graphics_context.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize Vulkan backend for buffers and stuff
|
* @brief Initialize Vulkan backend for buffers and stuff
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @return rse_err_t 0 on success. Status code on failure
|
* @return rse_err_t 0 on success. Status code on failure
|
||||||
*/
|
*/
|
||||||
rse_err_t preinit_vulkan();
|
rse_err_t init_vulkan(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize Vulkan backend with descriptors
|
* @brief Initialize Vulkan backend with descriptors
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @return rse_err_t 0 on success. Status code on failure
|
* @return rse_err_t 0 on success. Status code on failure
|
||||||
*/
|
*/
|
||||||
rse_err_t init_vulkan();
|
rse_err_t run_vulkan(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deinitialize Vulkan backend
|
* @brief Deinitialize Vulkan backend
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* */
|
* */
|
||||||
void deinit_vulkan();
|
void deinit_vulkan(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Draw frame on the screen.
|
* @brief Draw frame on the screen.
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context
|
||||||
* @return rse_err_t
|
* @return rse_err_t
|
||||||
*/
|
*/
|
||||||
rse_err_t draw_frame();
|
rse_err_t draw_frame(struct graphics_context_t* context);
|
||||||
|
|
||||||
#endif /* RSE_GRAPHICS_VULKANBASE_HPP */
|
#endif /* GRAPHICS_VULKANBASE_H */
|
||||||
+112
-109
@@ -1,26 +1,20 @@
|
|||||||
#include "vulkan_buffers.h"
|
#include "vulkan_buffers.h"
|
||||||
|
|
||||||
|
#include "src/graphics_context.h"
|
||||||
#include "src/vulkan_commons.h"
|
#include "src/vulkan_commons.h"
|
||||||
#include "utilities/rse_commons.h"
|
#include "utilities/commons.h"
|
||||||
#include "vulkan_errors.h"
|
#include "vulkan_errors.h"
|
||||||
#include "locale_vulkan.h"
|
|
||||||
#include "utilities/logger.h"
|
#include "utilities/logger.h"
|
||||||
#include "utilities/rse_errors_common.h"
|
#include "utilities/localization.h"
|
||||||
#include "rse_math.h"
|
#include "utilities/errors_common.h"
|
||||||
#include "rse_vulkan_commands.h"
|
#include "math.h"
|
||||||
|
#include "vulkan_commands.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define MAX_VERTEX_BUFFER_SIZE 33554432 /* 32 MB*/
|
#define MAX_VERTEX_BUFFER_SIZE 33554432 /* 32 MB*/
|
||||||
|
|
||||||
/* GPU visible buffer */
|
|
||||||
size_t g_vertex_offset = 0;
|
|
||||||
struct rse_vulkan_buffer_t g_vertex_buffer;
|
|
||||||
struct rse_vulkan_buffer_t g_index_buffer;
|
|
||||||
struct rse_vulkan_buffer_t g_instance_buffers[MAX_MESH_NUMBER];
|
|
||||||
struct rse_vulkan_buffer_t g_draw_indirect_command_buffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Copy one buffer's data to another
|
* @brief Copy one buffer's data to another
|
||||||
*
|
*
|
||||||
@@ -28,13 +22,13 @@ struct rse_vulkan_buffer_t g_draw_indirect_command_buffer;
|
|||||||
* @param dst Destination buffer
|
* @param dst Destination buffer
|
||||||
* @param size Size of buffer to copy
|
* @param size Size of buffer to copy
|
||||||
*/
|
*/
|
||||||
static void copy_buffer(VkBuffer src, VkBuffer dst, VkDeviceSize size, VkDeviceSize dest_offset)
|
static void copy_buffer(struct graphics_context_t* context, VkBuffer src, VkBuffer dst, VkDeviceSize size, VkDeviceSize dest_offset)
|
||||||
{
|
{
|
||||||
/* Vulkan buffers can only be copied using command buffers */
|
/* Vulkan buffers can only be copied using command buffers */
|
||||||
VkBufferCopy copy_region = {};
|
VkBufferCopy copy_region = {};
|
||||||
VkCommandBuffer command_buffer = {0};
|
VkCommandBuffer command_buffer = {0};
|
||||||
|
|
||||||
command_buffer = rse_begin_single_time_command();
|
command_buffer = begin_single_time_command(context);
|
||||||
|
|
||||||
copy_region.srcOffset = 0U;
|
copy_region.srcOffset = 0U;
|
||||||
copy_region.dstOffset = dest_offset;
|
copy_region.dstOffset = dest_offset;
|
||||||
@@ -42,18 +36,19 @@ static void copy_buffer(VkBuffer src, VkBuffer dst, VkDeviceSize size, VkDeviceS
|
|||||||
|
|
||||||
vkCmdCopyBuffer(command_buffer, src, dst, 1, ©_region);
|
vkCmdCopyBuffer(command_buffer, src, dst, 1, ©_region);
|
||||||
|
|
||||||
rse_end_single_time_comands(command_buffer);
|
end_single_time_comands(context, command_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a buffer holding all vertex data
|
* @brief Create a buffer holding all vertex data
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @return rse_err_t RSE_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_BUFFER_CREATION_FAILED
|
||||||
* VULKAN_ERROR_VERTEX_BUFFER_MAPPING_FAILED
|
* VULKAN_ERROR_VERTEX_BUFFER_MAPPING_FAILED
|
||||||
*/
|
*/
|
||||||
static rse_err_t create_vertex_buffer()
|
static rse_err_t create_vertex_buffer(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
VkDeviceSize buffer_size;
|
VkDeviceSize buffer_size;
|
||||||
@@ -61,23 +56,24 @@ static rse_err_t create_vertex_buffer()
|
|||||||
buffer_size = MAX_VERTEX_BUFFER_SIZE;
|
buffer_size = MAX_VERTEX_BUFFER_SIZE;
|
||||||
|
|
||||||
/* Create Vertex Buffer*/
|
/* Create Vertex Buffer*/
|
||||||
STATUS_CHECK(create_buffer(buffer_size,
|
STATUS_CHECK(create_buffer(context, buffer_size,
|
||||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
|
||||||
0, /* Will not be mapped with vmaMapMemory */
|
0, /* Will not be mapped with vmaMapMemory */
|
||||||
&g_vertex_buffer));
|
&context->vertex_buffer));
|
||||||
|
|
||||||
g_vertex_buffer.allocated_size = 0;
|
context->vertex_buffer.allocated_size = 0;
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create an index buffer, connected with vertex buffer
|
* @brief Create an index buffer, connected with vertex buffer
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @return rse_err_t RSE_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_BUFFER_CREATION_FAILED
|
||||||
*/
|
*/
|
||||||
static rse_err_t create_index_buffer()
|
static rse_err_t create_index_buffer(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
VkDeviceSize buffer_size;
|
VkDeviceSize buffer_size;
|
||||||
@@ -85,68 +81,75 @@ static rse_err_t create_index_buffer()
|
|||||||
buffer_size = MAX_VERTEX_BUFFER_SIZE;
|
buffer_size = MAX_VERTEX_BUFFER_SIZE;
|
||||||
|
|
||||||
/* Create Index Buffer*/
|
/* Create Index Buffer*/
|
||||||
STATUS_CHECK(create_buffer(buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
STATUS_CHECK(create_buffer(context, buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
|
||||||
0, /* Will not be mapped with vmaMapMemory */
|
0, /* Will not be mapped with vmaMapMemory */
|
||||||
&g_index_buffer));
|
&context->index_buffer));
|
||||||
|
|
||||||
g_index_buffer.allocated_size = 0;
|
context->index_buffer.allocated_size = 0;
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rse_err_t create_instance_buffers()
|
/**
|
||||||
|
* @brief Create instance buffers
|
||||||
|
*
|
||||||
|
* @param[in/out] context Graphics context handle
|
||||||
|
* @return RSE_ERROR_NO_ERROR on success.
|
||||||
|
*/
|
||||||
|
static rse_err_t create_instance_buffers(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
size_t iter = 0U;
|
size_t iter = 0U;
|
||||||
VkDeviceSize buffer_size;
|
VkDeviceSize buffer_size;
|
||||||
|
|
||||||
buffer_size = sizeof(struct rse_instance_data_t) * MAX_INSTANCE_NUMBER;
|
buffer_size = sizeof(struct instance_data_t) * MAX_INSTANCE_NUMBER;
|
||||||
|
|
||||||
for (iter = 0; iter < MAX_MESH_NUMBER; ++iter) {
|
for (iter = 0; iter < MAX_MESH_NUMBER; ++iter) {
|
||||||
/* Create Instance Buffer */
|
/* Create Instance Buffer */
|
||||||
STATUS_CHECK(create_buffer(buffer_size,
|
STATUS_CHECK(create_buffer(context, buffer_size,
|
||||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
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 */
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0, /* Will not be mapped with vmaMapMemory */
|
||||||
&g_instance_buffers[iter]));
|
&context->instance_buffers[iter]));
|
||||||
|
|
||||||
g_instance_buffers[iter].allocated_size = 0;
|
context->instance_buffers[iter].allocated_size = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_CHECK(create_buffer(sizeof(VkDrawIndexedIndirectCommand) * MAX_MESH_NUMBER,
|
STATUS_CHECK(create_buffer(context, sizeof(VkDrawIndexedIndirectCommand) * MAX_MESH_NUMBER,
|
||||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||||
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
||||||
| VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
| VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
||||||
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||||
&g_draw_indirect_command_buffer));
|
&context->draw_indirect_command_buffer));
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a Uniform Buffers
|
* @brief Create a Uniform Buffers
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success.
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success.
|
||||||
*/
|
*/
|
||||||
static rse_err_t create_uniform_buffer()
|
static rse_err_t create_uniform_buffer(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
VkDeviceSize buffer_size = sizeof(struct rse_uniform_buffer_object_t);
|
VkDeviceSize buffer_size = sizeof(struct uniform_buffer_object_t);
|
||||||
|
|
||||||
for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) {
|
for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) {
|
||||||
STATUS_CHECK(create_buffer(buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
STATUS_CHECK(create_buffer(context, 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,
|
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||||
&g_vulkan_state.uniform_buffers[i]));
|
&context->uniform_buffers[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t create_buffer(const VkDeviceSize size,
|
rse_err_t create_buffer(struct graphics_context_t* context, const VkDeviceSize size,
|
||||||
VkBufferUsageFlags buffer_usage,
|
VkBufferUsageFlags buffer_usage,
|
||||||
VmaMemoryUsage memory_usage,
|
VmaMemoryUsage memory_usage,
|
||||||
const VmaAllocationCreateFlags allocation_flags,
|
const VmaAllocationCreateFlags allocation_flags,
|
||||||
struct rse_vulkan_buffer_t* buffer)
|
struct vulkan_buffer_t* buffer)
|
||||||
{
|
{
|
||||||
VkBufferCreateInfo vertex_buffer_info = {};
|
VkBufferCreateInfo vertex_buffer_info = {};
|
||||||
VmaAllocationCreateInfo create_info = {};
|
VmaAllocationCreateInfo create_info = {};
|
||||||
@@ -169,28 +172,28 @@ rse_err_t create_buffer(const VkDeviceSize size,
|
|||||||
create_info.pUserData = VK_NULL_HANDLE;
|
create_info.pUserData = VK_NULL_HANDLE;
|
||||||
create_info.priority = 0.0f;
|
create_info.priority = 0.0f;
|
||||||
|
|
||||||
if (VK_SUCCESS != vmaCreateBuffer(g_vulkan_state.allocator,
|
if (VK_SUCCESS != vmaCreateBuffer(context->allocator,
|
||||||
&vertex_buffer_info,
|
&vertex_buffer_info,
|
||||||
&create_info,
|
&create_info,
|
||||||
&buffer->buffer,
|
&buffer->buffer,
|
||||||
&buffer->allocation,
|
&buffer->allocation,
|
||||||
&buffer->allocation_info)) {
|
&buffer->allocation_info)) {
|
||||||
LOGF(vulkan_messages[VULKAN_BUFFER_CREATION_FAILED]);
|
LOGF(_("Failed to create a vertex buffer\n"));
|
||||||
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_buffer(struct rse_vulkan_buffer_t* buffer)
|
void destroy_buffer(struct graphics_context_t* context, struct vulkan_buffer_t* buffer)
|
||||||
{
|
{
|
||||||
vmaDestroyBuffer(g_vulkan_state.allocator, buffer->buffer, buffer->allocation);
|
vmaDestroyBuffer(context->allocator, buffer->buffer, buffer->allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void update_uniform_buffers()
|
void update_uniform_buffers(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
struct rse_uniform_buffer_object_t ubo = {};
|
struct uniform_buffer_object_t ubo = {};
|
||||||
struct vec3_t eye = {0};
|
struct vec3_t eye = {0};
|
||||||
struct vec3_t center = {0};
|
struct vec3_t center = {0};
|
||||||
struct vec3_t up = {0};
|
struct vec3_t up = {0};
|
||||||
@@ -203,35 +206,35 @@ void update_uniform_buffers()
|
|||||||
|
|
||||||
up.y = 1.0f;
|
up.y = 1.0f;
|
||||||
|
|
||||||
fovy = rse_math_deg_to_radians(45.0f);
|
fovy = math_deg_to_radians(45.0f);
|
||||||
z_near = 0.1f;
|
z_near = 0.1f;
|
||||||
z_far = 20.0f;
|
z_far = 20.0f;
|
||||||
|
|
||||||
ubo.model = rse_math_rotate(rse_math_uniform_mat4(), rse_math_deg_to_radians(0.0f), rotation_vec);
|
ubo.model = math_rotate(math_uniform_mat4(), math_deg_to_radians(0.0f), rotation_vec);
|
||||||
ubo.view = rse_math_look_at(&eye, ¢er, &up);
|
ubo.view = math_look_at(&eye, ¢er, &up);
|
||||||
ubo.proj = rse_math_perspective(fovy,
|
ubo.proj = math_perspective(fovy,
|
||||||
g_vulkan_state.swapchain_extent.width / (float)g_vulkan_state.swapchain_extent.height,
|
context->swapchain_extent.width / (float)context->swapchain_extent.height,
|
||||||
z_near,
|
z_near,
|
||||||
z_far);
|
z_far);
|
||||||
rse_memcpy(g_vulkan_state.uniform_buffers[g_vulkan_state.current_frame].allocation_info.pMappedData, &ubo, sizeof(ubo));
|
memcpy(context->uniform_buffers[context->current_frame].allocation_info.pMappedData, &ubo, sizeof(ubo));
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t rse_add_vertices(uint16_t mesh_id,
|
rse_err_t add_vertices(struct graphics_context_t* context, uint16_t mesh_id,
|
||||||
const struct rse_vertex_t* vertices,
|
const struct vertex_t* vertices,
|
||||||
const uint16_t* indices,
|
const uint16_t* indices,
|
||||||
struct rse_buffer_data_t* vertex_data,
|
struct buffer_data_t* vertex_data,
|
||||||
struct rse_buffer_data_t* index_data)
|
struct buffer_data_t* index_data)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
VkDrawIndexedIndirectCommand draw_indirect_command;
|
VkDrawIndexedIndirectCommand draw_indirect_command;
|
||||||
struct rse_vulkan_buffer_t staging_buffer;
|
struct vulkan_buffer_t staging_buffer;
|
||||||
size_t vertices_size = sizeof(vertices[0]) * vertex_data->count;
|
size_t vertices_size = sizeof(vertices[0]) * vertex_data->count;
|
||||||
size_t indices_size = sizeof(indices[0]) * index_data->count;
|
size_t indices_size = sizeof(indices[0]) * index_data->count;
|
||||||
|
|
||||||
struct rse_vulkan_buffer_t* index_buffer = &g_index_buffer;
|
struct vulkan_buffer_t* index_buffer = &context->index_buffer;
|
||||||
|
|
||||||
/* Creating staging buffer*/
|
/* Creating staging buffer*/
|
||||||
STATUS_CHECK(create_buffer(MAX_VERTEX_BUFFER_SIZE,
|
STATUS_CHECK(create_buffer(context, MAX_VERTEX_BUFFER_SIZE,
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
||||||
VMA_ALLOCATION_CREATE_MAPPED_BIT
|
VMA_ALLOCATION_CREATE_MAPPED_BIT
|
||||||
@@ -240,27 +243,27 @@ rse_err_t rse_add_vertices(uint16_t mesh_id,
|
|||||||
|
|
||||||
/* Fill staging buffer with vertex data */
|
/* Fill staging buffer with vertex data */
|
||||||
memset(staging_buffer.allocation_info.pMappedData, 0, MAX_VERTEX_BUFFER_SIZE);
|
memset(staging_buffer.allocation_info.pMappedData, 0, MAX_VERTEX_BUFFER_SIZE);
|
||||||
rse_memcpy(staging_buffer.allocation_info.pMappedData, vertices, vertices_size);
|
memcpy(staging_buffer.allocation_info.pMappedData, vertices, vertices_size);
|
||||||
copy_buffer(staging_buffer.buffer,
|
copy_buffer(context, staging_buffer.buffer,
|
||||||
g_vertex_buffer.buffer,
|
context->vertex_buffer.buffer,
|
||||||
vertices_size,
|
vertices_size,
|
||||||
g_vertex_buffer.allocated_size);
|
context->vertex_buffer.allocated_size);
|
||||||
|
|
||||||
vertex_data->buffer_offset = g_vertex_offset;
|
vertex_data->buffer_offset = context->vertex_offset;
|
||||||
g_vertex_offset += vertex_data->count;
|
context->vertex_offset += vertex_data->count;
|
||||||
g_vertex_buffer.allocated_size += vertices_size;
|
context->vertex_buffer.allocated_size += vertices_size;
|
||||||
|
|
||||||
/* Fill staging buffer with index data */
|
/* Fill staging buffer with index data */
|
||||||
memset(staging_buffer.allocation_info.pMappedData, 0, indices_size);
|
memset(staging_buffer.allocation_info.pMappedData, 0, indices_size);
|
||||||
rse_memcpy(staging_buffer.allocation_info.pMappedData, indices, indices_size);
|
memcpy(staging_buffer.allocation_info.pMappedData, indices, indices_size);
|
||||||
copy_buffer(staging_buffer.buffer,
|
copy_buffer(context, staging_buffer.buffer,
|
||||||
index_buffer->buffer,
|
index_buffer->buffer,
|
||||||
indices_size,
|
indices_size,
|
||||||
index_buffer->allocated_size);
|
index_buffer->allocated_size);
|
||||||
index_data->buffer_offset = index_buffer->allocated_size;
|
index_data->buffer_offset = index_buffer->allocated_size;
|
||||||
index_buffer->allocated_size += indices_size;
|
index_buffer->allocated_size += indices_size;
|
||||||
|
|
||||||
destroy_buffer(&staging_buffer);
|
destroy_buffer(context, &staging_buffer);
|
||||||
|
|
||||||
draw_indirect_command.indexCount = vertex_data->count;
|
draw_indirect_command.indexCount = vertex_data->count;
|
||||||
draw_indirect_command.instanceCount = 0;
|
draw_indirect_command.instanceCount = 0;
|
||||||
@@ -268,21 +271,21 @@ rse_err_t rse_add_vertices(uint16_t mesh_id,
|
|||||||
draw_indirect_command.vertexOffset = vertex_data->buffer_offset;
|
draw_indirect_command.vertexOffset = vertex_data->buffer_offset;
|
||||||
draw_indirect_command.firstInstance = 0;
|
draw_indirect_command.firstInstance = 0;
|
||||||
|
|
||||||
rse_memcpy(g_draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), &draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand));
|
memcpy(context->draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), &draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand));
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* instance_data)
|
rse_err_t update_mesh_instances(struct graphics_context_t* context, uint16_t mesh_id, struct instance_data_t* instance_data)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
VkDrawIndexedIndirectCommand draw_indirect_command;
|
VkDrawIndexedIndirectCommand draw_indirect_command;
|
||||||
struct rse_vulkan_buffer_t staging_buffer;
|
struct vulkan_buffer_t staging_buffer;
|
||||||
struct rse_vulkan_buffer_t* instance_buffer = &g_instance_buffers[mesh_id];
|
struct vulkan_buffer_t* instance_buffer = &context->instance_buffers[mesh_id];
|
||||||
size_t instance_size = sizeof(struct rse_instance_data_t);
|
size_t instance_size = sizeof(struct instance_data_t);
|
||||||
|
|
||||||
/* Creating staging buffer*/
|
/* Creating staging buffer*/
|
||||||
STATUS_CHECK(create_buffer(instance_size,
|
STATUS_CHECK(create_buffer(context, instance_size,
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
||||||
VMA_ALLOCATION_CREATE_MAPPED_BIT
|
VMA_ALLOCATION_CREATE_MAPPED_BIT
|
||||||
@@ -290,19 +293,19 @@ rse_err_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* in
|
|||||||
&staging_buffer));
|
&staging_buffer));
|
||||||
|
|
||||||
/* Copy transformation information about instance */
|
/* Copy transformation information about instance */
|
||||||
rse_memcpy(staging_buffer.allocation_info.pMappedData, instance_data, instance_size);
|
memcpy(staging_buffer.allocation_info.pMappedData, instance_data, instance_size);
|
||||||
copy_buffer(staging_buffer.buffer,
|
copy_buffer(context, staging_buffer.buffer,
|
||||||
instance_buffer->buffer,
|
instance_buffer->buffer,
|
||||||
instance_size,
|
instance_size,
|
||||||
instance_buffer->allocated_size);
|
instance_buffer->allocated_size);
|
||||||
|
|
||||||
destroy_buffer(&staging_buffer);
|
destroy_buffer(context, &staging_buffer);
|
||||||
|
|
||||||
instance_buffer->allocated_size += instance_size;
|
instance_buffer->allocated_size += instance_size;
|
||||||
|
|
||||||
rse_memcpy(&draw_indirect_command, g_draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), sizeof(VkDrawIndexedIndirectCommand));
|
memcpy(&draw_indirect_command, context->draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), sizeof(VkDrawIndexedIndirectCommand));
|
||||||
draw_indirect_command.instanceCount++;
|
draw_indirect_command.instanceCount++;
|
||||||
rse_memcpy(g_draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), &draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand));
|
memcpy(context->draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), &draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand));
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
@@ -315,11 +318,11 @@ rse_err_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* in
|
|||||||
* @return rse_err_t RSE_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
|
* VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED
|
||||||
*/
|
*/
|
||||||
rse_err_t record_command_buffer(uint32_t image_index)
|
rse_err_t record_command_buffer(struct graphics_context_t* context, uint32_t image_index)
|
||||||
{
|
{
|
||||||
VkCommandBuffer command_buffer = g_vulkan_state.command_buffers[g_vulkan_state.current_frame];
|
VkCommandBuffer command_buffer = context->command_buffers[context->current_frame];
|
||||||
VkDescriptorSet descriptor_sets[] = {g_vulkan_state.descriptor_sets[g_vulkan_state.current_frame],
|
VkDescriptorSet descriptor_sets[] = {context->descriptor_sets[context->current_frame],
|
||||||
g_vulkan_state.descriptor_sets_bindless};
|
context->descriptor_sets_bindless};
|
||||||
VkCommandBufferBeginInfo begin_info = {};
|
VkCommandBufferBeginInfo begin_info = {};
|
||||||
VkRenderPassBeginInfo render_pass_info = {};
|
VkRenderPassBeginInfo render_pass_info = {};
|
||||||
VkViewport viewport = {};
|
VkViewport viewport = {};
|
||||||
@@ -340,47 +343,47 @@ rse_err_t record_command_buffer(uint32_t image_index)
|
|||||||
begin_info.pInheritanceInfo = NULL;
|
begin_info.pInheritanceInfo = NULL;
|
||||||
|
|
||||||
if (vkBeginCommandBuffer(command_buffer, &begin_info) != VK_SUCCESS) {
|
if (vkBeginCommandBuffer(command_buffer, &begin_info) != VK_SUCCESS) {
|
||||||
LOGF(vulkan_messages[VULKAN_RECORD_COMMAND_BEGIN_FAILED]);
|
LOGF(_("Failed to start recording command buffer\n"));
|
||||||
return VULKAN_ERROR_RECORD_COMMAND_BEGIN_FAILED;
|
return VULKAN_ERROR_RECORD_COMMAND_BEGIN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
render_pass_info.renderPass = g_vulkan_state.render_pass;
|
render_pass_info.renderPass = context->render_pass;
|
||||||
render_pass_info.framebuffer = g_vulkan_state.swapchain_framebuffers[image_index];
|
render_pass_info.framebuffer = context->swapchain_framebuffers[image_index];
|
||||||
render_pass_info.renderArea.offset.x = 0;
|
render_pass_info.renderArea.offset.x = 0;
|
||||||
render_pass_info.renderArea.offset.y = 0;
|
render_pass_info.renderArea.offset.y = 0;
|
||||||
render_pass_info.renderArea.extent = g_vulkan_state.swapchain_extent;
|
render_pass_info.renderArea.extent = context->swapchain_extent;
|
||||||
render_pass_info.clearValueCount = 2;
|
render_pass_info.clearValueCount = 2;
|
||||||
render_pass_info.pClearValues = clear_values;
|
render_pass_info.pClearValues = clear_values;
|
||||||
|
|
||||||
vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_vulkan_state.graphics_pipeline);
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->graphics_pipeline);
|
||||||
|
|
||||||
viewport.x = 0.0f;
|
viewport.x = 0.0f;
|
||||||
viewport.y = 0.0f;
|
viewport.y = 0.0f;
|
||||||
viewport.width = (float)(g_vulkan_state.swapchain_extent.width);
|
viewport.width = (float)(context->swapchain_extent.width);
|
||||||
viewport.height = (float)(g_vulkan_state.swapchain_extent.height);
|
viewport.height = (float)(context->swapchain_extent.height);
|
||||||
viewport.minDepth = 0.0f;
|
viewport.minDepth = 0.0f;
|
||||||
viewport.maxDepth = 1.0f;
|
viewport.maxDepth = 1.0f;
|
||||||
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
||||||
|
|
||||||
scissor.offset.x = 0;
|
scissor.offset.x = 0;
|
||||||
scissor.offset.y = 0;
|
scissor.offset.y = 0;
|
||||||
scissor.extent = g_vulkan_state.swapchain_extent;
|
scissor.extent = context->swapchain_extent;
|
||||||
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
||||||
|
|
||||||
vkCmdBindVertexBuffers(command_buffer, 0, 1, &g_vertex_buffer.buffer, offsets);
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, &context->vertex_buffer.buffer, offsets);
|
||||||
vkCmdBindIndexBuffer(command_buffer, g_index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16);
|
vkCmdBindIndexBuffer(command_buffer, context->index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16);
|
||||||
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_vulkan_state.pipeline_layout, 0, 2,
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->pipeline_layout, 0, 2,
|
||||||
descriptor_sets, 0, NULL);
|
descriptor_sets, 0, NULL);
|
||||||
|
|
||||||
for (i = 0; i < MAX_MESH_NUMBER; ++i) {
|
for (i = 0; i < MAX_MESH_NUMBER; ++i) {
|
||||||
VkBuffer instance_buffer = {g_instance_buffers[i].buffer};
|
VkBuffer instance_buffer = {context->instance_buffers[i].buffer};
|
||||||
|
|
||||||
vkCmdBindVertexBuffers(command_buffer, 1, 1, &instance_buffer, offsets);
|
vkCmdBindVertexBuffers(command_buffer, 1, 1, &instance_buffer, offsets);
|
||||||
|
|
||||||
vkCmdDrawIndexedIndirect(command_buffer,
|
vkCmdDrawIndexedIndirect(command_buffer,
|
||||||
g_draw_indirect_command_buffer.buffer,
|
context->draw_indirect_command_buffer.buffer,
|
||||||
sizeof(VkDrawIndexedIndirectCommand) * i,
|
sizeof(VkDrawIndexedIndirectCommand) * i,
|
||||||
1,
|
1,
|
||||||
0); /* Can be 0 since we are not doing multiple draws each loop */
|
0); /* Can be 0 since we are not doing multiple draws each loop */
|
||||||
@@ -389,46 +392,46 @@ rse_err_t record_command_buffer(uint32_t image_index)
|
|||||||
vkCmdEndRenderPass(command_buffer);
|
vkCmdEndRenderPass(command_buffer);
|
||||||
|
|
||||||
if (VK_SUCCESS != vkEndCommandBuffer(command_buffer)) {
|
if (VK_SUCCESS != vkEndCommandBuffer(command_buffer)) {
|
||||||
LOGF(vulkan_messages[VULKAN_RECORD_COMMAND_BUFFER_FAILED]);
|
LOGF(_("Failed to record command buffer. Validate your commands.\n"));
|
||||||
return VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED;
|
return VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t create_buffers()
|
rse_err_t create_buffers(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
|
||||||
STATUS_CHECK(create_vertex_buffer());
|
STATUS_CHECK(create_vertex_buffer(context));
|
||||||
STATUS_CHECK(create_index_buffer());
|
STATUS_CHECK(create_index_buffer(context));
|
||||||
STATUS_CHECK(create_instance_buffers());
|
STATUS_CHECK(create_instance_buffers(context));
|
||||||
STATUS_CHECK(create_uniform_buffer());
|
STATUS_CHECK(create_uniform_buffer(context));
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset_command_buffer()
|
void reset_command_buffer(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
vkResetCommandBuffer(g_vulkan_state.command_buffers[g_vulkan_state.current_frame], /*VkCommandBufferResetFlagBits*/ 0);
|
vkResetCommandBuffer(context->command_buffers[context->current_frame], /*VkCommandBufferResetFlagBits*/ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void destroy_buffers()
|
void destroy_buffers(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
size_t i = 0U;
|
size_t i = 0U;
|
||||||
|
|
||||||
for (i = 0; i < SWAP_BUFFER_COUNT; ++i) {
|
for (i = 0; i < SWAP_BUFFER_COUNT; ++i) {
|
||||||
vmaDestroyBuffer(g_vulkan_state.allocator,
|
vmaDestroyBuffer(context->allocator,
|
||||||
g_vulkan_state.uniform_buffers[i].buffer,
|
context->uniform_buffers[i].buffer,
|
||||||
g_vulkan_state.uniform_buffers[i].allocation);
|
context->uniform_buffers[i].allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
vmaDestroyBuffer(g_vulkan_state.allocator, g_vertex_buffer.buffer, g_vertex_buffer.allocation);
|
vmaDestroyBuffer(context->allocator, context->vertex_buffer.buffer, context->vertex_buffer.allocation);
|
||||||
vmaDestroyBuffer(g_vulkan_state.allocator, g_index_buffer.buffer, g_index_buffer.allocation);
|
vmaDestroyBuffer(context->allocator, context->index_buffer.buffer, context->index_buffer.allocation);
|
||||||
vmaDestroyBuffer(g_vulkan_state.allocator, g_draw_indirect_command_buffer.buffer, g_draw_indirect_command_buffer.allocation);
|
vmaDestroyBuffer(context->allocator, context->draw_indirect_command_buffer.buffer, context->draw_indirect_command_buffer.allocation);
|
||||||
|
|
||||||
for(i = 0; i < MAX_MESH_NUMBER; ++i) {
|
for(i = 0; i < MAX_MESH_NUMBER; ++i) {
|
||||||
vmaDestroyBuffer(g_vulkan_state.allocator, g_instance_buffers[i].buffer, g_instance_buffers[i].allocation);
|
vmaDestroyBuffer(context->allocator, context->instance_buffers[i].buffer, context->instance_buffers[i].allocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,38 +1,30 @@
|
|||||||
#ifndef RSE_VULKAN_BUFFERS_H
|
#ifndef VULKAN_BUFFERS_H
|
||||||
#define RSE_VULKAN_BUFFERS_H
|
#define VULKAN_BUFFERS_H
|
||||||
|
|
||||||
#include "vulkan_commons.h"
|
#include "vulkan_commons.h"
|
||||||
#include "utilities/rse_commons.h"
|
#include "utilities/commons.h"
|
||||||
|
#include "graphics_context.h"
|
||||||
|
|
||||||
#include "vk_mem_alloc.h"
|
#include "vk_mem_alloc.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define MAX_MESH_NUMBER 256
|
|
||||||
#define MAX_INSTANCE_NUMBER 256
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Represents data within vertex or instance buffer.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
struct rse_buffer_data_t
|
|
||||||
{
|
|
||||||
size_t count;
|
|
||||||
size_t buffer_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create buffers needed by vulkan pipeline
|
* @brief Create buffers needed by vulkan pipeline
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||||
*/
|
*/
|
||||||
rse_err_t create_buffers();
|
rse_err_t create_buffers(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Update uniform buffers
|
* @brief Update uniform buffers
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void update_uniform_buffers();
|
void update_uniform_buffers(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add vertices and indices to vulkan buffers
|
* @brief Add vertices and indices to vulkan buffers
|
||||||
@@ -43,11 +35,11 @@ void update_uniform_buffers();
|
|||||||
* @param index_data Mutable index 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 rse_err_t RSE_ERROR_NO_ERROR on success
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||||
*/
|
*/
|
||||||
rse_err_t rse_add_vertices(uint16_t mesh_id,
|
rse_err_t add_vertices(struct graphics_context_t* context, uint16_t mesh_id,
|
||||||
const struct rse_vertex_t* vertices,
|
const struct vertex_t* vertices,
|
||||||
const uint16_t* indices,
|
const uint16_t* indices,
|
||||||
struct rse_buffer_data_t* vertex_data,
|
struct buffer_data_t* vertex_data,
|
||||||
struct rse_buffer_data_t* index_data);
|
struct buffer_data_t* index_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add instance data to vulkan buffers
|
* @brief Add instance data to vulkan buffers
|
||||||
@@ -56,7 +48,7 @@ rse_err_t rse_add_vertices(uint16_t mesh_id,
|
|||||||
* @param instance_data Instance data
|
* @param instance_data Instance data
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||||
*/
|
*/
|
||||||
rse_err_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* instance_data);
|
rse_err_t update_mesh_instances(struct graphics_context_t* context, uint16_t mesh_id, struct instance_data_t* instance_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Record commands for given image index
|
* @brief Record commands for given image index
|
||||||
@@ -65,21 +57,21 @@ rse_err_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* in
|
|||||||
* @param imageIndex
|
* @param imageIndex
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||||
*/
|
*/
|
||||||
rse_err_t record_command_buffer(uint32_t imageIndex);
|
rse_err_t record_command_buffer(struct graphics_context_t* context, uint32_t imageIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reset command buffer for current frame.
|
* @brief Reset command buffer for current frame.
|
||||||
*
|
*
|
||||||
* @param vulkan_state
|
* @param vulkan_state
|
||||||
*/
|
*/
|
||||||
void reset_command_buffer();
|
void reset_command_buffer(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Destroy ALL previously allocated buffers
|
* @brief Destroy ALL previously allocated buffers
|
||||||
*
|
*
|
||||||
* @param vulkan_state
|
* @param vulkan_state
|
||||||
*/
|
*/
|
||||||
void destroy_buffers();
|
void destroy_buffers(struct graphics_context_t* context);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,11 +85,11 @@ void destroy_buffers();
|
|||||||
* @return rse_err_t RSE_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
|
* VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED
|
||||||
*/
|
*/
|
||||||
rse_err_t create_buffer(const VkDeviceSize size,
|
rse_err_t create_buffer(struct graphics_context_t* context, const VkDeviceSize size,
|
||||||
VkBufferUsageFlags buffer_usage,
|
VkBufferUsageFlags buffer_usage,
|
||||||
VmaMemoryUsage memory_usage,
|
VmaMemoryUsage memory_usage,
|
||||||
const VmaAllocationCreateFlags allocation_flags,
|
const VmaAllocationCreateFlags allocation_flags,
|
||||||
struct rse_vulkan_buffer_t* buffer);
|
struct vulkan_buffer_t* buffer);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,6 +97,6 @@ rse_err_t create_buffer(const VkDeviceSize size,
|
|||||||
*
|
*
|
||||||
* @param buffer buffer to destroy
|
* @param buffer buffer to destroy
|
||||||
*/
|
*/
|
||||||
void destroy_buffer(struct rse_vulkan_buffer_t* buffer);
|
void destroy_buffer(struct graphics_context_t* context, struct vulkan_buffer_t* buffer);
|
||||||
|
|
||||||
#endif /* RSE_VULKAN_BUFFERS_H */
|
#endif /* VULKAN_BUFFERS_H */
|
||||||
@@ -1,30 +1,30 @@
|
|||||||
#include "rse_vulkan_commands.h"
|
#include "vulkan_commands.h"
|
||||||
|
|
||||||
|
#include "src/graphics_context.h"
|
||||||
#include "vulkan_commons.h"
|
#include "vulkan_commons.h"
|
||||||
#include "vulkan_errors.h"
|
#include "vulkan_errors.h"
|
||||||
#include "locale_vulkan.h"
|
|
||||||
#include "utilities/logger.h"
|
#include "utilities/logger.h"
|
||||||
#include "utilities/rse_errors_common.h"
|
#include "utilities/errors_common.h"
|
||||||
|
#include "utilities/localization.h"
|
||||||
VkCommandPool g_command_pool = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create Command Pools
|
* @brief Create Command Pools
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @return rse_err_t RSE_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
|
* VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED
|
||||||
*/
|
*/
|
||||||
static rse_err_t create_command_pools()
|
static rse_err_t create_command_pools(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
VkCommandPoolCreateInfo create_info;
|
VkCommandPoolCreateInfo create_info;
|
||||||
|
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
create_info.pNext = NULL;
|
create_info.pNext = NULL;
|
||||||
create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
create_info.queueFamilyIndex = g_vulkan_state.queue_family_indices[0];
|
create_info.queueFamilyIndex = context->queue_family_indices[0];
|
||||||
|
|
||||||
if (VK_SUCCESS != vkCreateCommandPool(g_vulkan_state.device, &create_info, NULL, &g_command_pool)) {
|
if (VK_SUCCESS != vkCreateCommandPool(context->device, &create_info, NULL, &context->command_pool)) {
|
||||||
LOGF(vulkan_messages[VULKAN_COMMAND_POOL_CREATION_FAILED]);
|
LOGF(_("Failed to create command pool\n"));
|
||||||
return VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED;
|
return VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,30 +34,31 @@ static rse_err_t create_command_pools()
|
|||||||
/**
|
/**
|
||||||
* @brief Allocate Command Buffers
|
* @brief Allocate Command Buffers
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @return rse_err_t RSE_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
|
* VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED
|
||||||
*/
|
*/
|
||||||
static rse_err_t allocate_command_buffers()
|
static rse_err_t allocate_command_buffers(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
VkCommandBufferAllocateInfo allocate_info;
|
VkCommandBufferAllocateInfo allocate_info;
|
||||||
|
|
||||||
/* Allocate memory for command buffers */
|
/* Allocate memory for command buffers */
|
||||||
allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
allocate_info.pNext = NULL;
|
allocate_info.pNext = NULL;
|
||||||
allocate_info.commandPool = g_command_pool;
|
allocate_info.commandPool = context->command_pool;
|
||||||
allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
allocate_info.commandBufferCount = SWAP_BUFFER_COUNT;
|
allocate_info.commandBufferCount = SWAP_BUFFER_COUNT;
|
||||||
|
|
||||||
if (VK_SUCCESS != vkAllocateCommandBuffers(g_vulkan_state.device,
|
if (VK_SUCCESS != vkAllocateCommandBuffers(context->device,
|
||||||
&allocate_info,
|
&allocate_info,
|
||||||
g_vulkan_state.command_buffers)) {
|
context->command_buffers)) {
|
||||||
LOGF(vulkan_messages[VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED]);
|
LOGF(_("Failed to allocate command buffers\n"));
|
||||||
return VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED;
|
return VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED;
|
||||||
}
|
}
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkCommandBuffer rse_begin_single_time_command()
|
VkCommandBuffer begin_single_time_command(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
VkCommandBuffer command_buffer = VK_NULL_HANDLE;
|
VkCommandBuffer command_buffer = VK_NULL_HANDLE;
|
||||||
VkCommandBufferBeginInfo begin_info = {};
|
VkCommandBufferBeginInfo begin_info = {};
|
||||||
@@ -65,7 +66,7 @@ VkCommandBuffer rse_begin_single_time_command()
|
|||||||
|
|
||||||
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
alloc_info.pNext = NULL;
|
alloc_info.pNext = NULL;
|
||||||
alloc_info.commandPool = g_command_pool;
|
alloc_info.commandPool = context->command_pool;
|
||||||
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
alloc_info.commandBufferCount = 1;
|
alloc_info.commandBufferCount = 1;
|
||||||
|
|
||||||
@@ -74,13 +75,13 @@ VkCommandBuffer rse_begin_single_time_command()
|
|||||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
begin_info.pInheritanceInfo = NULL;
|
begin_info.pInheritanceInfo = NULL;
|
||||||
|
|
||||||
vkAllocateCommandBuffers(g_vulkan_state.device, &alloc_info, &command_buffer);
|
vkAllocateCommandBuffers(context->device, &alloc_info, &command_buffer);
|
||||||
vkBeginCommandBuffer(command_buffer, &begin_info);
|
vkBeginCommandBuffer(command_buffer, &begin_info);
|
||||||
|
|
||||||
return command_buffer;
|
return command_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rse_end_single_time_comands(VkCommandBuffer command_buffer)
|
void end_single_time_comands(struct graphics_context_t* context, VkCommandBuffer command_buffer)
|
||||||
{
|
{
|
||||||
VkSubmitInfo submit_info = {};
|
VkSubmitInfo submit_info = {};
|
||||||
|
|
||||||
@@ -96,22 +97,22 @@ void rse_end_single_time_comands(VkCommandBuffer command_buffer)
|
|||||||
|
|
||||||
vkEndCommandBuffer(command_buffer);
|
vkEndCommandBuffer(command_buffer);
|
||||||
|
|
||||||
vkQueueSubmit(g_vulkan_state.graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
|
vkQueueSubmit(context->graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||||
vkQueueWaitIdle(g_vulkan_state.graphics_queue);
|
vkQueueWaitIdle(context->graphics_queue);
|
||||||
|
|
||||||
vkFreeCommandBuffers(g_vulkan_state.device, g_command_pool, 1, &command_buffer);
|
vkFreeCommandBuffers(context->device, context->command_pool, 1, &command_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t init_commands()
|
rse_err_t init_commands(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
STATUS_CHECK(create_command_pools());
|
STATUS_CHECK(create_command_pools(context));
|
||||||
STATUS_CHECK(allocate_command_buffers());
|
STATUS_CHECK(allocate_command_buffers(context));
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_commands()
|
void destroy_commands(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
vkDestroyCommandPool(g_vulkan_state.device, g_command_pool, NULL);
|
vkDestroyCommandPool(context->device, context->command_pool, NULL);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file rse_vulkan_commands.h
|
* @file vulkan_commands.h
|
||||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
* @brief Vukan Commands allocation and execution
|
* @brief Vukan Commands allocation and execution
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
@@ -9,37 +9,43 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_VULKAN_COMMANDS_H
|
#ifndef VULKAN_COMMANDS_H
|
||||||
#define RSE_VULKAN_COMMANDS_H
|
#define VULKAN_COMMANDS_H
|
||||||
|
|
||||||
#include "vk_mem_alloc.h"
|
#include "vk_mem_alloc.h"
|
||||||
#include "utilities/rse_commons.h"
|
#include "utilities/commons.h"
|
||||||
|
#include "graphics_context.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize vulkan commands pools and sets
|
* @brief Initialize vulkan commands pools and sets
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||||
*/
|
*/
|
||||||
rse_err_t init_commands();
|
rse_err_t init_commands(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Destroy vulkan commands sets and pools
|
* @brief Destroy vulkan commands sets and pools
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void destroy_commands();
|
void destroy_commands(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper function, creates command buffer for recording a command. Useful for copying buffer na images.
|
* @brief Helper function, creates command buffer for recording a command. Useful for copying buffer na images.
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @return VkCommandBuffer Created command buffer, ready to be filled with commands.
|
* @return VkCommandBuffer Created command buffer, ready to be filled with commands.
|
||||||
*/
|
*/
|
||||||
VkCommandBuffer rse_begin_single_time_command();
|
VkCommandBuffer begin_single_time_command(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Close command buffer and execute recorded command.
|
* @brief Close command buffer and execute recorded command.
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @param command_buffer Command buffer for execution
|
* @param command_buffer Command buffer for execution
|
||||||
*/
|
*/
|
||||||
void rse_end_single_time_comands(VkCommandBuffer command_buffer);
|
void end_single_time_comands(struct graphics_context_t* context, VkCommandBuffer command_buffer);
|
||||||
|
|
||||||
#endif /* RSE_VULKAN_COMMANDS_H */
|
#endif /* VULKAN_COMMANDS_H */
|
||||||
@@ -2,25 +2,23 @@
|
|||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
struct rse_vulkan_state_t g_vulkan_state;
|
|
||||||
|
|
||||||
time_t g_last_frame_time;
|
time_t g_last_frame_time;
|
||||||
time_t g_this_frame_time;
|
time_t g_this_frame_time;
|
||||||
float g_float_delta_time;
|
float g_float_delta_time;
|
||||||
|
|
||||||
void rse_init_time()
|
void init_time()
|
||||||
{
|
{
|
||||||
time(&g_last_frame_time);
|
time(&g_last_frame_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rse_update_time()
|
void update_time()
|
||||||
{
|
{
|
||||||
g_last_frame_time = g_this_frame_time;
|
g_last_frame_time = g_this_frame_time;
|
||||||
time(&g_this_frame_time);
|
time(&g_this_frame_time);
|
||||||
g_float_delta_time = (float)difftime(g_this_frame_time, g_last_frame_time);
|
g_float_delta_time = (float)difftime(g_this_frame_time, g_last_frame_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
float rse_get_time_diff()
|
float get_time_diff()
|
||||||
{
|
{
|
||||||
return g_float_delta_time;
|
return g_float_delta_time;
|
||||||
}
|
}
|
||||||
@@ -9,10 +9,10 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_VULKAN_GLOBAL_H
|
#ifndef VULKAN_GLOBAL_H
|
||||||
#define RSE_VULKAN_GLOBAL_H
|
#define VULKAN_GLOBAL_H
|
||||||
|
|
||||||
#include "rse_math.h"
|
#include "math.h"
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
@@ -21,12 +21,11 @@
|
|||||||
|
|
||||||
#define SWAP_BUFFER_COUNT 2U
|
#define SWAP_BUFFER_COUNT 2U
|
||||||
|
|
||||||
extern struct rse_vulkan_state_t g_vulkan_state;
|
|
||||||
/**
|
/**
|
||||||
* @brief Represents single vertex on the screen
|
* @brief Represents single vertex on the screen
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct rse_vertex_t
|
struct vertex_t
|
||||||
{
|
{
|
||||||
struct vec3_t pos;
|
struct vec3_t pos;
|
||||||
struct vec3_t color;
|
struct vec3_t color;
|
||||||
@@ -37,7 +36,7 @@ struct rse_vertex_t
|
|||||||
* @brief Wrapper for Vulkan buffer. Holds allocation data;
|
* @brief Wrapper for Vulkan buffer. Holds allocation data;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct rse_vulkan_buffer_t
|
struct vulkan_buffer_t
|
||||||
{
|
{
|
||||||
size_t allocated_size;
|
size_t allocated_size;
|
||||||
VkBuffer buffer;
|
VkBuffer buffer;
|
||||||
@@ -45,46 +44,22 @@ struct rse_vulkan_buffer_t
|
|||||||
VmaAllocationInfo allocation_info;
|
VmaAllocationInfo allocation_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rse_uniform_buffer_object_t
|
struct uniform_buffer_object_t
|
||||||
{
|
{
|
||||||
alignas(16) struct mat4_t model;
|
alignas(16) struct mat4_t model;
|
||||||
alignas(16) struct mat4_t view;
|
alignas(16) struct mat4_t view;
|
||||||
alignas(16) struct mat4_t proj;
|
alignas(16) struct mat4_t proj;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rse_vulkan_state_t
|
struct instance_data_t {
|
||||||
{
|
|
||||||
VkDevice device;
|
|
||||||
VkSurfaceKHR surface;
|
|
||||||
VkQueue graphics_queue;
|
|
||||||
VmaAllocator allocator;
|
|
||||||
VkPhysicalDevice physical_device;
|
|
||||||
uint32_t current_frame;
|
|
||||||
uint32_t queue_family_indices[1];
|
|
||||||
struct rse_vulkan_buffer_t uniform_buffers[SWAP_BUFFER_COUNT];
|
|
||||||
VkCommandBuffer command_buffers[SWAP_BUFFER_COUNT];
|
|
||||||
VkDescriptorSet descriptor_sets[SWAP_BUFFER_COUNT];
|
|
||||||
VkDescriptorSet descriptor_sets_bindless;
|
|
||||||
VkImageView* swapchain_image_views;
|
|
||||||
VkExtent2D swapchain_extent;
|
|
||||||
VkRenderPass render_pass;
|
|
||||||
VkDescriptorSetLayout descriptor_set_layout;
|
|
||||||
VkDescriptorSetLayout descriptor_set_layout_bindless;
|
|
||||||
VkFramebuffer* swapchain_framebuffers;
|
|
||||||
VkPipeline graphics_pipeline;
|
|
||||||
VkPipelineLayout pipeline_layout;
|
|
||||||
VkSwapchainKHR swapchain;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rse_instance_data_t {
|
|
||||||
struct vec3_t pos;
|
struct vec3_t pos;
|
||||||
struct vec3_t rot;
|
struct vec3_t rot;
|
||||||
float scale;
|
float scale;
|
||||||
uint8_t texture_id;
|
uint8_t texture_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
void rse_init_time();
|
void init_time();
|
||||||
void rse_update_time();
|
void update_time();
|
||||||
float rse_get_time_diff();
|
float get_time_diff();
|
||||||
|
|
||||||
#endif /* RSE_VULKAN_GLOBAL_H */
|
#endif /* VULKAN_GLOBAL_H */
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
#include "vulkan_descriptors.h"
|
#include "vulkan_descriptors.h"
|
||||||
|
|
||||||
#include "locale_vulkan.h"
|
#include "utilities/errors_common.h"
|
||||||
|
#include "utilities/localization.h"
|
||||||
#include "utilities/logger.h"
|
#include "utilities/logger.h"
|
||||||
#include "utilities/rse_errors_common.h"
|
|
||||||
#include "vulkan_errors.h"
|
|
||||||
#include "vulkan_commons.h"
|
#include "vulkan_commons.h"
|
||||||
#include "rse_vulkan_image.h"
|
#include "vulkan_errors.h"
|
||||||
|
#include "vulkan_image.h"
|
||||||
VkDescriptorPool gDescriptorPool;
|
|
||||||
VkDescriptorPool gDescriptorPool_bindless;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a Descriptor Pool
|
* @brief Create a Descriptor Pool
|
||||||
@@ -16,7 +13,7 @@ VkDescriptorPool gDescriptorPool_bindless;
|
|||||||
* @return rse_err_t RSE_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
|
* VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED
|
||||||
*/
|
*/
|
||||||
static rse_err_t create_descriptor_pool()
|
static rse_err_t create_descriptor_pool(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
VkDescriptorPoolSize pool_sizes[2] = {};
|
VkDescriptorPoolSize pool_sizes[2] = {};
|
||||||
VkDescriptorPoolCreateInfo pool_info = {};
|
VkDescriptorPoolCreateInfo pool_info = {};
|
||||||
@@ -32,8 +29,9 @@ static rse_err_t create_descriptor_pool()
|
|||||||
pool_info.pPoolSizes = &pool_sizes[0];
|
pool_info.pPoolSizes = &pool_sizes[0];
|
||||||
|
|
||||||
pool_info.maxSets = (uint32_t)(SWAP_BUFFER_COUNT);
|
pool_info.maxSets = (uint32_t)(SWAP_BUFFER_COUNT);
|
||||||
if (vkCreateDescriptorPool(g_vulkan_state.device, &pool_info, NULL, &gDescriptorPool) != VK_SUCCESS) {
|
if (vkCreateDescriptorPool(context->device, &pool_info, NULL,
|
||||||
LOGF(vulkan_messages[VULKAN_DESCRIPTOR_POOL_CREATION_FAILED]);
|
&context->descriptor_pool) != VK_SUCCESS) {
|
||||||
|
LOGF(_("Failed to create descriptor pool\n"));
|
||||||
return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED;
|
return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,8 +39,10 @@ static rse_err_t create_descriptor_pool()
|
|||||||
pool_info.maxSets = MAX_BINDLESS_RESOURCES * 2;
|
pool_info.maxSets = MAX_BINDLESS_RESOURCES * 2;
|
||||||
pool_info.pPoolSizes = &pool_sizes[1];
|
pool_info.pPoolSizes = &pool_sizes[1];
|
||||||
|
|
||||||
if (vkCreateDescriptorPool(g_vulkan_state.device, &pool_info, NULL, &gDescriptorPool_bindless) != VK_SUCCESS) {
|
if (vkCreateDescriptorPool(context->device, &pool_info, NULL,
|
||||||
LOGF(vulkan_messages[VULKAN_DESCRIPTOR_POOL_CREATION_FAILED]);
|
&context->descriptor_pool_bindless) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
|
LOGF(_("Failed to create descriptor pool\n"));
|
||||||
return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED;
|
return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,43 +54,44 @@ static rse_err_t create_descriptor_pool()
|
|||||||
*
|
*
|
||||||
* @return rse_err_t RSE_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 */
|
* VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED */
|
||||||
static rse_err_t create_descriptor_sets()
|
static rse_err_t create_descriptor_sets(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
uint32_t max_binding = MAX_BINDLESS_RESOURCES - 1;
|
uint32_t max_binding = MAX_BINDLESS_RESOURCES - 1;
|
||||||
VkDescriptorSetLayout layouts[SWAP_BUFFER_COUNT] = {
|
VkDescriptorSetLayout layouts[SWAP_BUFFER_COUNT] = {
|
||||||
g_vulkan_state.descriptor_set_layout,
|
context->descriptor_set_layout, context->descriptor_set_layout};
|
||||||
g_vulkan_state.descriptor_set_layout
|
|
||||||
};
|
|
||||||
VkDescriptorSetLayout layouts_bindless[SWAP_BUFFER_COUNT] = {
|
VkDescriptorSetLayout layouts_bindless[SWAP_BUFFER_COUNT] = {
|
||||||
g_vulkan_state.descriptor_set_layout_bindless,
|
context->descriptor_set_layout_bindless,
|
||||||
g_vulkan_state.descriptor_set_layout_bindless
|
context->descriptor_set_layout_bindless};
|
||||||
};
|
|
||||||
VkDescriptorSetAllocateInfo allocInfo = {};
|
VkDescriptorSetAllocateInfo allocInfo = {};
|
||||||
VkDescriptorSetAllocateInfo allocInfo_bindless = {};
|
VkDescriptorSetAllocateInfo allocInfo_bindless = {};
|
||||||
VkDescriptorSetVariableDescriptorCountAllocateInfoEXT count_info = {};
|
VkDescriptorSetVariableDescriptorCountAllocateInfoEXT count_info = {};
|
||||||
|
|
||||||
count_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT;
|
count_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT;
|
||||||
count_info.descriptorSetCount = 1;
|
count_info.descriptorSetCount = 1;
|
||||||
count_info.pDescriptorCounts = &max_binding;
|
count_info.pDescriptorCounts = &max_binding;
|
||||||
|
|
||||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
allocInfo.descriptorPool = gDescriptorPool;
|
allocInfo.descriptorPool = context->descriptor_pool;
|
||||||
allocInfo.descriptorSetCount = (uint32_t)(SWAP_BUFFER_COUNT);
|
allocInfo.descriptorSetCount = (uint32_t)(SWAP_BUFFER_COUNT);
|
||||||
allocInfo.pSetLayouts = layouts;
|
allocInfo.pSetLayouts = layouts;
|
||||||
|
|
||||||
allocInfo_bindless = allocInfo;
|
allocInfo_bindless = allocInfo;
|
||||||
allocInfo_bindless.descriptorPool = gDescriptorPool_bindless;
|
allocInfo_bindless.descriptorPool = context->descriptor_pool_bindless;
|
||||||
allocInfo_bindless.pSetLayouts = layouts_bindless;
|
allocInfo_bindless.pSetLayouts = layouts_bindless;
|
||||||
allocInfo_bindless.pNext = &count_info;
|
allocInfo_bindless.pNext = &count_info;
|
||||||
allocInfo_bindless.descriptorSetCount = 1;
|
allocInfo_bindless.descriptorSetCount = 1;
|
||||||
|
|
||||||
if (vkAllocateDescriptorSets(g_vulkan_state.device, &allocInfo, g_vulkan_state.descriptor_sets) != VK_SUCCESS) {
|
if (vkAllocateDescriptorSets(context->device, &allocInfo,
|
||||||
LOGF(vulkan_messages[VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED]);
|
context->descriptor_sets) != VK_SUCCESS) {
|
||||||
|
LOGF(_("Failed to allocate descriptor sets\n"));
|
||||||
return VULKAN_ERROR_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) {
|
if (vkAllocateDescriptorSets(context->device, &allocInfo_bindless,
|
||||||
LOGF(vulkan_messages[VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED]);
|
&context->descriptor_sets_bindless) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
|
LOGF(_("Failed to allocate descriptor sets\n"));
|
||||||
return VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED;
|
return VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,21 +102,24 @@ static rse_err_t create_descriptor_sets()
|
|||||||
size_t image_iterator = 0U;
|
size_t image_iterator = 0U;
|
||||||
size_t image_info_iterator = 0U;
|
size_t image_info_iterator = 0U;
|
||||||
|
|
||||||
buffer_info.buffer = g_vulkan_state.uniform_buffers[i].buffer;
|
buffer_info.buffer = context->uniform_buffers[i].buffer;
|
||||||
buffer_info.offset = 0;
|
buffer_info.offset = 0;
|
||||||
buffer_info.range = sizeof(struct rse_uniform_buffer_object_t);
|
buffer_info.range = sizeof(struct uniform_buffer_object_t);
|
||||||
|
|
||||||
for (image_iterator = 0U; image_iterator < RSE_MAX_IMAGE_COUNT; ++image_iterator) {
|
for (image_iterator = 0U; image_iterator < RSE_MAX_IMAGE_COUNT;
|
||||||
if (image_exists(image_iterator)) {
|
++image_iterator) {
|
||||||
image_infos[image_info_iterator].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
if (image_exists(context, image_iterator)) {
|
||||||
image_infos[image_info_iterator].imageView = rse_get_image_view(image_iterator);
|
image_infos[image_info_iterator].imageLayout =
|
||||||
image_infos[image_info_iterator].sampler = rse_get_texture_sampler();
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
image_infos[image_info_iterator].imageView =
|
||||||
|
context->swapchain_image_views[image_iterator];
|
||||||
|
image_infos[image_info_iterator].sampler = context->sampler;
|
||||||
image_info_iterator++;
|
image_info_iterator++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
descriptor_writes[0].dstSet = g_vulkan_state.descriptor_sets[i];
|
descriptor_writes[0].dstSet = context->descriptor_sets[i];
|
||||||
descriptor_writes[0].dstBinding = 0;
|
descriptor_writes[0].dstBinding = 0;
|
||||||
descriptor_writes[0].dstArrayElement = 0;
|
descriptor_writes[0].dstArrayElement = 0;
|
||||||
descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
@@ -123,33 +127,37 @@ static rse_err_t create_descriptor_sets()
|
|||||||
descriptor_writes[0].pBufferInfo = &buffer_info;
|
descriptor_writes[0].pBufferInfo = &buffer_info;
|
||||||
|
|
||||||
descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
descriptor_writes[1].dstSet = g_vulkan_state.descriptor_sets_bindless;
|
descriptor_writes[1].dstSet = context->descriptor_sets_bindless;
|
||||||
descriptor_writes[1].dstBinding = 1;
|
descriptor_writes[1].dstBinding = 1;
|
||||||
descriptor_writes[1].dstArrayElement = 0;
|
descriptor_writes[1].dstArrayElement = 0;
|
||||||
descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
descriptor_writes[1].descriptorType =
|
||||||
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
descriptor_writes[1].descriptorCount = image_info_iterator;
|
descriptor_writes[1].descriptorCount = image_info_iterator;
|
||||||
descriptor_writes[1].pImageInfo = image_infos;
|
descriptor_writes[1].pImageInfo = image_infos;
|
||||||
|
|
||||||
vkUpdateDescriptorSets(g_vulkan_state.device, 2, descriptor_writes, 0, NULL);
|
vkUpdateDescriptorSets(context->device, 2, descriptor_writes, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t create_descriptors()
|
rse_err_t create_descriptors(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
|
||||||
STATUS_CHECK(create_descriptor_pool());
|
STATUS_CHECK(create_descriptor_pool(context));
|
||||||
STATUS_CHECK(create_descriptor_sets());
|
STATUS_CHECK(create_descriptor_sets(context));
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_descriptors()
|
void destroy_descriptors(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
vkDestroyDescriptorPool(g_vulkan_state.device, gDescriptorPool, NULL);
|
vkDestroyDescriptorPool(context->device, context->descriptor_pool, NULL);
|
||||||
vkDestroyDescriptorPool(g_vulkan_state.device, gDescriptorPool_bindless, NULL);
|
vkDestroyDescriptorPool(context->device, context->descriptor_pool_bindless,
|
||||||
vkDestroyDescriptorSetLayout(g_vulkan_state.device, g_vulkan_state.descriptor_set_layout, NULL);
|
NULL);
|
||||||
vkDestroyDescriptorSetLayout(g_vulkan_state.device, g_vulkan_state.descriptor_set_layout_bindless, NULL);
|
vkDestroyDescriptorSetLayout(context->device,
|
||||||
|
context->descriptor_set_layout, NULL);
|
||||||
|
vkDestroyDescriptorSetLayout(context->device,
|
||||||
|
context->descriptor_set_layout_bindless, NULL);
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
#ifndef RSE_VULKAN_DESCRIPTORS_H
|
#ifndef VULKAN_DESCRIPTORS_H
|
||||||
#define RSE_VULKAN_DESCRIPTORS_H
|
#define VULKAN_DESCRIPTORS_H
|
||||||
|
|
||||||
#include "utilities/rse_commons.h"
|
#include "utilities/commons.h"
|
||||||
|
#include "graphics_context.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAX_BINDLESS_RESOURCES 16536
|
#define MAX_BINDLESS_RESOURCES 16536
|
||||||
@@ -9,15 +10,17 @@
|
|||||||
/**
|
/**
|
||||||
* @brief Create descriptors
|
* @brief Create descriptors
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
* @param vulkan_state
|
* @param vulkan_state
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||||
*/
|
*/
|
||||||
rse_err_t create_descriptors();
|
rse_err_t create_descriptors(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Destroy all descriptors
|
* @brief Destroy all descriptors
|
||||||
*
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
*/
|
*/
|
||||||
void destroy_descriptors();
|
void destroy_descriptors(struct graphics_context_t* context);
|
||||||
|
|
||||||
#endif /* RSE_VULKAN_DESCRIPTORS_H */
|
#endif /* VULKAN_DESCRIPTORS_H */
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#define RSE_VULKAN_MODULE_ID 0x0300U
|
#define RSE_VULKAN_MODULE_ID 0x0300U
|
||||||
|
|
||||||
enum rse_vulkan_error_t
|
enum vulkan_error_t
|
||||||
{
|
{
|
||||||
VULKAN_ERROR_DEBUG_MESSENGER_CREATION_FAILED = RSE_VULKAN_MODULE_ID,
|
VULKAN_ERROR_DEBUG_MESSENGER_CREATION_FAILED = RSE_VULKAN_MODULE_ID,
|
||||||
VULKAN_ERROR_LAYER_NOT_SUPPORTED,
|
VULKAN_ERROR_LAYER_NOT_SUPPORTED,
|
||||||
@@ -30,6 +30,8 @@ enum rse_vulkan_error_t
|
|||||||
VULKAN_ERROR_FORMAT_NOT_FOUND,
|
VULKAN_ERROR_FORMAT_NOT_FOUND,
|
||||||
VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED,
|
VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED,
|
||||||
VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED,
|
VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED,
|
||||||
|
VULKAN_ERROR_DESCRIPTORSETLAYOUT_NO_BINDINGS,
|
||||||
|
VULKAN_ERROR_DESCRIPTORSETLAYOUT_TOO_MANY,
|
||||||
VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED,
|
VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED,
|
||||||
VULKAN_ERROR_FRAMEBUFFERS_CREATION_FAILED,
|
VULKAN_ERROR_FRAMEBUFFERS_CREATION_FAILED,
|
||||||
VULKAN_ERROR_RECORD_COMMAND_BEGIN_FAILED,
|
VULKAN_ERROR_RECORD_COMMAND_BEGIN_FAILED,
|
||||||
@@ -41,7 +43,19 @@ enum rse_vulkan_error_t
|
|||||||
VULKAN_ERROR_IMAGE_VIEW_NOT_CREATED,
|
VULKAN_ERROR_IMAGE_VIEW_NOT_CREATED,
|
||||||
VULKAN_ERROR_MAX_TEXTURE_COUNT_REACHED,
|
VULKAN_ERROR_MAX_TEXTURE_COUNT_REACHED,
|
||||||
VULKAN_ERROR_TRANSITION_IMAGE_LAYOUT_FAILED,
|
VULKAN_ERROR_TRANSITION_IMAGE_LAYOUT_FAILED,
|
||||||
|
VULKAN_ERROR_PIPELINE_TOO_MANY_SHADER_STAGES,
|
||||||
|
VULKAN_ERROR_PIPELINE_INVALID_SHADER_STAGE,
|
||||||
|
VULKAN_ERROR_PIPELINE_INVALID_VERTEX_INPUT_RATE,
|
||||||
|
VULKAN_ERROR_PIPELINE_INVALID_BINDING,
|
||||||
|
VULKAN_ERROR_PIPELINE_INVALID_FORMAT,
|
||||||
|
VULKAN_ERROR_PIPELINE_INVALID_DYNAMIC_STATE,
|
||||||
|
VULKAN_ERROR_PIPELINE_MISSING_DYNAMIC_STATE,
|
||||||
|
VULKAN_ERROR_PIPELINE_MISSING_SHADER_STAGES,
|
||||||
|
VULKAN_ERROR_PIPELINE_MISSING_VERTEX_BINDINGS,
|
||||||
|
VULKAN_ERROR_PIPELINE_MISSING_SHADER_ATTRIBUTES,
|
||||||
|
VULKAN_ERROR_PIPELINE_MISSING_SHADER_MODULES,
|
||||||
VULKAN_ERROR_DRAW_FAILED,
|
VULKAN_ERROR_DRAW_FAILED,
|
||||||
|
VULKAN_ERROR_PIPELINE_ALREADY_INITIALIZED,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,54 +1,36 @@
|
|||||||
#include "rse_vulkan_image.h"
|
#include "vulkan_image.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "src/vulkan_pipeline.h"
|
#include "src/vulkan_pipeline.h"
|
||||||
|
#include "utilities/commons.h"
|
||||||
|
#include "utilities/errors_common.h"
|
||||||
#include "utilities/file_utils.h"
|
#include "utilities/file_utils.h"
|
||||||
|
#include "utilities/localization.h"
|
||||||
#include "utilities/logger.h"
|
#include "utilities/logger.h"
|
||||||
#include "utilities/rse_commons.h"
|
|
||||||
#include "utilities/rse_errors_common.h"
|
|
||||||
#include "locale_vulkan.h"
|
|
||||||
#include "vk_mem_alloc.h"
|
|
||||||
#include "vulkan/vulkan_core.h"
|
#include "vulkan/vulkan_core.h"
|
||||||
#include "vulkan_errors.h"
|
|
||||||
#include "rse_vulkan_commands.h"
|
|
||||||
#include "vulkan_buffers.h"
|
#include "vulkan_buffers.h"
|
||||||
|
#include "vulkan_commands.h"
|
||||||
|
#include "vulkan_errors.h"
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "stb_image.h"
|
|
||||||
#include "vma/vk_mem_alloc.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "stb_image.h"
|
||||||
|
#include "vma/vk_mem_alloc.h"
|
||||||
|
|
||||||
#define IMAGE_TAKEN 1U
|
#define IMAGE_TAKEN 1U
|
||||||
#define IMAGE_FREE 0U
|
#define IMAGE_FREE 0U
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Wrapper for Vulkan buffer. Holds allocation data;
|
* @brief Create a sampler object for texture sampling
|
||||||
*
|
*
|
||||||
|
* @param[in/out] context Graphics context to create sampler in
|
||||||
|
* @return RSE_ERROR_NO_ERROR on success, error code otherwise
|
||||||
*/
|
*/
|
||||||
struct rse_vulkan_image_t
|
static rse_err_t create_sampler(struct graphics_context_t* context)
|
||||||
{
|
|
||||||
uint8_t id_taken;
|
|
||||||
size_t allocated_size;
|
|
||||||
VkImage image;
|
|
||||||
VkImageView image_view;
|
|
||||||
VmaAllocation allocation;
|
|
||||||
VmaAllocationInfo allocation_info;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* For now we will only have one image view per image */
|
|
||||||
extern struct rse_vulkan_state_t g_vulkan_state;
|
|
||||||
|
|
||||||
struct rse_vulkan_image_t g_texture_images[RSE_MAX_IMAGE_COUNT];
|
|
||||||
|
|
||||||
struct rse_vulkan_image_t g_depth_image;
|
|
||||||
struct rse_vulkan_image_t g_color_image;
|
|
||||||
VkSampler g_sampler;
|
|
||||||
|
|
||||||
|
|
||||||
static rse_err_t create_sampler()
|
|
||||||
{
|
{
|
||||||
VkSamplerCreateInfo create_info = {0};
|
VkSamplerCreateInfo create_info = {0};
|
||||||
|
|
||||||
@@ -62,7 +44,7 @@ static rse_err_t create_sampler()
|
|||||||
create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
create_info.mipLodBias = 0.0f;
|
create_info.mipLodBias = 0.0f;
|
||||||
create_info.anisotropyEnable = VK_FALSE; // TODO: Enable this
|
create_info.anisotropyEnable = VK_FALSE; // TODO: Enable this
|
||||||
create_info.maxAnisotropy = 1.0f;
|
create_info.maxAnisotropy = 1.0f;
|
||||||
create_info.compareEnable = VK_FALSE;
|
create_info.compareEnable = VK_FALSE;
|
||||||
create_info.compareOp = VK_COMPARE_OP_ALWAYS;
|
create_info.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
@@ -71,10 +53,8 @@ static rse_err_t create_sampler()
|
|||||||
create_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
create_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||||
create_info.unnormalizedCoordinates = VK_FALSE;
|
create_info.unnormalizedCoordinates = VK_FALSE;
|
||||||
|
|
||||||
if (VK_SUCCESS != vkCreateSampler(g_vulkan_state.device,
|
if (VK_SUCCESS != vkCreateSampler(context->device, &create_info, NULL,
|
||||||
&create_info,
|
&context->sampler)) {
|
||||||
NULL,
|
|
||||||
&g_sampler)) {
|
|
||||||
LOGF("Failed to create image view");
|
LOGF("Failed to create image view");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -82,35 +62,38 @@ static rse_err_t create_sampler()
|
|||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rse_err_t find_supported_format(const VkFormat* candidates,
|
static rse_err_t find_supported_format(struct graphics_context_t* context,
|
||||||
size_t candidates_count,
|
const VkFormat* candidates,
|
||||||
VkImageTiling tiling,
|
size_t candidates_count,
|
||||||
VkFormatFeatureFlags features,
|
VkImageTiling tiling,
|
||||||
VkFormat* found_format)
|
VkFormatFeatureFlags features,
|
||||||
|
VkFormat* found_format)
|
||||||
{
|
{
|
||||||
size_t i = 0U;
|
size_t i = 0U;
|
||||||
|
|
||||||
for (i = 0U; i < candidates_count; ++i) {
|
for (i = 0U; i < candidates_count; ++i) {
|
||||||
VkFormatProperties props;
|
VkFormatProperties props;
|
||||||
vkGetPhysicalDeviceFormatProperties(g_vulkan_state.physical_device, candidates[i], &props);
|
vkGetPhysicalDeviceFormatProperties(context->physical_device,
|
||||||
|
candidates[i], &props);
|
||||||
|
|
||||||
if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) {
|
if (tiling == VK_IMAGE_TILING_LINEAR &&
|
||||||
|
(props.linearTilingFeatures & features) == features) {
|
||||||
*found_format = candidates[i];
|
*found_format = candidates[i];
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
} else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) {
|
} else if (tiling == VK_IMAGE_TILING_OPTIMAL &&
|
||||||
|
(props.optimalTilingFeatures & features) == features) {
|
||||||
*found_format = candidates[i];
|
*found_format = candidates[i];
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGE(vulkan_messages[VULKAN_FORMAT_NOT_FOUND]);
|
LOGE(_("Failed to find correct format\n"));
|
||||||
return VULKAN_ERROR_FORMAT_NOT_FOUND;
|
return VULKAN_ERROR_FORMAT_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rse_err_t create_image(struct rse_vulkan_image_t* image,
|
static rse_err_t create_image(struct graphics_context_t* context,
|
||||||
uint32_t width,
|
struct vulkan_image_t* image, uint32_t width,
|
||||||
uint32_t height,
|
uint32_t height, VkFormat format,
|
||||||
VkFormat format,
|
|
||||||
VkSampleCountFlagBits maa_samples,
|
VkSampleCountFlagBits maa_samples,
|
||||||
VkImageUsageFlags usage,
|
VkImageUsageFlags usage,
|
||||||
VmaAllocationCreateFlags allocationFlags)
|
VmaAllocationCreateFlags allocationFlags)
|
||||||
@@ -134,7 +117,9 @@ static rse_err_t create_image(struct rse_vulkan_image_t* image,
|
|||||||
image_info.samples = maa_samples;
|
image_info.samples = maa_samples;
|
||||||
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
image_info.usage = usage;
|
image_info.usage = usage;
|
||||||
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; //TODO: Change if used by more than one queue family
|
image_info.sharingMode =
|
||||||
|
VK_SHARING_MODE_EXCLUSIVE; // TODO: Change if used by more than one
|
||||||
|
// queue family
|
||||||
image_info.queueFamilyIndexCount = 0U;
|
image_info.queueFamilyIndexCount = 0U;
|
||||||
image_info.pQueueFamilyIndices = NULL;
|
image_info.pQueueFamilyIndices = NULL;
|
||||||
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
@@ -148,20 +133,21 @@ static rse_err_t create_image(struct rse_vulkan_image_t* image,
|
|||||||
alloc_create_info.pUserData = NULL;
|
alloc_create_info.pUserData = NULL;
|
||||||
alloc_create_info.priority = 1.0f;
|
alloc_create_info.priority = 1.0f;
|
||||||
|
|
||||||
if (VK_SUCCESS != vmaCreateImage(g_vulkan_state.allocator,
|
if (VK_SUCCESS != vmaCreateImage(context->allocator, &image_info,
|
||||||
&image_info,
|
&alloc_create_info, &image->image,
|
||||||
&alloc_create_info,
|
|
||||||
&image->image,
|
|
||||||
&image->allocation,
|
&image->allocation,
|
||||||
&image->allocation_info)) {
|
&image->allocation_info)) {
|
||||||
LOGF(vulkan_messages[VULKAN_IMAGE_NOT_CREATED]);
|
LOGF(_("Failed to create image\n"));
|
||||||
return VULKAN_ERROR_IMAGE_NOT_CREATED;
|
return VULKAN_ERROR_IMAGE_NOT_CREATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rse_err_t create_image_view(struct rse_vulkan_image_t* image, VkFormat format, VkImageAspectFlags aspectFlags)
|
static rse_err_t create_image_view(struct graphics_context_t* context,
|
||||||
|
struct vulkan_image_t* image,
|
||||||
|
VkFormat format,
|
||||||
|
VkImageAspectFlags aspectFlags)
|
||||||
{
|
{
|
||||||
VkImageViewCreateInfo image_view_create_info = {0};
|
VkImageViewCreateInfo image_view_create_info = {0};
|
||||||
|
|
||||||
@@ -181,88 +167,97 @@ static rse_err_t create_image_view(struct rse_vulkan_image_t* image, VkFormat fo
|
|||||||
image_view_create_info.subresourceRange.baseArrayLayer = 0U;
|
image_view_create_info.subresourceRange.baseArrayLayer = 0U;
|
||||||
image_view_create_info.subresourceRange.layerCount = 1U;
|
image_view_create_info.subresourceRange.layerCount = 1U;
|
||||||
|
|
||||||
if (VK_SUCCESS != vkCreateImageView(g_vulkan_state.device,
|
if (VK_SUCCESS != vkCreateImageView(context->device,
|
||||||
&image_view_create_info,
|
&image_view_create_info, NULL,
|
||||||
NULL,
|
|
||||||
&image->image_view)) {
|
&image->image_view)) {
|
||||||
LOGF(vulkan_messages[VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED]);
|
LOGF(_("Failed to create swapchain image view\n"));
|
||||||
return VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED;
|
return VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t rse_create_color_resource()
|
rse_err_t create_color_resource(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
VkFormat color_format = IMAGE_FORMAT;
|
VkFormat color_format = IMAGE_FORMAT;
|
||||||
VkSurfaceCapabilitiesKHR physical_device_surface_capabilities;
|
VkSurfaceCapabilitiesKHR physical_device_surface_capabilities;
|
||||||
|
|
||||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_vulkan_state.physical_device,
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
||||||
g_vulkan_state.surface,
|
context->physical_device, context->surface,
|
||||||
&physical_device_surface_capabilities);
|
&physical_device_surface_capabilities);
|
||||||
|
|
||||||
STATUS_CHECK(create_image(&g_color_image,
|
STATUS_CHECK(
|
||||||
physical_device_surface_capabilities.currentExtent.width,
|
create_image(context, &context->color_image,
|
||||||
physical_device_surface_capabilities.currentExtent.height,
|
physical_device_surface_capabilities.currentExtent.width,
|
||||||
color_format,
|
physical_device_surface_capabilities.currentExtent.height,
|
||||||
VK_SAMPLE_COUNT_16_BIT,
|
color_format, VK_SAMPLE_COUNT_16_BIT,
|
||||||
VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0U));
|
VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
|
||||||
STATUS_CHECK(create_image_view(&g_color_image, color_format, VK_IMAGE_ASPECT_COLOR_BIT));
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||||
|
0U));
|
||||||
|
STATUS_CHECK(create_image_view(context, &context->color_image, color_format,
|
||||||
|
VK_IMAGE_ASPECT_COLOR_BIT));
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rse_err_t create_depth_resources(struct graphics_context_t* context)
|
||||||
rse_err_t rse_create_depth_resources()
|
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
VkFormat depth_format = {0};
|
VkFormat depth_format = {0};
|
||||||
VkSurfaceCapabilitiesKHR physical_device_surface_capabilities;
|
VkSurfaceCapabilitiesKHR physical_device_surface_capabilities;
|
||||||
|
|
||||||
|
STATUS_CHECK(find_depth_format(context, &depth_format));
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
||||||
|
context->physical_device, context->surface,
|
||||||
|
&physical_device_surface_capabilities);
|
||||||
|
|
||||||
STATUS_CHECK(find_depth_format(&depth_format));
|
STATUS_CHECK(
|
||||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_vulkan_state.physical_device,
|
create_image(context, &context->depth_image,
|
||||||
g_vulkan_state.surface,
|
physical_device_surface_capabilities.currentExtent.width,
|
||||||
&physical_device_surface_capabilities);
|
physical_device_surface_capabilities.currentExtent.height,
|
||||||
|
depth_format, VK_SAMPLE_COUNT_16_BIT,
|
||||||
STATUS_CHECK(create_image(&g_depth_image,
|
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0U));
|
||||||
physical_device_surface_capabilities.currentExtent.width,
|
STATUS_CHECK(create_image_view(context, &context->depth_image, depth_format,
|
||||||
physical_device_surface_capabilities.currentExtent.height,
|
VK_IMAGE_ASPECT_DEPTH_BIT));
|
||||||
depth_format,
|
|
||||||
VK_SAMPLE_COUNT_16_BIT,
|
|
||||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
|
||||||
0U));
|
|
||||||
STATUS_CHECK(create_image_view(&g_depth_image, depth_format, VK_IMAGE_ASPECT_DEPTH_BIT));
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Translate vulkan format to pixel width
|
||||||
|
*
|
||||||
|
* @param[int] format Format to translate
|
||||||
|
* @param[out] format_size Format size in bytes to return
|
||||||
|
* @return RSE_ERROR_NO_ERROR on success, error code otherwise
|
||||||
|
*/
|
||||||
static rse_err_t format_to_pixel_size(VkFormat format,
|
static rse_err_t format_to_pixel_size(VkFormat format,
|
||||||
VkDeviceSize* format_size)
|
VkDeviceSize* format_size)
|
||||||
{
|
{
|
||||||
switch (format)
|
switch (format) {
|
||||||
{
|
case VK_FORMAT_R8_SRGB:
|
||||||
case VK_FORMAT_R8_SRGB:
|
case VK_FORMAT_R8_SNORM:
|
||||||
case VK_FORMAT_R8_SNORM:
|
case VK_FORMAT_R8_UNORM:
|
||||||
case VK_FORMAT_R8_UNORM:
|
case VK_FORMAT_R8_USCALED:
|
||||||
case VK_FORMAT_R8_USCALED:
|
case VK_FORMAT_R8_SSCALED:
|
||||||
case VK_FORMAT_R8_SSCALED:
|
case VK_FORMAT_R8_UINT:
|
||||||
case VK_FORMAT_R8_UINT:
|
*format_size = 1;
|
||||||
*format_size = 1;
|
break;
|
||||||
break;
|
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
*format_size = 4;
|
||||||
*format_size = 4;
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOGE("Failed translate vulkan format to pixel width");
|
LOGE("Failed translate vulkan format to pixel width");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rse_err_t transition_image_layout(struct rse_vulkan_image_t* image, VkImageLayout old_layout, VkImageLayout new_layout)
|
static rse_err_t transition_image_layout(struct graphics_context_t* context,
|
||||||
|
struct vulkan_image_t* image,
|
||||||
|
VkImageLayout old_layout,
|
||||||
|
VkImageLayout new_layout)
|
||||||
{
|
{
|
||||||
VkImageSubresourceRange range = {0};
|
VkImageSubresourceRange range = {0};
|
||||||
VkImageMemoryBarrier image_barrier = {0};
|
VkImageMemoryBarrier image_barrier = {0};
|
||||||
@@ -270,7 +265,8 @@ static rse_err_t transition_image_layout(struct rse_vulkan_image_t* image, VkIma
|
|||||||
VkPipelineStageFlags source_stage = {0};
|
VkPipelineStageFlags source_stage = {0};
|
||||||
VkPipelineStageFlags destination_stage = {0};
|
VkPipelineStageFlags destination_stage = {0};
|
||||||
|
|
||||||
/* Put image into correct layout to copy pixels from buffer to image memory */
|
/* Put image into correct layout to copy pixels from buffer to image memory
|
||||||
|
*/
|
||||||
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
range.baseMipLevel = 0;
|
range.baseMipLevel = 0;
|
||||||
range.levelCount = 1;
|
range.levelCount = 1;
|
||||||
@@ -286,13 +282,15 @@ static rse_err_t transition_image_layout(struct rse_vulkan_image_t* image, VkIma
|
|||||||
image_barrier.image = image->image;
|
image_barrier.image = image->image;
|
||||||
image_barrier.subresourceRange = range;
|
image_barrier.subresourceRange = range;
|
||||||
|
|
||||||
if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
|
||||||
|
new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||||
image_barrier.srcAccessMask = 0;
|
image_barrier.srcAccessMask = 0;
|
||||||
image_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
image_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
|
||||||
source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
destination_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
destination_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
} else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
} else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
|
||||||
|
new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||||
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
image_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
image_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
|
||||||
@@ -302,36 +300,27 @@ static rse_err_t transition_image_layout(struct rse_vulkan_image_t* image, VkIma
|
|||||||
return VULKAN_ERROR_TRANSITION_IMAGE_LAYOUT_FAILED;
|
return VULKAN_ERROR_TRANSITION_IMAGE_LAYOUT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
command_buffer = rse_begin_single_time_command();
|
command_buffer = begin_single_time_command(context);
|
||||||
vkCmdPipelineBarrier(command_buffer,
|
vkCmdPipelineBarrier(command_buffer, source_stage, destination_stage, 0, 0,
|
||||||
source_stage,
|
NULL, 0, NULL, 1, &image_barrier);
|
||||||
destination_stage,
|
end_single_time_comands(context, command_buffer);
|
||||||
0,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
1,
|
|
||||||
&image_barrier);
|
|
||||||
rse_end_single_time_comands(command_buffer);
|
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rse_err_t create_textured_image(struct graphics_context_t* context,
|
||||||
static rse_err_t create_textured_image(uint32_t width,
|
uint32_t width, uint32_t height,
|
||||||
uint32_t height,
|
VkFormat format,
|
||||||
VkFormat format,
|
const unsigned char* pixels,
|
||||||
const unsigned char* pixels,
|
uint16_t* texture_id)
|
||||||
uint16_t* texture_id)
|
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
struct rse_vulkan_buffer_t staging_buffer = {0};
|
struct vulkan_buffer_t staging_buffer = {0};
|
||||||
VkDeviceSize staging_buffer_size = 0U;
|
VkDeviceSize staging_buffer_size = 0U;
|
||||||
VkCommandBuffer command_buffer = {0};
|
VkCommandBuffer command_buffer = {0};
|
||||||
VkBufferImageCopy copy_region = {0};
|
VkBufferImageCopy copy_region = {0};
|
||||||
VkExtent3D image_extent = {0};
|
VkExtent3D image_extent = {0};
|
||||||
struct rse_vulkan_image_t* free_texture_image = NULL;
|
struct vulkan_image_t* free_texture_image = NULL;
|
||||||
|
|
||||||
image_extent.width = width;
|
image_extent.width = width;
|
||||||
image_extent.height = height;
|
image_extent.height = height;
|
||||||
@@ -339,9 +328,9 @@ static rse_err_t create_textured_image(uint32_t width,
|
|||||||
|
|
||||||
*texture_id = 0U;
|
*texture_id = 0U;
|
||||||
|
|
||||||
while(free_texture_image == NULL && *texture_id < RSE_MAX_IMAGE_COUNT) {
|
while (free_texture_image == NULL && *texture_id < RSE_MAX_IMAGE_COUNT) {
|
||||||
if(g_texture_images[*texture_id].id_taken == IMAGE_FREE) {
|
if (context->texture_images[*texture_id].id_taken == IMAGE_FREE) {
|
||||||
free_texture_image = &g_texture_images[*texture_id];
|
free_texture_image = &context->texture_images[*texture_id];
|
||||||
} else {
|
} else {
|
||||||
*texture_id += 1;
|
*texture_id += 1;
|
||||||
}
|
}
|
||||||
@@ -349,7 +338,7 @@ static rse_err_t create_textured_image(uint32_t width,
|
|||||||
|
|
||||||
/* Check if we found free image handle */
|
/* Check if we found free image handle */
|
||||||
if (free_texture_image == NULL) {
|
if (free_texture_image == NULL) {
|
||||||
LOGE(vulkan_messages[VULKAN_MAX_TEXTURE_COUNT_REACHED]);
|
LOGE(_("Failed to find free texture image handle\n"));
|
||||||
*texture_id = -1;
|
*texture_id = -1;
|
||||||
return VULKAN_ERROR_MAX_TEXTURE_COUNT_REACHED;
|
return VULKAN_ERROR_MAX_TEXTURE_COUNT_REACHED;
|
||||||
}
|
}
|
||||||
@@ -358,16 +347,14 @@ static rse_err_t create_textured_image(uint32_t width,
|
|||||||
|
|
||||||
staging_buffer_size = staging_buffer_size * width * height;
|
staging_buffer_size = staging_buffer_size * width * height;
|
||||||
|
|
||||||
STATUS_CHECK(create_image(free_texture_image,
|
STATUS_CHECK(create_image(
|
||||||
width,
|
context, free_texture_image, width, height, format,
|
||||||
height,
|
VK_SAMPLE_COUNT_1_BIT,
|
||||||
format,
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
VK_SAMPLE_COUNT_1_BIT,
|
VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT));
|
||||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
||||||
VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT));
|
|
||||||
|
|
||||||
// /* Put image into correct layout to copy pixels from buffer to image memory */
|
// /* Put image into correct layout to copy pixels from buffer to image
|
||||||
// range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
// memory */ range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
// range.baseMipLevel = 0;
|
// range.baseMipLevel = 0;
|
||||||
// range.levelCount = 1;
|
// range.levelCount = 1;
|
||||||
// range.baseArrayLayer = 0;
|
// range.baseArrayLayer = 0;
|
||||||
@@ -384,7 +371,7 @@ static rse_err_t create_textured_image(uint32_t width,
|
|||||||
// image_barrier.image = free_texture_image->image;
|
// image_barrier.image = free_texture_image->image;
|
||||||
// image_barrier.subresourceRange = range;
|
// image_barrier.subresourceRange = range;
|
||||||
//
|
//
|
||||||
// command_buffer = rse_begin_single_time_command();
|
// command_buffer = begin_single_time_command();
|
||||||
// vkCmdPipelineBarrier(command_buffer,
|
// vkCmdPipelineBarrier(command_buffer,
|
||||||
// VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
// VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
// VK_PIPELINE_STAGE_TRANSFER_BIT,
|
// VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
@@ -395,18 +382,21 @@ static rse_err_t create_textured_image(uint32_t width,
|
|||||||
// NULL,
|
// NULL,
|
||||||
// 1,
|
// 1,
|
||||||
// &image_barrier);
|
// &image_barrier);
|
||||||
// rse_end_single_time_comands(command_buffer);
|
// end_single_time_comands(command_buffer);
|
||||||
|
|
||||||
transition_image_layout(free_texture_image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
transition_image_layout(context, free_texture_image,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
/* Copy pixel data to GPU memory */
|
/* Copy pixel data to GPU memory */
|
||||||
STATUS_CHECK(create_buffer(staging_buffer_size,
|
STATUS_CHECK(create_buffer(
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
context, staging_buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
||||||
VMA_ALLOCATION_CREATE_MAPPED_BIT
|
VMA_ALLOCATION_CREATE_MAPPED_BIT |
|
||||||
| VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||||
&staging_buffer));
|
&staging_buffer));
|
||||||
|
|
||||||
memcpy(staging_buffer.allocation_info.pMappedData, pixels, staging_buffer_size);
|
memcpy(staging_buffer.allocation_info.pMappedData, pixels,
|
||||||
|
staging_buffer_size);
|
||||||
|
|
||||||
copy_region.bufferOffset = 0U;
|
copy_region.bufferOffset = 0U;
|
||||||
copy_region.bufferRowLength = 0U;
|
copy_region.bufferRowLength = 0U;
|
||||||
@@ -420,18 +410,16 @@ static rse_err_t create_textured_image(uint32_t width,
|
|||||||
copy_region.imageOffset.z = 0;
|
copy_region.imageOffset.z = 0;
|
||||||
copy_region.imageExtent = image_extent;
|
copy_region.imageExtent = image_extent;
|
||||||
|
|
||||||
command_buffer = rse_begin_single_time_command();
|
command_buffer = begin_single_time_command(context);
|
||||||
vkCmdCopyBufferToImage(command_buffer,
|
vkCmdCopyBufferToImage(
|
||||||
staging_buffer.buffer,
|
command_buffer, staging_buffer.buffer, free_texture_image->image,
|
||||||
free_texture_image->image,
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
|
||||||
|
end_single_time_comands(context, command_buffer);
|
||||||
|
destroy_buffer(context, &staging_buffer);
|
||||||
|
|
||||||
|
transition_image_layout(context, free_texture_image,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
1,
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
©_region);
|
|
||||||
rse_end_single_time_comands(command_buffer);
|
|
||||||
destroy_buffer(&staging_buffer);
|
|
||||||
|
|
||||||
|
|
||||||
transition_image_layout(free_texture_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
|
|
||||||
// /* Change image layout for shaders to be able to read it */
|
// /* Change image layout for shaders to be able to read it */
|
||||||
// image_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
// image_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
@@ -439,7 +427,7 @@ static rse_err_t create_textured_image(uint32_t width,
|
|||||||
// image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
// image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
// image_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
// image_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
//
|
//
|
||||||
// command_buffer = rse_begin_single_time_command();
|
// command_buffer = begin_single_time_command();
|
||||||
// vkCmdPipelineBarrier(command_buffer,
|
// vkCmdPipelineBarrier(command_buffer,
|
||||||
// VK_PIPELINE_STAGE_TRANSFER_BIT,
|
// VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
// VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
// VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
@@ -450,39 +438,42 @@ static rse_err_t create_textured_image(uint32_t width,
|
|||||||
// NULL,
|
// NULL,
|
||||||
// 1,
|
// 1,
|
||||||
// &image_barrier);
|
// &image_barrier);
|
||||||
// rse_end_single_time_comands(command_buffer);
|
// end_single_time_comands(command_buffer);
|
||||||
|
|
||||||
STATUS_CHECK(create_image_view(free_texture_image, format, VK_IMAGE_ASPECT_COLOR_BIT));
|
STATUS_CHECK(create_image_view(context, free_texture_image, format,
|
||||||
|
VK_IMAGE_ASPECT_COLOR_BIT));
|
||||||
|
|
||||||
free_texture_image->id_taken = IMAGE_TAKEN;
|
free_texture_image->id_taken = IMAGE_TAKEN;
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t init_vulkan_images()
|
rse_err_t init_vulkan_images(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
|
||||||
STATUS_CHECK(create_sampler());
|
STATUS_CHECK(create_sampler(context));
|
||||||
STATUS_CHECK(rse_create_depth_resources());
|
STATUS_CHECK(create_depth_resources(context));
|
||||||
STATUS_CHECK(rse_create_color_resource());
|
STATUS_CHECK(create_color_resource(context));
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t rse_load_texture_from_bitmat(const unsigned char* pixel_buffer, int width, int height, uint16_t* texture_id, VkFormat color_format)
|
rse_err_t load_texture_from_bitmat(struct graphics_context_t* context,
|
||||||
|
const unsigned char* pixel_buffer, int width,
|
||||||
|
int height, uint16_t* texture_id,
|
||||||
|
VkFormat color_format)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
|
||||||
/* Create actual Vulkan Image */
|
/* Create actual Vulkan Image */
|
||||||
STATUS_CHECK(create_textured_image(width,
|
STATUS_CHECK(create_textured_image(context, width, height, color_format,
|
||||||
height,
|
pixel_buffer, texture_id));
|
||||||
color_format,
|
|
||||||
pixel_buffer, texture_id));
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t rse_load_texture_from_file(const char* file_path, uint16_t* texture_id)
|
rse_err_t load_texture_from_file(struct graphics_context_t* context,
|
||||||
|
const char* file_path, uint16_t* texture_id)
|
||||||
{
|
{
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
@@ -490,77 +481,65 @@ rse_err_t rse_load_texture_from_file(const char* file_path, uint16_t* texture_id
|
|||||||
int channels = 0;
|
int channels = 0;
|
||||||
stbi_uc* pixel_buffer = NULL;
|
stbi_uc* pixel_buffer = NULL;
|
||||||
|
|
||||||
pixel_buffer = stbi_load(file_path, &width, &height, &channels, STBI_rgb_alpha);
|
pixel_buffer =
|
||||||
|
stbi_load(file_path, &width, &height, &channels, STBI_rgb_alpha);
|
||||||
|
|
||||||
if (pixel_buffer == NULL) {
|
if (pixel_buffer == NULL) {
|
||||||
LOGE("Failed to load texture from file: %s", file_path);
|
LOGE("Failed to load texture from file: %s", file_path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_CHECK(rse_load_texture_from_bitmat(pixel_buffer, width, height, texture_id, VK_FORMAT_R8G8B8A8_SRGB));
|
STATUS_CHECK(load_texture_from_bitmat(context, pixel_buffer, width, height,
|
||||||
|
texture_id, VK_FORMAT_R8G8B8A8_SRGB));
|
||||||
|
|
||||||
stbi_image_free(pixel_buffer);
|
stbi_image_free(pixel_buffer);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rse_destroy_textures()
|
void destroy_textures(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
size_t i = 0U;
|
size_t i = 0U;
|
||||||
|
|
||||||
vkDestroySampler(g_vulkan_state.device, g_sampler, NULL);
|
vkDestroySampler(context->device, context->sampler, NULL);
|
||||||
|
|
||||||
for (i = 0U; i < RSE_MAX_IMAGE_COUNT; ++i) {
|
for (i = 0U; i < RSE_MAX_IMAGE_COUNT; ++i) {
|
||||||
if (g_texture_images[i].id_taken == IMAGE_TAKEN) {
|
if (context->texture_images[i].id_taken == IMAGE_TAKEN) {
|
||||||
vkDestroyImageView(g_vulkan_state.device, g_texture_images[i].image_view, NULL);
|
vkDestroyImageView(context->device,
|
||||||
vmaDestroyImage(g_vulkan_state.allocator, g_texture_images[i].image, g_texture_images[i].allocation);
|
context->texture_images[i].image_view, NULL);
|
||||||
|
vmaDestroyImage(context->allocator,
|
||||||
|
context->texture_images[i].image,
|
||||||
|
context->texture_images[i].allocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rse_destroy_depth_resource()
|
void destroy_depth_resource(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
vkDestroyImageView(g_vulkan_state.device, g_depth_image.image_view, NULL);
|
vkDestroyImageView(context->device, context->depth_image.image_view, NULL);
|
||||||
vmaDestroyImage(g_vulkan_state.allocator, g_depth_image.image, g_depth_image.allocation);
|
vmaDestroyImage(context->allocator, context->depth_image.image,
|
||||||
|
context->depth_image.allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rse_destroy_color_resource()
|
void destroy_color_resource(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
vkDestroyImageView(g_vulkan_state.device, g_color_image.image_view, NULL);
|
vkDestroyImageView(context->device, context->color_image.image_view, NULL);
|
||||||
vmaDestroyImage(g_vulkan_state.allocator, g_color_image.image, g_color_image.allocation);
|
vmaDestroyImage(context->allocator, context->color_image.image,
|
||||||
|
context->color_image.allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t image_exists(uint8_t image_id) {
|
uint8_t image_exists(struct graphics_context_t* context, uint8_t image_id)
|
||||||
return g_texture_images[image_id].id_taken == IMAGE_TAKEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView rse_get_image_view(size_t image_id)
|
|
||||||
{
|
{
|
||||||
return g_texture_images[image_id].image_view;
|
return context->texture_images[image_id].id_taken == IMAGE_TAKEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageView rse_get_depth_image_view()
|
size_t get_textures_count(struct graphics_context_t* context)
|
||||||
{
|
|
||||||
return g_depth_image.image_view;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView rse_get_color_image_view()
|
|
||||||
{
|
|
||||||
return g_color_image.image_view;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSampler rse_get_texture_sampler()
|
|
||||||
{
|
|
||||||
return g_sampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t get_textures_count()
|
|
||||||
{
|
{
|
||||||
size_t count = 0U;
|
size_t count = 0U;
|
||||||
size_t i = 0U;
|
size_t i = 0U;
|
||||||
|
|
||||||
for (i = 0U; i < RSE_MAX_IMAGE_COUNT; ++i) {
|
for (i = 0U; i < RSE_MAX_IMAGE_COUNT; ++i) {
|
||||||
if(g_texture_images[i].id_taken == IMAGE_TAKEN) {
|
if (context->texture_images[i].id_taken == IMAGE_TAKEN) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -568,20 +547,17 @@ size_t get_textures_count()
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t find_depth_format(VkFormat* found_format)
|
rse_err_t find_depth_format(struct graphics_context_t* context,
|
||||||
|
VkFormat* found_format)
|
||||||
{
|
{
|
||||||
#define formats_count 3
|
#define formats_count 3
|
||||||
rse_err_t status;
|
rse_err_t status;
|
||||||
VkFormat formats[formats_count] = {VK_FORMAT_D32_SFLOAT};
|
VkFormat formats[formats_count] = {VK_FORMAT_D32_SFLOAT};
|
||||||
|
|
||||||
STATUS_CHECK(find_supported_format(
|
STATUS_CHECK(find_supported_format(
|
||||||
formats,
|
context, formats, formats_count, VK_IMAGE_TILING_OPTIMAL,
|
||||||
formats_count,
|
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, found_format));
|
||||||
VK_IMAGE_TILING_OPTIMAL,
|
|
||||||
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
|
||||||
found_format
|
|
||||||
));
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
#undef formats_count
|
#undef formats_count
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* @file vulkan_image.h
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief Library for loading and handling textures
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-09-27
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TEXTURE_H
|
||||||
|
#define TEXTURE_H
|
||||||
|
|
||||||
|
#include "utilities/file_utils.h"
|
||||||
|
#include "utilities/commons.h"
|
||||||
|
#include "graphics_context.h"
|
||||||
|
|
||||||
|
#include "vulkan/vulkan_core.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define IMAGE_FORMAT VK_FORMAT_B8G8R8A8_SRGB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize vulkan with image views and stuff
|
||||||
|
*
|
||||||
|
* @param context Graphics context
|
||||||
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||||
|
*/
|
||||||
|
rse_err_t init_vulkan_images(struct graphics_context_t* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Loads image from file, for later to be used as a texture
|
||||||
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
rse_err_t load_texture_from_bitmat(struct graphics_context_t* context, const unsigned char* pixel_buffer, int width, int height, uint16_t* texture_id, VkFormat color_format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Loads image from file, for later to be used as a texture
|
||||||
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
rse_err_t load_texture_from_file(struct graphics_context_t* context, const char* file_path, uint16_t* texture_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy all loaded textures. Usefull for closing application or just clearing.
|
||||||
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void destroy_textures(struct graphics_context_t* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if image exists for provided image ID.
|
||||||
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
|
* @param image_id Image ID
|
||||||
|
* @return uint8_t 1 on success, 0 on failure
|
||||||
|
*/
|
||||||
|
uint8_t image_exists(struct graphics_context_t* context, uint8_t image_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns number of loaded texture
|
||||||
|
*
|
||||||
|
* @param context Graphics context handle
|
||||||
|
* @return size_t Texture count
|
||||||
|
*/
|
||||||
|
size_t get_textures_count(struct graphics_context_t* context);
|
||||||
|
|
||||||
|
rse_err_t find_depth_format(struct graphics_context_t* context, VkFormat* found_format);
|
||||||
|
|
||||||
|
rse_err_t create_color_resource(struct graphics_context_t* context);
|
||||||
|
void destroy_color_resource(struct graphics_context_t* context);
|
||||||
|
|
||||||
|
rse_err_t create_depth_resources(struct graphics_context_t* context);
|
||||||
|
void destroy_depth_resource(struct graphics_context_t* context);
|
||||||
|
|
||||||
|
#endif /* TEXTURE_H */
|
||||||
@@ -1,855 +0,0 @@
|
|||||||
#include "vulkan_pipeline.h"
|
|
||||||
|
|
||||||
#include "GLFW/glfw3.h"
|
|
||||||
#include "locale_vulkan.h"
|
|
||||||
#include "src/window.h"
|
|
||||||
#include "utilities/file_utils.h"
|
|
||||||
#include "utilities/logger.h"
|
|
||||||
#include "utilities/rse_commons.h"
|
|
||||||
#include "utilities/rse_errors_common.h"
|
|
||||||
#include "vulkan/vulkan_core.h"
|
|
||||||
#include "vulkan_errors.h"
|
|
||||||
#include "rse_vulkan_image.h"
|
|
||||||
#include "vulkan_descriptors.h"
|
|
||||||
#include "vulkan_commons.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define SHADER_MODULES_COUNT 2U
|
|
||||||
|
|
||||||
enum shader_stage_t
|
|
||||||
{
|
|
||||||
VERTEX,
|
|
||||||
FRAGMENTS
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t g_swapchain_images_count = 0U;
|
|
||||||
|
|
||||||
VkImage* g_swapchain_images = NULL;
|
|
||||||
VkShaderModule g_shader_modules[SHADER_MODULES_COUNT];
|
|
||||||
|
|
||||||
|
|
||||||
const char* g_shader_paths[] = {
|
|
||||||
"../graphics/shaders/shader.vert.num",
|
|
||||||
"../graphics/shaders/solid_objects.frag.num",
|
|
||||||
"../graphics/shaders/on_screen_text.frag.num",
|
|
||||||
};
|
|
||||||
|
|
||||||
static VkVertexInputBindingDescription get_binding_description()
|
|
||||||
{
|
|
||||||
VkVertexInputBindingDescription binding_description;
|
|
||||||
|
|
||||||
binding_description.binding = 0;
|
|
||||||
binding_description.stride = sizeof(struct rse_vertex_t);
|
|
||||||
binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
|
||||||
|
|
||||||
return binding_description;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static VkVertexInputAttributeDescription* get_attribute_descriptions()
|
|
||||||
{
|
|
||||||
static VkVertexInputAttributeDescription attribute_descriptions[3];
|
|
||||||
|
|
||||||
attribute_descriptions[0].binding = 0;
|
|
||||||
attribute_descriptions[0].location = 0; /* inPosition in shader.vert */
|
|
||||||
attribute_descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
||||||
attribute_descriptions[0].offset = offsetof(struct rse_vertex_t, pos);
|
|
||||||
|
|
||||||
attribute_descriptions[1].binding = 0;
|
|
||||||
attribute_descriptions[1].location = 1; /* inColor in shader.vert */
|
|
||||||
attribute_descriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
|
||||||
attribute_descriptions[1].offset = offsetof(struct rse_vertex_t, color);
|
|
||||||
|
|
||||||
attribute_descriptions[2].binding = 0;
|
|
||||||
attribute_descriptions[2].location = 2; /* inTexCoords in shader.vert */
|
|
||||||
attribute_descriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
|
|
||||||
attribute_descriptions[2].offset = offsetof(struct rse_vertex_t, tex_coords);
|
|
||||||
|
|
||||||
return attribute_descriptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates shader module
|
|
||||||
*
|
|
||||||
* @param binary_data Shader compiled code
|
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
|
||||||
*/
|
|
||||||
static rse_err_t create_shader_module(const char* binary_data, size_t data_size, VkShaderModule* shader_module)
|
|
||||||
{
|
|
||||||
VkShaderModuleCreateInfo create_info = {};
|
|
||||||
|
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
||||||
create_info.pNext = NULL;
|
|
||||||
create_info.flags = 0U;
|
|
||||||
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_messages[VULKAN_SHADER_UNABLE_TO_CREATE_SHADER]);
|
|
||||||
return VULKAN_ERROR_SHADER_CREATION_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create a Swapchain
|
|
||||||
*
|
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
|
||||||
* VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED
|
|
||||||
*/
|
|
||||||
static rse_err_t create_swapchain()
|
|
||||||
{
|
|
||||||
VkSwapchainCreateInfoKHR create_info;
|
|
||||||
VkSurfaceCapabilitiesKHR physical_device_surface_capabilities;
|
|
||||||
VkBool32 surfaceSupported;
|
|
||||||
|
|
||||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_vulkan_state.physical_device,
|
|
||||||
g_vulkan_state.surface,
|
|
||||||
&physical_device_surface_capabilities);
|
|
||||||
|
|
||||||
/* Store extent in global variable, for later use */
|
|
||||||
g_vulkan_state.swapchain_extent = physical_device_surface_capabilities.currentExtent;
|
|
||||||
|
|
||||||
/* Check if device supports surface for presentation */
|
|
||||||
vkGetPhysicalDeviceSurfaceSupportKHR(g_vulkan_state.physical_device,
|
|
||||||
g_vulkan_state.queue_family_indices[0],
|
|
||||||
g_vulkan_state.surface,
|
|
||||||
&surfaceSupported);
|
|
||||||
|
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
||||||
create_info.pNext = NULL;
|
|
||||||
create_info.flags = 0U;
|
|
||||||
create_info.surface = g_vulkan_state.surface;
|
|
||||||
create_info.minImageCount = SWAP_BUFFER_COUNT + 1;
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
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_messages[VULKAN_SWAPCHAIN_CREATION_FAILED]);
|
|
||||||
return VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain swapchain images */
|
|
||||||
vkGetSwapchainImagesKHR(g_vulkan_state.device, g_vulkan_state.swapchain, &g_swapchain_images_count, NULL);
|
|
||||||
rse_malloc(g_swapchain_images, sizeof(VkImage) * g_swapchain_images_count);
|
|
||||||
vkGetSwapchainImagesKHR(g_vulkan_state.device, g_vulkan_state.swapchain, &g_swapchain_images_count, g_swapchain_images);
|
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create a Swapchain Image Views
|
|
||||||
*
|
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
|
||||||
*/
|
|
||||||
static rse_err_t create_swapchain_image_views()
|
|
||||||
{
|
|
||||||
rse_malloc(g_vulkan_state.swapchain_image_views, sizeof(VkImageView) * g_swapchain_images_count);
|
|
||||||
for (size_t i = 0; i < g_swapchain_images_count; i++) {
|
|
||||||
VkImageViewCreateInfo create_info;
|
|
||||||
|
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
create_info.pNext = NULL;
|
|
||||||
create_info.flags = 0U;
|
|
||||||
create_info.image = g_swapchain_images[i];
|
|
||||||
create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; /* 2D Texture */
|
|
||||||
create_info.format = VK_FORMAT_B8G8R8A8_SRGB;
|
|
||||||
create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
||||||
create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
||||||
create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
||||||
create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
||||||
create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
create_info.subresourceRange.baseMipLevel = 0U;
|
|
||||||
create_info.subresourceRange.levelCount = 1U;
|
|
||||||
create_info.subresourceRange.baseArrayLayer = 0U;
|
|
||||||
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_messages[VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED]);
|
|
||||||
return VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create a Render Pass
|
|
||||||
*
|
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
|
||||||
* VULKAN_ERROR_RENDERPASS_CREATION_FAILED
|
|
||||||
*/
|
|
||||||
static rse_err_t create_render_pass()
|
|
||||||
{
|
|
||||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
|
||||||
VkAttachmentDescription attachments[3] = {};
|
|
||||||
VkAttachmentDescription color_attachment = {};
|
|
||||||
VkAttachmentReference color_attachment_ref = {};
|
|
||||||
VkAttachmentDescription color_attachment_resolve = {};
|
|
||||||
VkAttachmentReference color_attachment_resolve_ref = {};
|
|
||||||
VkSubpassDescription subpass = {};
|
|
||||||
VkRenderPassCreateInfo renderpass_info = {};
|
|
||||||
VkAttachmentDescription depth_attachment = {};
|
|
||||||
VkAttachmentReference depth_attachment_ref = {};
|
|
||||||
VkSubpassDependency dependency = {};
|
|
||||||
|
|
||||||
STATUS_CHECK(find_depth_format(&depth_attachment.format));
|
|
||||||
|
|
||||||
depth_attachment.samples = VK_SAMPLE_COUNT_16_BIT;
|
|
||||||
depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
||||||
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
||||||
depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
||||||
depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
||||||
depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
|
||||||
|
|
||||||
depth_attachment_ref.attachment = 1;
|
|
||||||
depth_attachment_ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
|
||||||
|
|
||||||
color_attachment.flags = 0U;
|
|
||||||
color_attachment.format = IMAGE_FORMAT;
|
|
||||||
color_attachment.samples = VK_SAMPLE_COUNT_16_BIT;
|
|
||||||
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
||||||
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
||||||
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
||||||
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
||||||
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
color_attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
||||||
|
|
||||||
color_attachment_ref.attachment = 0;
|
|
||||||
color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
||||||
|
|
||||||
color_attachment_resolve.format = IMAGE_FORMAT;
|
|
||||||
color_attachment_resolve.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
color_attachment_resolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
||||||
color_attachment_resolve.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
||||||
color_attachment_resolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
||||||
color_attachment_resolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
||||||
color_attachment_resolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
color_attachment_resolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
|
||||||
|
|
||||||
color_attachment_resolve_ref.attachment = 2;
|
|
||||||
color_attachment_resolve_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
||||||
|
|
||||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
|
||||||
subpass.colorAttachmentCount = 1;
|
|
||||||
subpass.pColorAttachments = &color_attachment_ref;
|
|
||||||
subpass.pDepthStencilAttachment = &depth_attachment_ref;
|
|
||||||
subpass.pResolveAttachments = &color_attachment_resolve_ref;
|
|
||||||
|
|
||||||
attachments[0] = color_attachment;
|
|
||||||
attachments[1] = depth_attachment;
|
|
||||||
attachments[2] = color_attachment_resolve;
|
|
||||||
|
|
||||||
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
|
||||||
dependency.dstSubpass = 0;
|
|
||||||
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
|
||||||
dependency.srcAccessMask = 0;
|
|
||||||
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
|
||||||
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
|
||||||
|
|
||||||
renderpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
|
||||||
renderpass_info.attachmentCount = 3;
|
|
||||||
renderpass_info.pAttachments = attachments;
|
|
||||||
renderpass_info.subpassCount = 1;
|
|
||||||
renderpass_info.pSubpasses = &subpass;
|
|
||||||
renderpass_info.dependencyCount = 1;
|
|
||||||
renderpass_info.pDependencies = &dependency;
|
|
||||||
|
|
||||||
if (VK_SUCCESS != vkCreateRenderPass(g_vulkan_state.device, &renderpass_info, NULL, &g_vulkan_state.render_pass)) {
|
|
||||||
LOGF(vulkan_messages[VULKAN_RENDERPASS_CREATION_FAILED]);
|
|
||||||
return VULKAN_ERROR_RENDERPASS_CREATION_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create a Descriptor Set Layout
|
|
||||||
*
|
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success.
|
|
||||||
*/
|
|
||||||
static rse_err_t create_descriptor_set_layout()
|
|
||||||
{
|
|
||||||
VkDescriptorSetLayoutCreateInfo layout_info = {};
|
|
||||||
VkDescriptorSetLayoutCreateInfo layout_info_bindless = {};
|
|
||||||
VkDescriptorSetLayoutBinding bindings[2];
|
|
||||||
VkDescriptorSetLayoutBinding ubo_layout_binding = {};
|
|
||||||
VkDescriptorSetLayoutBinding sampler_layout_binding = {};
|
|
||||||
VkDescriptorSetLayoutBindingFlagsCreateInfoEXT extended_info = {0};
|
|
||||||
VkDescriptorBindingFlags bindless_flags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT
|
|
||||||
| VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT
|
|
||||||
| VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT;
|
|
||||||
|
|
||||||
extended_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT;
|
|
||||||
extended_info.bindingCount = 1;
|
|
||||||
extended_info.pBindingFlags = &bindless_flags;
|
|
||||||
|
|
||||||
ubo_layout_binding.binding = 0;
|
|
||||||
ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
||||||
ubo_layout_binding.descriptorCount = 1;
|
|
||||||
ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
|
||||||
ubo_layout_binding.pImmutableSamplers = NULL;
|
|
||||||
|
|
||||||
sampler_layout_binding.binding = 1;
|
|
||||||
sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
sampler_layout_binding.descriptorCount = MAX_BINDLESS_RESOURCES;
|
|
||||||
sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
sampler_layout_binding.pImmutableSamplers = NULL;
|
|
||||||
|
|
||||||
bindings[0] = ubo_layout_binding;
|
|
||||||
bindings[1] = sampler_layout_binding;
|
|
||||||
|
|
||||||
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
|
||||||
layout_info.bindingCount = 1U;
|
|
||||||
layout_info.pBindings = &bindings[0];
|
|
||||||
|
|
||||||
if (vkCreateDescriptorSetLayout(g_vulkan_state.device, &layout_info, NULL, &g_vulkan_state.descriptor_set_layout) != VK_SUCCESS) {
|
|
||||||
LOGF(vulkan_messages[VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED]);
|
|
||||||
return VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
layout_info_bindless = layout_info;
|
|
||||||
layout_info_bindless.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT;
|
|
||||||
layout_info_bindless.pNext = &extended_info;
|
|
||||||
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_messages[VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED]);
|
|
||||||
return VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief Create a Pipeline Layout
|
|
||||||
*
|
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
|
||||||
* VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED
|
|
||||||
*/
|
|
||||||
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 = {};
|
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
||||||
create_info.pNext = NULL;
|
|
||||||
create_info.flags = 0U;
|
|
||||||
create_info.setLayoutCount = 2U;
|
|
||||||
create_info.pSetLayouts = set_layouts;
|
|
||||||
create_info.pushConstantRangeCount = 0U;
|
|
||||||
create_info.pPushConstantRanges = NULL;
|
|
||||||
|
|
||||||
if (VK_SUCCESS != vkCreatePipelineLayout(g_vulkan_state.device, &create_info, NULL, &g_vulkan_state.pipeline_layout)) {
|
|
||||||
LOGF(vulkan_messages[VULKAN_PIPELAYOUT_CREATION_FAILED]);
|
|
||||||
return VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
|
||||||
* VULKAN_ERROR_SHADER_FILE_OPEN_FAILED
|
|
||||||
* VULKAN_ERROR_SHADER_CREATION_FAILED
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
VkShaderModule fragments_shader_module;
|
|
||||||
VkPipelineShaderStageCreateInfo vert_shader_stage_info = {};
|
|
||||||
VkPipelineShaderStageCreateInfo frag_shader_stage_info = {};
|
|
||||||
|
|
||||||
rse_read_file(g_shader_paths[VERTEX], &buffer_size, NULL);
|
|
||||||
rse_malloc(buffer, buffer_size);
|
|
||||||
rse_read_file(g_shader_paths[VERTEX], &buffer_size, buffer);
|
|
||||||
|
|
||||||
STATUS_CHECK(create_shader_module(buffer, buffer_size, &vertex_shader_module));
|
|
||||||
rse_free(buffer);
|
|
||||||
|
|
||||||
rse_read_file(g_shader_paths[FRAGMENTS], &buffer_size, NULL);
|
|
||||||
rse_malloc(buffer, buffer_size);
|
|
||||||
rse_read_file(g_shader_paths[FRAGMENTS], &buffer_size, buffer);
|
|
||||||
|
|
||||||
STATUS_CHECK(create_shader_module(buffer, buffer_size, &fragments_shader_module));
|
|
||||||
rse_free(buffer);
|
|
||||||
|
|
||||||
/* Vertex Shader Pipeline Stage */
|
|
||||||
vert_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
||||||
vert_shader_stage_info.pNext = NULL;
|
|
||||||
vert_shader_stage_info.flags = 0U;
|
|
||||||
vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
|
||||||
vert_shader_stage_info.module = vertex_shader_module;
|
|
||||||
vert_shader_stage_info.pName = "main"; /* Entry point function */
|
|
||||||
vert_shader_stage_info.pSpecializationInfo = NULL; /* Specialization in a SPIR-V module */
|
|
||||||
|
|
||||||
/* Fragments Shader Pipeline Stage */
|
|
||||||
frag_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
||||||
frag_shader_stage_info.pNext = NULL;
|
|
||||||
frag_shader_stage_info.flags = 0U;
|
|
||||||
frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
frag_shader_stage_info.module = fragments_shader_module;
|
|
||||||
frag_shader_stage_info.pName = "main"; /* Entry point function */
|
|
||||||
frag_shader_stage_info.pSpecializationInfo = NULL; /* Specialization in a SPIR-V module */
|
|
||||||
|
|
||||||
shader_stages[VERTEX] = vert_shader_stage_info;
|
|
||||||
shader_stages[FRAGMENTS] = frag_shader_stage_info;
|
|
||||||
|
|
||||||
rse_memcpy(&g_shader_modules[0], &vertex_shader_module, sizeof(VkShaderModule));
|
|
||||||
rse_memcpy(&g_shader_modules[1], &fragments_shader_module, sizeof(VkShaderModule));
|
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Fill dynamic pipeline state info
|
|
||||||
*
|
|
||||||
* @param dynamic_state structure to be filled
|
|
||||||
*/
|
|
||||||
static void fill_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state)
|
|
||||||
{
|
|
||||||
VkDynamicState* dynamic_states;
|
|
||||||
/*
|
|
||||||
* Select pipeline stages that will be set dynamically. Those that are selected are ignored in
|
|
||||||
* pipeline create structures. I'll list ignored members of structs, that will be ignored due to the
|
|
||||||
* settings and also functions, that will need to be called to set specific state.
|
|
||||||
*/
|
|
||||||
rse_malloc(dynamic_states, sizeof(VkDynamicState) * 2);
|
|
||||||
dynamic_states[0] = VK_DYNAMIC_STATE_VIEWPORT; /* VkPipelineViewportStateCreateInfo:pViewport; vkCmdSetViewport() */
|
|
||||||
dynamic_states[1] = VK_DYNAMIC_STATE_SCISSOR; /* VkPipelineViewportStateCreateInfo:pScissors; vkCmdSetScissors() */
|
|
||||||
|
|
||||||
dynamic_state->sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
|
||||||
dynamic_state->pNext = NULL;
|
|
||||||
dynamic_state->flags = 0U;
|
|
||||||
dynamic_state->dynamicStateCount = 2U;
|
|
||||||
|
|
||||||
/* dynamic_state is constructed localy. To avoid creation of VkPipelineDynamicStateCreateInfo structure in
|
|
||||||
* main pipeline construction function, we have to do a little memory trickery here and allocate memory for
|
|
||||||
* dynamic state pointer manually. We must also free this memory later */
|
|
||||||
dynamic_state->pDynamicStates = dynamic_states;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Release allocated dynamic pipeline state info
|
|
||||||
*
|
|
||||||
* @param dynamic_state structure to be freed
|
|
||||||
*/
|
|
||||||
static void free_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state)
|
|
||||||
{
|
|
||||||
rse_free((VkDynamicState*)dynamic_state->pDynamicStates);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Fill vertex input info
|
|
||||||
*
|
|
||||||
* @param vertex_input_info structure to be filled
|
|
||||||
*/
|
|
||||||
static void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info)
|
|
||||||
{
|
|
||||||
const size_t binding_descriptions_count = 2;
|
|
||||||
const size_t attribute_descriptions_count = 7;
|
|
||||||
/* TODO: This is clusterfuck with some magic numbers here and there and unneeded malloc and memcpy stuff. Change,
|
|
||||||
* so you won't feel ashamed. */
|
|
||||||
VkVertexInputBindingDescription vertex_binding_description = get_binding_description();
|
|
||||||
VkVertexInputAttributeDescription* vertex_attribute_descriptions = get_attribute_descriptions();
|
|
||||||
VkVertexInputBindingDescription* binding_descriptions = NULL;
|
|
||||||
VkVertexInputAttributeDescription* attribute_descriptions = NULL;
|
|
||||||
|
|
||||||
rse_malloc(binding_descriptions, sizeof(VkVertexInputBindingDescription) * binding_descriptions_count);
|
|
||||||
rse_malloc(attribute_descriptions, sizeof(VkVertexInputAttributeDescription) * attribute_descriptions_count);
|
|
||||||
|
|
||||||
binding_descriptions[0] = vertex_binding_description;
|
|
||||||
|
|
||||||
binding_descriptions[1].binding = 1;
|
|
||||||
binding_descriptions[1].stride = sizeof(struct rse_instance_data_t);
|
|
||||||
binding_descriptions[1].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
|
|
||||||
|
|
||||||
rse_memcpy(attribute_descriptions, vertex_attribute_descriptions, sizeof(VkVertexInputAttributeDescription) * 3);
|
|
||||||
|
|
||||||
attribute_descriptions[3].binding = 1;
|
|
||||||
attribute_descriptions[3].location = 3;
|
|
||||||
attribute_descriptions[3].format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
||||||
attribute_descriptions[3].offset = offsetof(struct rse_instance_data_t, pos);
|
|
||||||
|
|
||||||
attribute_descriptions[4].binding = 1;
|
|
||||||
attribute_descriptions[4].location = 4;
|
|
||||||
attribute_descriptions[4].format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
||||||
attribute_descriptions[4].offset = offsetof(struct rse_instance_data_t, rot);
|
|
||||||
|
|
||||||
attribute_descriptions[5].binding = 1;
|
|
||||||
attribute_descriptions[5].location = 5;
|
|
||||||
attribute_descriptions[5].format = VK_FORMAT_R32_SFLOAT;
|
|
||||||
attribute_descriptions[5].offset = offsetof(struct rse_instance_data_t, scale);
|
|
||||||
|
|
||||||
attribute_descriptions[6].binding = 1;
|
|
||||||
attribute_descriptions[6].location = 6;
|
|
||||||
attribute_descriptions[6].format = VK_FORMAT_R8_UINT;
|
|
||||||
attribute_descriptions[6].offset = offsetof(struct rse_instance_data_t, texture_id);
|
|
||||||
// ************************
|
|
||||||
|
|
||||||
vertex_input_info->sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
||||||
vertex_input_info->pNext = NULL;
|
|
||||||
vertex_input_info->flags = 0U;
|
|
||||||
|
|
||||||
vertex_input_info->vertexBindingDescriptionCount = binding_descriptions_count;
|
|
||||||
vertex_input_info->pVertexBindingDescriptions = binding_descriptions;
|
|
||||||
vertex_input_info->vertexAttributeDescriptionCount = attribute_descriptions_count;
|
|
||||||
vertex_input_info->pVertexAttributeDescriptions = attribute_descriptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Free allocated vertex input info
|
|
||||||
*
|
|
||||||
* @param vertex_input_info structure to be freed
|
|
||||||
*/
|
|
||||||
static void free_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info)
|
|
||||||
{
|
|
||||||
rse_free((VkVertexInputBindingDescription*)vertex_input_info->pVertexBindingDescriptions);
|
|
||||||
rse_free((VkVertexInputAttributeDescription*)vertex_input_info->pVertexAttributeDescriptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Fill input assembly info
|
|
||||||
*
|
|
||||||
* @param input_assembly structure to be filled
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
input_assembly->primitiveRestartEnable = VK_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Fill viewport state info
|
|
||||||
*
|
|
||||||
* @param viewport_state structure to be filled
|
|
||||||
*/
|
|
||||||
static void fill_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state)
|
|
||||||
{
|
|
||||||
VkViewport* viewport = NULL;
|
|
||||||
VkRect2D* scissor = NULL;
|
|
||||||
|
|
||||||
rse_malloc(viewport, sizeof(VkViewport));
|
|
||||||
rse_malloc(scissor, sizeof(VkRect2D));
|
|
||||||
viewport->x = 0.0f;
|
|
||||||
viewport->y = 0.0f;
|
|
||||||
viewport->width = (float)(g_vulkan_state.swapchain_extent.width);
|
|
||||||
viewport->height = (float)(g_vulkan_state.swapchain_extent.height);
|
|
||||||
viewport->minDepth = 0.0f;
|
|
||||||
viewport->maxDepth = 1.0f;
|
|
||||||
|
|
||||||
/* Setting Scissors to fill entire window*/
|
|
||||||
scissor->offset.x = 0;
|
|
||||||
scissor->offset.y = 0;
|
|
||||||
scissor->extent = g_vulkan_state.swapchain_extent;
|
|
||||||
|
|
||||||
viewport_state->sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
|
||||||
viewport_state->viewportCount = 1;
|
|
||||||
viewport_state->pViewports = viewport;
|
|
||||||
viewport_state->scissorCount = 1;
|
|
||||||
viewport_state->pScissors = scissor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Free allocated viewport state input info
|
|
||||||
*
|
|
||||||
* @param viewport_state structure to be freed
|
|
||||||
*/
|
|
||||||
static void free_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state)
|
|
||||||
{
|
|
||||||
rse_free((VkViewport*)viewport_state->pViewports);
|
|
||||||
rse_free((VkRect2D*)viewport_state->pScissors);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Fill rasteriation info
|
|
||||||
*
|
|
||||||
* @param rasterizer
|
|
||||||
*/
|
|
||||||
static void fill_rasterization_info(VkPipelineRasterizationStateCreateInfo* rasterizer)
|
|
||||||
{
|
|
||||||
rasterizer->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
|
||||||
rasterizer->pNext = NULL;
|
|
||||||
rasterizer->flags = 0U;
|
|
||||||
rasterizer->depthClampEnable = VK_FALSE; /* VK_TRUE to play with shadow maps */
|
|
||||||
rasterizer->rasterizerDiscardEnable = VK_FALSE; /* Disable/Enable output to framebuffer*/
|
|
||||||
rasterizer->polygonMode = VK_POLYGON_MODE_FILL;
|
|
||||||
rasterizer->cullMode = VK_CULL_MODE_BACK_BIT;
|
|
||||||
rasterizer->frontFace = VK_FRONT_FACE_CLOCKWISE;
|
|
||||||
rasterizer->depthBiasEnable = VK_FALSE;
|
|
||||||
rasterizer->depthBiasConstantFactor = 0.0f;
|
|
||||||
rasterizer->depthBiasClamp = 0.0f;
|
|
||||||
rasterizer->depthBiasSlopeFactor = 0.0f;
|
|
||||||
rasterizer->lineWidth = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Fill multisampling state info
|
|
||||||
*
|
|
||||||
* @param multisampling structure to be filled
|
|
||||||
*/
|
|
||||||
static void fill_multisampling_state_info(VkPipelineMultisampleStateCreateInfo* multisampling)
|
|
||||||
{
|
|
||||||
multisampling->sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
|
||||||
multisampling->pNext = NULL;
|
|
||||||
multisampling->flags = 0U;
|
|
||||||
multisampling->rasterizationSamples = VK_SAMPLE_COUNT_16_BIT;
|
|
||||||
multisampling->sampleShadingEnable = VK_FALSE;
|
|
||||||
multisampling->minSampleShading = 1.0f;
|
|
||||||
multisampling->pSampleMask = NULL;
|
|
||||||
multisampling->alphaToCoverageEnable = VK_FALSE;
|
|
||||||
multisampling->alphaToOneEnable = VK_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Fill color blend state info
|
|
||||||
*
|
|
||||||
* @param color_blending structure to be filled
|
|
||||||
*/
|
|
||||||
static void fill_color_blend_state_info(VkPipelineColorBlendStateCreateInfo* color_blending)
|
|
||||||
{
|
|
||||||
VkPipelineColorBlendAttachmentState* color_blend_attachment = NULL;
|
|
||||||
|
|
||||||
rse_malloc(color_blend_attachment, sizeof(VkPipelineColorBlendAttachmentState));
|
|
||||||
|
|
||||||
color_blend_attachment->blendEnable = VK_TRUE;
|
|
||||||
color_blend_attachment->srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
||||||
color_blend_attachment->dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
||||||
color_blend_attachment->colorBlendOp = VK_BLEND_OP_ADD;
|
|
||||||
color_blend_attachment->srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
||||||
color_blend_attachment->dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
||||||
color_blend_attachment->alphaBlendOp = VK_BLEND_OP_ADD;
|
|
||||||
color_blend_attachment->colorWriteMask =
|
|
||||||
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
||||||
|
|
||||||
color_blending->sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
||||||
color_blending->pNext = NULL;
|
|
||||||
color_blending->flags = 0U;
|
|
||||||
color_blending->logicOpEnable = VK_FALSE;
|
|
||||||
color_blending->logicOp = VK_LOGIC_OP_COPY;
|
|
||||||
color_blending->attachmentCount = 1U;
|
|
||||||
color_blending->pAttachments = color_blend_attachment;
|
|
||||||
color_blending->blendConstants[0] = 0.0f;
|
|
||||||
color_blending->blendConstants[1] = 0.0f;
|
|
||||||
color_blending->blendConstants[2] = 0.0f;
|
|
||||||
color_blending->blendConstants[3] = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Free allocated color blend state info
|
|
||||||
*
|
|
||||||
* @param color_blending Structure to be freed
|
|
||||||
*/
|
|
||||||
static void free_color_blend_info(VkPipelineColorBlendStateCreateInfo* color_blending)
|
|
||||||
{
|
|
||||||
rse_free((VkPipelineColorBlendAttachmentState*)color_blending->pAttachments);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fill_depth_stencil_info(VkPipelineDepthStencilStateCreateInfo* depth_stencil)
|
|
||||||
{
|
|
||||||
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 = NULL;
|
|
||||||
|
|
||||||
rse_malloc(g_vulkan_state.swapchain_framebuffers, sizeof(VkFramebuffer) * g_swapchain_images_count);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < g_swapchain_images_count; i++) {
|
|
||||||
VkImageView attachments[] = {rse_get_color_image_view(), rse_get_depth_image_view(), g_vulkan_state.swapchain_image_views[i]};
|
|
||||||
|
|
||||||
VkFramebufferCreateInfo framebufferInfo = {};
|
|
||||||
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
||||||
framebufferInfo.renderPass = g_vulkan_state.render_pass;
|
|
||||||
framebufferInfo.attachmentCount = 3;
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
|
|
||||||
glfwGetFramebufferSize(get_window_handle(), &width, &height);
|
|
||||||
while (width == 0 || height == 0) {
|
|
||||||
glfwGetFramebufferSize(get_window_handle(), &width, &height);
|
|
||||||
glfwWaitEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
vkDeviceWaitIdle(g_vulkan_state.device);
|
|
||||||
|
|
||||||
cleanup_swapchain();
|
|
||||||
|
|
||||||
create_swapchain();
|
|
||||||
create_swapchain_image_views();
|
|
||||||
rse_create_color_resource();
|
|
||||||
rse_create_depth_resources();
|
|
||||||
create_framebuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Cleanup swapchain
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void cleanup_swapchain()
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
rse_destroy_color_resource();
|
|
||||||
rse_destroy_depth_resource();
|
|
||||||
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());
|
|
||||||
STATUS_CHECK(create_render_pass());
|
|
||||||
STATUS_CHECK(create_descriptor_set_layout());
|
|
||||||
STATUS_CHECK(create_pipeline_layout());
|
|
||||||
STATUS_CHECK(create_graphics_pipeline());
|
|
||||||
STATUS_CHECK(create_framebuffers());
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy_pipeline()
|
|
||||||
{
|
|
||||||
vkDestroyPipeline(g_vulkan_state.device, g_vulkan_state.graphics_pipeline, NULL);
|
|
||||||
vkDestroyPipelineLayout(g_vulkan_state.device, g_vulkan_state.pipeline_layout, NULL);
|
|
||||||
vkDestroyRenderPass(g_vulkan_state.device, g_vulkan_state.render_pass, NULL);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < SHADER_MODULES_COUNT; i++) {
|
|
||||||
vkDestroyShaderModule(g_vulkan_state.device, g_shader_modules[i], NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#ifndef RSE_VULKAN_PIPELINE_H
|
|
||||||
#define RSE_VULKAN_PIPELINE_H
|
|
||||||
|
|
||||||
#include "utilities/rse_commons.h"
|
|
||||||
|
|
||||||
#define IMAGE_FORMAT VK_FORMAT_B8G8R8A8_SRGB;
|
|
||||||
/**
|
|
||||||
* @brief Create a graphics pipeline
|
|
||||||
*
|
|
||||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
|
||||||
*/
|
|
||||||
rse_err_t create_pipeline(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Cleanup swapchain
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void cleanup_swapchain(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Recreates swapchain
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void recreate_swapchain(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Destroy all vulkan pipeline objects
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void destroy_pipeline(void);
|
|
||||||
|
|
||||||
#endif /* RSE_VULKAN_PIPELINE_H */
|
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utilities/commons.h"
|
||||||
|
#include "utilities/errors_common.h"
|
||||||
|
#include "utilities/logger.h"
|
||||||
|
#include "utilities/localization.h"
|
||||||
|
#include "vulkan/vulkan_core.h"
|
||||||
|
#include "vulkan_commons.h"
|
||||||
|
#include "vulkan_descriptors.h"
|
||||||
|
#include "vulkan_errors.h"
|
||||||
|
#include "vulkan_image.h"
|
||||||
|
#include "vulkan_swapchain.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Swapchain
|
||||||
|
*
|
||||||
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED
|
||||||
|
*/
|
||||||
|
static rse_err_t create_swapchain(struct graphics_context_t* context)
|
||||||
|
{
|
||||||
|
VkSwapchainCreateInfoKHR create_info;
|
||||||
|
VkSurfaceCapabilitiesKHR physical_device_surface_capabilities;
|
||||||
|
VkBool32 surfaceSupported;
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
||||||
|
context->physical_device, context->surface,
|
||||||
|
&physical_device_surface_capabilities);
|
||||||
|
|
||||||
|
/* Store extent in global variable, for later use */
|
||||||
|
context->swapchain_extent =
|
||||||
|
physical_device_surface_capabilities.currentExtent;
|
||||||
|
|
||||||
|
/* Check if device supports surface for presentation */
|
||||||
|
vkGetPhysicalDeviceSurfaceSupportKHR(context->physical_device,
|
||||||
|
context->queue_family_indices[0],
|
||||||
|
context->surface, &surfaceSupported);
|
||||||
|
|
||||||
|
create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||||
|
create_info.pNext = NULL;
|
||||||
|
create_info.flags = 0U;
|
||||||
|
create_info.surface = context->surface;
|
||||||
|
create_info.minImageCount = SWAP_BUFFER_COUNT + 1;
|
||||||
|
create_info.imageFormat = IMAGE_FORMAT;
|
||||||
|
create_info.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||||
|
create_info.imageExtent = context->swapchain_extent;
|
||||||
|
create_info.imageArrayLayers =
|
||||||
|
1U; /* For non-stereoscopic-3D applications, this value is 1. */
|
||||||
|
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 = context->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;
|
||||||
|
create_info.clipped = VK_TRUE;
|
||||||
|
create_info.oldSwapchain = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
if (VK_SUCCESS != vkCreateSwapchainKHR(context->device, &create_info, NULL,
|
||||||
|
&context->swapchain)) {
|
||||||
|
LOGF(_("Failed to create swapchain\n"));
|
||||||
|
return VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Obtain swapchain images */
|
||||||
|
vkGetSwapchainImagesKHR(context->device, context->swapchain,
|
||||||
|
&context->swapchain_images_count, NULL);
|
||||||
|
rse_malloc(context->swapchain_images, sizeof(VkImage) * context->swapchain_images_count);
|
||||||
|
vkGetSwapchainImagesKHR(context->device, context->swapchain,
|
||||||
|
&context->swapchain_images_count, context->swapchain_images);
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Swapchain Image Views
|
||||||
|
*
|
||||||
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
*/
|
||||||
|
static rse_err_t create_swapchain_image_views(struct graphics_context_t* context)
|
||||||
|
{
|
||||||
|
rse_malloc(context->swapchain_image_views,
|
||||||
|
sizeof(VkImageView) * context->swapchain_images_count);
|
||||||
|
for (size_t i = 0; i < context->swapchain_images_count; i++) {
|
||||||
|
VkImageViewCreateInfo create_info;
|
||||||
|
|
||||||
|
create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
create_info.pNext = NULL;
|
||||||
|
create_info.flags = 0U;
|
||||||
|
create_info.image = context->swapchain_images[i];
|
||||||
|
create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; /* 2D Texture */
|
||||||
|
create_info.format = VK_FORMAT_B8G8R8A8_SRGB;
|
||||||
|
create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
create_info.subresourceRange.baseMipLevel = 0U;
|
||||||
|
create_info.subresourceRange.levelCount = 1U;
|
||||||
|
create_info.subresourceRange.baseArrayLayer = 0U;
|
||||||
|
create_info.subresourceRange.layerCount = 1U;
|
||||||
|
|
||||||
|
if (VK_SUCCESS !=
|
||||||
|
vkCreateImageView(context->device, &create_info, NULL,
|
||||||
|
&context->swapchain_image_views[i])) {
|
||||||
|
LOGF(_("Failed to create swapchain image view\n"));
|
||||||
|
return VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create Frambuffers
|
||||||
|
*
|
||||||
|
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
*/
|
||||||
|
static rse_err_t create_framebuffers(struct graphics_context_t* context)
|
||||||
|
{
|
||||||
|
context->swapchain_framebuffers = NULL;
|
||||||
|
|
||||||
|
rse_malloc(context->swapchain_framebuffers,
|
||||||
|
sizeof(VkFramebuffer) * context->swapchain_images_count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < context->swapchain_images_count; i++) {
|
||||||
|
VkImageView attachments[] = {context->color_image.image_view,
|
||||||
|
context->depth_image.image_view,
|
||||||
|
context->swapchain_image_views[i]};
|
||||||
|
|
||||||
|
VkFramebufferCreateInfo framebufferInfo = {};
|
||||||
|
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
|
framebufferInfo.renderPass = context->render_pass;
|
||||||
|
framebufferInfo.attachmentCount = 3;
|
||||||
|
framebufferInfo.pAttachments = attachments;
|
||||||
|
framebufferInfo.width = context->swapchain_extent.width;
|
||||||
|
framebufferInfo.height = context->swapchain_extent.height;
|
||||||
|
framebufferInfo.layers = 1;
|
||||||
|
|
||||||
|
if (vkCreateFramebuffer(context->device, &framebufferInfo, NULL,
|
||||||
|
&context->swapchain_framebuffers[i]) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
|
LOGF(_("Failed to create framebuffer\n"));
|
||||||
|
return VULKAN_ERROR_FRAMEBUFFERS_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSE_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Recreate swapchain
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void recreate_swapchain(struct graphics_context_t* context)
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
|
||||||
|
glfwGetFramebufferSize(context->window_handle, &width, &height);
|
||||||
|
while (width == 0 || height == 0) {
|
||||||
|
glfwGetFramebufferSize(context->window_handle, &width, &height);
|
||||||
|
glfwWaitEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDeviceWaitIdle(context->device);
|
||||||
|
|
||||||
|
cleanup_swapchain(context);
|
||||||
|
|
||||||
|
create_swapchain(context);
|
||||||
|
create_swapchain_image_views(context);
|
||||||
|
create_color_resource(context);
|
||||||
|
create_depth_resources(context);
|
||||||
|
create_framebuffers(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cleanup swapchain
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void cleanup_swapchain(struct graphics_context_t* context)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
destroy_color_resource(context);
|
||||||
|
destroy_depth_resource(context);
|
||||||
|
for (i = 0; i < context->swapchain_images_count; i++) {
|
||||||
|
vkDestroyFramebuffer(context->device,
|
||||||
|
context->swapchain_framebuffers[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < context->swapchain_images_count; i++) {
|
||||||
|
vkDestroyImageView(context->device, context->swapchain_image_views[i],
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroySwapchainKHR(context->device, context->swapchain, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_err_t create_swapchain_and_framebuffers(struct graphics_context_t* context)
|
||||||
|
{
|
||||||
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||||
|
|
||||||
|
STATUS_CHECK(create_swapchain(context));
|
||||||
|
STATUS_CHECK(create_swapchain_image_views(context));
|
||||||
|
STATUS_CHECK(create_framebuffers(context));
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef VULKAN_SWAPCHAIN_H
|
||||||
|
#define VULKAN_SWAPCHAIN_H
|
||||||
|
|
||||||
|
#include "utilities/commons.h"
|
||||||
|
#include "graphics_context.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cleanup swapchain
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void cleanup_swapchain(struct graphics_context_t* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Recreates swapchain
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void recreate_swapchain(struct graphics_context_t* context);
|
||||||
|
|
||||||
|
#endif /* VULKAN_SWAPCHAIN_H */
|
||||||
+20
-39
@@ -10,20 +10,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
#include "locale_window.h"
|
#include "utilities/localization.h"
|
||||||
#include "rse_window_errors.h"
|
#include "window_errors.h"
|
||||||
#include "src/vulkan_commons.h"
|
|
||||||
#include "utilities/logger.h"
|
#include "utilities/logger.h"
|
||||||
#include "utilities/rse_errors_common.h"
|
#include "utilities/errors_common.h"
|
||||||
#include "vulkan/vulkan_core.h"
|
#include "vulkan/vulkan_core.h"
|
||||||
#include "vulkan_base.h"
|
#include "vulkan_base.h"
|
||||||
|
|
||||||
GLFWwindow *g_window_handle = NULL;
|
|
||||||
uint8_t g_is_frambuffer_resized = 0U;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief GLFW error callback
|
* @brief GLFW error callback
|
||||||
*
|
*
|
||||||
@@ -58,26 +53,27 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
|
|||||||
|
|
||||||
static void framebuffer_resized_callback(GLFWwindow* window, int width, int height)
|
static void framebuffer_resized_callback(GLFWwindow* window, int width, int height)
|
||||||
{
|
{
|
||||||
|
bool* is_frambuffer_resized = (bool*)glfwGetWindowUserPointer(window);
|
||||||
(void)window;
|
(void)window;
|
||||||
(void)width;
|
(void)width;
|
||||||
(void)height;
|
(void)height;
|
||||||
g_is_frambuffer_resized = 1;
|
*is_frambuffer_resized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rse_err_t window_init()
|
rse_err_t window_init(GLFWwindow* window_handle, bool* is_framebuffer_resized)
|
||||||
{
|
{
|
||||||
/* Initiliaze GLFW AP */
|
/* Initiliaze GLFW AP */
|
||||||
if (GLFW_TRUE != glfwInit())
|
if (GLFW_TRUE != glfwInit())
|
||||||
{
|
{
|
||||||
LOGF(window_error_messages[WINDOW_GLFW_INIT_FAILED]);
|
LOGF(_("GLFW init failed!\n"));
|
||||||
return WINDOW_ERROR_GLFW_INIT_FAILED;
|
return WINDOW_ERROR_GLFW_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Check for Vulkan support */
|
/* Check for Vulkan support */
|
||||||
if (GLFW_FALSE == glfwVulkanSupported()) {
|
if (GLFW_FALSE == glfwVulkanSupported()) {
|
||||||
LOGF(window_error_messages[WINDOW_VULKAN_NOT_SUPPORTED]);
|
LOGF(_("Unable to load Vulkan\n"));
|
||||||
return WINDOW_ERROR_VULKAN_NOT_LOADED;
|
return WINDOW_ERROR_VULKAN_NOT_LOADED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,48 +83,33 @@ rse_err_t window_init()
|
|||||||
/* Create window */
|
/* Create window */
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
|
||||||
g_window_handle = glfwCreateWindow(640, 480, "RedScarfEngine", NULL, NULL);
|
window_handle = glfwCreateWindow(640, 480, "RedScarfEngine", NULL, NULL);
|
||||||
|
|
||||||
if (NULL == g_window_handle) {
|
if (NULL == window_handle) {
|
||||||
LOGF(window_error_messages[WINDOW_NOT_CREATED]);
|
LOGF(_("Window context creation failed\n"));
|
||||||
return WINDOW_ERROR_WINDOW_NOT_CREATED;
|
return WINDOW_ERROR_WINDOW_NOT_CREATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
glfwSetKeyCallback(g_window_handle, key_callback);
|
glfwSetKeyCallback(window_handle, key_callback);
|
||||||
glfwSetFramebufferSizeCallback(g_window_handle, framebuffer_resized_callback);
|
glfwSetFramebufferSizeCallback(window_handle, framebuffer_resized_callback);
|
||||||
|
glfwSetWindowUserPointer(window_handle, is_framebuffer_resized);
|
||||||
|
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rse_err_t window_loop()
|
rse_err_t window_loop(struct graphics_context_t* context)
|
||||||
{
|
{
|
||||||
while (!glfwWindowShouldClose(g_window_handle)) {
|
while (!glfwWindowShouldClose(context->window_handle)) {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
draw_frame();
|
draw_frame(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
vkDeviceWaitIdle(g_vulkan_state.device);
|
vkDeviceWaitIdle(context->device);
|
||||||
return RSE_ERROR_NO_ERROR;
|
return RSE_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_terminate()
|
void window_terminate(GLFWwindow* window_handle)
|
||||||
{
|
{
|
||||||
glfwDestroyWindow(g_window_handle);
|
glfwDestroyWindow(window_handle);
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GLFWwindow* get_window_handle()
|
|
||||||
{
|
|
||||||
return g_window_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t is_framebuffer_resized()
|
|
||||||
{
|
|
||||||
return g_is_frambuffer_resized;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset_framebuffer_resized()
|
|
||||||
{
|
|
||||||
g_is_frambuffer_resized = 0U;
|
|
||||||
}
|
|
||||||
+12
-14
@@ -9,44 +9,42 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_WINDOW_H
|
#ifndef WINDOW_H
|
||||||
#define RSE_WINDOW_H
|
#define WINDOW_H
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
/* Vulkan header MUST be included before glfw */
|
/* Vulkan header MUST be included before glfw */
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#include "utilities/rse_commons.h"
|
#include "utilities/commons.h"
|
||||||
|
#include "graphics_context.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize window
|
* @brief Initialize window
|
||||||
*
|
*
|
||||||
|
* @param window_handle Pointer to window window_handle, that will be initialized
|
||||||
|
* @param is_framebuffer_resized Pointer to boolean, that will be set to true if framebuffer was resized
|
||||||
* @return rse_err_t WINDOW_SUCCESS on success. Possible errors:
|
* @return rse_err_t WINDOW_SUCCESS on success. Possible errors:
|
||||||
* WINDOW_VULKAN_NOT_LOADED
|
* WINDOW_VULKAN_NOT_LOADED
|
||||||
* WINDOW_WINDOW_NOT_CREATED
|
* WINDOW_WINDOW_NOT_CREATED
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
rse_err_t window_init();
|
rse_err_t window_init(GLFWwindow* window_handle, bool* is_framebuffer_resized);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Main window loop
|
* @brief Main window loop
|
||||||
*
|
*
|
||||||
* @param vulkan_state
|
* @param context Graphics context
|
||||||
* @return rse_err_t WINDOW_SUCCESS or error code
|
* @return rse_err_t WINDOW_SUCCESS or error code
|
||||||
*/
|
*/
|
||||||
rse_err_t window_loop();
|
rse_err_t window_loop(struct graphics_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Closes window and terminates GLFW
|
* @brief Closes window and terminates GLFW
|
||||||
*
|
*
|
||||||
|
* @param window_handle Pointer to window window_handle
|
||||||
*/
|
*/
|
||||||
void window_terminate();
|
void window_terminate(GLFWwindow* window_handle);
|
||||||
|
|
||||||
GLFWwindow* get_window_handle();
|
#endif /* WINDOW_H */
|
||||||
|
|
||||||
uint8_t is_framebuffer_resized(void);
|
|
||||||
void reset_framebuffer_resized(void);
|
|
||||||
|
|
||||||
#endif /* RSE_WINDOW_H */
|
|
||||||
@@ -9,16 +9,16 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_WINDOW_ERRORS_H
|
#ifndef WINDOW_ERRORS_H
|
||||||
#define RSE_WINDOW_ERRORS_H
|
#define WINDOW_ERRORS_H
|
||||||
|
|
||||||
#define RSE_WINDOW_MODULE_ID 0x0200U
|
#define RSE_WINDOW_MODULE_ID 0x0200U
|
||||||
|
|
||||||
/* Error codes */
|
/* Error codes */
|
||||||
enum rse_window_error_t {
|
enum window_error_t {
|
||||||
WINDOW_ERROR_GLFW_INIT_FAILED = RSE_WINDOW_MODULE_ID,
|
WINDOW_ERROR_GLFW_INIT_FAILED = RSE_WINDOW_MODULE_ID,
|
||||||
WINDOW_ERROR_VULKAN_NOT_LOADED,
|
WINDOW_ERROR_VULKAN_NOT_LOADED,
|
||||||
WINDOW_ERROR_WINDOW_NOT_CREATED
|
WINDOW_ERROR_WINDOW_NOT_CREATED
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* RSE_WINDOW_ERRORS_H */
|
#endif /* WINDOW_ERRORS_H */
|
||||||
@@ -6,5 +6,5 @@ target_include_directories(${PROJECT_NAME} PRIVATE
|
|||||||
${CMAKE_SOURCE_DIR})
|
${CMAKE_SOURCE_DIR})
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||||
rse_graphics
|
graphics
|
||||||
rse_utilities)
|
utilities)
|
||||||
@@ -1,19 +1,21 @@
|
|||||||
|
#include "graphics/graphics.h"
|
||||||
#include "graphics/rse_graphics.h"
|
#include "graphics/rse_graphics.h"
|
||||||
#include "utilities/rse_task.h"
|
#include "utilities/task.h"
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
rse_thread_t graphics_task;
|
thread_t graphics_task;
|
||||||
|
struct rse_graphics_context_t* context = NULL;
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
rse_graphics_init();
|
rse_graphics_init(context);
|
||||||
rse_graphics_test_function();
|
rse_graphics_test_function(context);
|
||||||
rse_create_task(&graphics_task, (thread_worker_t)rse_graphics_run, NULL);
|
create_task(&graphics_task, (thread_worker_t)rse_graphics_run, context);
|
||||||
|
|
||||||
rse_task_join(&graphics_task);
|
task_join(&graphics_task);
|
||||||
rse_task_exit();
|
task_exit();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
pushd build/red_scarf_engine/
|
||||||
|
VULKAN_SDK=${PWD}/third_party/vulkan/x86_64/ VK_LAYER_PATH=${PWD}/third_party/vulkan/x86_64/etc/vulkan/explicit_layer.d PATH=${PATH}:${PWD}/third_party/vulkan/x86_64/bin LD_LIBRARY_PATH=:${PWD}/third_party/vulkan/x86_64/lib ./RedScarfEngine
|
||||||
|
popd
|
||||||
@@ -11,24 +11,24 @@ src/main.c
|
|||||||
src/mocks/vulkan/Mockvulkan_core.c
|
src/mocks/vulkan/Mockvulkan_core.c
|
||||||
src/mocks/GLFW/Mockglfw3.c
|
src/mocks/GLFW/Mockglfw3.c
|
||||||
src/mocks/vk_mem_alloc.c
|
src/mocks/vk_mem_alloc.c
|
||||||
src/rse_math_tests.c
|
src/math_tests.c
|
||||||
src/rse_graphics_window_tests.c
|
src/graphics_window_tests.c
|
||||||
src/rse_graphics_vulkan_tests.c
|
src/graphics_vulkan_tests.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/window.c
|
${PROJECT_SOURCE_DIR}/graphics/src/window.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_base.c
|
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_base.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_pipeline.c
|
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_pipeline.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/rse_vulkan_commands.c
|
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_commands.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_buffers.c
|
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_buffers.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_descriptors.c
|
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_descriptors.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/rse_graphics.c
|
${PROJECT_SOURCE_DIR}/graphics/src/graphics.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/rse_math.c
|
${PROJECT_SOURCE_DIR}/graphics/src/math.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/mesh_controller.c
|
${PROJECT_SOURCE_DIR}/graphics/src/mesh_controller.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_commons.c
|
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_commons.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/rse_vulkan_image.c
|
${PROJECT_SOURCE_DIR}/graphics/src/vulkan_image.c
|
||||||
${PROJECT_SOURCE_DIR}/graphics/src/rse_text_renderer.c
|
${PROJECT_SOURCE_DIR}/graphics/src/text_renderer.c
|
||||||
${PROJECT_SOURCE_DIR}/utilities/src/logger.c
|
${PROJECT_SOURCE_DIR}/utilities/src/logger.c
|
||||||
${PROJECT_SOURCE_DIR}/utilities/src/file_utils.c
|
${PROJECT_SOURCE_DIR}/utilities/src/file_utils.c
|
||||||
${PROJECT_SOURCE_DIR}/utilities/src/rse_task_linux.c
|
${PROJECT_SOURCE_DIR}/utilities/src/task_linux.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#include "unity.h"
|
#include "unity.h"
|
||||||
#include "vulkan/vulkan_core.h"
|
#include "vulkan/vulkan_core.h"
|
||||||
|
|
||||||
static void test_rse_graphics_init(void)
|
static void test_rse_rse_graphics_init(void)
|
||||||
{
|
{
|
||||||
VkExtensionProperties extenstion_properties[1];
|
VkExtensionProperties extenstion_properties[1];
|
||||||
VkLayerProperties layer_properties[1];
|
VkLayerProperties layer_properties[1];
|
||||||
@@ -44,7 +44,7 @@ static void test_rse_graphics_init(void)
|
|||||||
vkEnumerateInstanceLayerProperties_ExpectAnyArgsAndReturn(VK_SUCCESS);
|
vkEnumerateInstanceLayerProperties_ExpectAnyArgsAndReturn(VK_SUCCESS);
|
||||||
vkEnumerateInstanceLayerProperties_ReturnThruPtr_pPropertyCount(&count);
|
vkEnumerateInstanceLayerProperties_ReturnThruPtr_pPropertyCount(&count);
|
||||||
/* TODO: Currently, due to the implementation, layer_properties that we get here is NULL.
|
/* TODO: Currently, due to the implementation, layer_properties that we get here is NULL.
|
||||||
* This is because mocked rse_malloc does nothing. Fix this somehow */
|
* This is because mocked rse_rse_malloc does nothing. Fix this somehow */
|
||||||
vkEnumerateInstanceLayerProperties_ReturnThruPtr_pProperties(layer_properties);
|
vkEnumerateInstanceLayerProperties_ReturnThruPtr_pProperties(layer_properties);
|
||||||
|
|
||||||
vkEnumerateInstanceExtensionProperties_ExpectAnyArgsAndReturn(VK_SUCCESS);
|
vkEnumerateInstanceExtensionProperties_ExpectAnyArgsAndReturn(VK_SUCCESS);
|
||||||
@@ -52,10 +52,10 @@ static void test_rse_graphics_init(void)
|
|||||||
vkEnumerateInstanceExtensionProperties_ReturnThruPtr_pPropertyCount(&count);
|
vkEnumerateInstanceExtensionProperties_ReturnThruPtr_pPropertyCount(&count);
|
||||||
vkEnumerateInstanceExtensionProperties_ReturnThruPtr_pProperties(extenstion_properties);
|
vkEnumerateInstanceExtensionProperties_ReturnThruPtr_pProperties(extenstion_properties);
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL(RSE_ERROR_NO_ERROR, rse_graphics_init());
|
TEST_ASSERT_EQUAL(RSE_ERROR_NO_ERROR, rse_rse_graphics_init());
|
||||||
}
|
}
|
||||||
|
|
||||||
void rse_graphics_vulkan_tests(void)
|
void rse_graphics_vulkan_tests(void)
|
||||||
{
|
{
|
||||||
RUN_TEST(test_rse_graphics_init);
|
RUN_TEST(test_rse_rse_graphics_init);
|
||||||
}
|
}
|
||||||
@@ -9,9 +9,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_GRAPHICS_VULKAN_TESTS_H
|
#ifndef GRAPHICS_VULKAN_TESTS_H
|
||||||
#define RSE_GRAPHICS_VULKAN_TESTS_H
|
#define GRAPHICS_VULKAN_TESTS_H
|
||||||
|
|
||||||
void rse_graphics_vulkan_tests(void);
|
void rse_graphics_vulkan_tests(void);
|
||||||
|
|
||||||
#endif // RSE_GRAPHICS_VULKAN_TESTS_H
|
#endif // GRAPHICS_VULKAN_TESTS_H
|
||||||
@@ -9,9 +9,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_GRAPHICS_TESTS_H
|
#ifndef GRAPHICS_TESTS_H
|
||||||
#define RSE_GRAPHICS_TESTS_H
|
#define GRAPHICS_TESTS_H
|
||||||
|
|
||||||
void rse_graphics_window_tests(void);
|
void rse_graphics_window_tests(void);
|
||||||
|
|
||||||
#endif // RSE_GRAPHICS_TESTS_H
|
#endif // GRAPHICS_TESTS_H
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
|
||||||
|
|
||||||
add_library(rse_utilities SHARED)
|
add_library(utilities SHARED)
|
||||||
|
|
||||||
target_include_directories(rse_utilities PRIVATE
|
target_include_directories(utilities PRIVATE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${PROJECT_SOURCE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_sources(rse_utilities PRIVATE
|
target_sources(utilities PRIVATE
|
||||||
src/file_utils.c
|
src/file_utils.c
|
||||||
src/logger.c
|
src/logger.c
|
||||||
src/rse_task_linux.c
|
src/task_linux.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(rse_utilities PRIVATE
|
target_link_libraries(utilities PRIVATE
|
||||||
pthread)
|
pthread)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file rse_commons.h
|
* @file commons.h
|
||||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
* @brief Common functionality for all modules
|
* @brief Common functionality for all modules
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
@@ -9,11 +9,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_COMMONS_H
|
#ifndef COMMONS_H
|
||||||
#define RSE_COMMONS_H
|
#define COMMONS_H
|
||||||
|
|
||||||
|
#include "utilities/logger.h"
|
||||||
|
|
||||||
#include "utilities/locale_common.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Macro for allocating memory and checking it on the same line
|
* @brief Macro for allocating memory and checking it on the same line
|
||||||
@@ -23,17 +25,19 @@
|
|||||||
#define rse_malloc(ptr, size) \
|
#define rse_malloc(ptr, size) \
|
||||||
ptr = malloc(size); \
|
ptr = malloc(size); \
|
||||||
if (ptr == NULL) { \
|
if (ptr == NULL) { \
|
||||||
LOGF(common_messages[COMMON_ERROR_MEMORY_ALLOCATION_FAILED]); \
|
LOGF(_("Memory allocation failed\n")); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define rse_free(ptr) free(ptr);
|
#define rse_free(ptr) free(ptr);
|
||||||
|
|
||||||
#define rse_memcpy(dst, src, size) memcpy(dst, src, size);
|
#define rse_memcpy(dst, src, size) memcpy(dst, src, size);
|
||||||
|
#define rse_memset(ptr, value, size) memset(ptr, value, size);
|
||||||
#else
|
#else
|
||||||
#define rse_malloc(ptr, size) ptr = NULL;
|
#define rse_malloc(ptr, size) ptr = NULL;
|
||||||
#define rse_free(ptr)
|
#define rse_free(ptr)
|
||||||
#define rse_memcpy(dst, src, size)
|
#define rse_memcpy(dst, src, size)
|
||||||
|
#define rse_memset
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,4 +46,4 @@ if (ptr == NULL) { \
|
|||||||
*/
|
*/
|
||||||
typedef uint32_t rse_err_t;
|
typedef uint32_t rse_err_t;
|
||||||
|
|
||||||
#endif /* RSE_COMMONS_H */
|
#endif /* COMMONS_H */
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file rse_errors_common.h
|
* @file errors_common.h
|
||||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
* @brief Common error messages, that can appear in any module
|
* @brief Common error messages, that can appear in any module
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_ERRORS_COMMON_H
|
#ifndef ERRORS_COMMON_H
|
||||||
|
|
||||||
/* Macro for checking status of function execution in initVulkan. Created to avoid writing boilerplate code */
|
/* Macro for checking status of function execution in initVulkan. Created to avoid writing boilerplate code */
|
||||||
#define STATUS_CHECK(FUNC) \
|
#define STATUS_CHECK(FUNC) \
|
||||||
@@ -20,11 +20,12 @@
|
|||||||
|
|
||||||
#define RSE_COMMON_MODULE_ID 0x0100U
|
#define RSE_COMMON_MODULE_ID 0x0100U
|
||||||
|
|
||||||
enum rse_common_error_t
|
enum common_error_t
|
||||||
{
|
{
|
||||||
RSE_ERROR_NO_ERROR = RSE_COMMON_MODULE_ID,
|
RSE_ERROR_NO_ERROR = RSE_COMMON_MODULE_ID,
|
||||||
|
RSE_ERROR_ALREADY_INITIALIZED,
|
||||||
RSE_COMMON_ERROR_MALLLOC_FAILED,
|
RSE_COMMON_ERROR_MALLLOC_FAILED,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RSE_ERRORS_COMMON_H
|
#define ERRORS_COMMON_H
|
||||||
#endif /* RSE_ERRORS_COMMON_H */
|
#endif /* ERRORS_COMMON_H */
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef RSE_FILE_UTILS_H
|
#ifndef FILE_UTILS_H
|
||||||
#define RSE_FILE_UTILS_H
|
#define FILE_UTILS_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@@ -11,9 +11,9 @@
|
|||||||
* @param bytes_count Returned bytes count
|
* @param bytes_count Returned bytes count
|
||||||
* @param buffer Returned filled buffer
|
* @param buffer Returned filled buffer
|
||||||
*/
|
*/
|
||||||
void rse_read_file(const char* file_path, long* bytes_count, char* buffer);
|
void read_file(const char* file_path, size_t* bytes_count, char* buffer);
|
||||||
|
|
||||||
void rse_write_to_file(const char* file_name, long bytes_count, char* buffer);
|
void write_to_file(const char* file_name, size_t bytes_count, char* buffer);
|
||||||
|
|
||||||
#endif /* RSE_FILE_UTILS_H */
|
#endif /* FILE_UTILS_H */
|
||||||
|
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* @file linked_list.h
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-05-01
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LINKED_LIST_H
|
||||||
|
#define LINKED_LIST_H
|
||||||
|
|
||||||
|
#include "utilities/commons.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define a linked list structure
|
||||||
|
*
|
||||||
|
* @param name Name of the linked list structure
|
||||||
|
* @param type Type of the data stored in the linked list
|
||||||
|
* @return struct name { type data; struct name *next; }
|
||||||
|
* @note This macro defines a linked list structure with a given name and data type
|
||||||
|
*/
|
||||||
|
#define RSE_LINKED_LIST_DEFINE(name, type) \
|
||||||
|
struct name { \
|
||||||
|
type data; \
|
||||||
|
struct name *next; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_PUSH_FRONT(list, value) \
|
||||||
|
typeof(list) new_node = NULL; \
|
||||||
|
rse_malloc(new_node, sizeof(*(list))); \
|
||||||
|
new_node->data = value; \
|
||||||
|
new_node->next = list; \
|
||||||
|
list = new_node
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_PUSH_BACK(list, value) \
|
||||||
|
typeof(list) new_node = NULL; \
|
||||||
|
rse_malloc(new_node, sizeof(*(list))); \
|
||||||
|
new_node->data = value; \
|
||||||
|
new_node->next = NULL; \
|
||||||
|
if (list == NULL) { \
|
||||||
|
list = new_node; \
|
||||||
|
} else { \
|
||||||
|
typeof(list) current = list; \
|
||||||
|
while (current->next != NULL) { \
|
||||||
|
current = current->next; \
|
||||||
|
} \
|
||||||
|
current->next = new_node; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_POP_FRONT(list) \
|
||||||
|
if (list != NULL) { \
|
||||||
|
typeof(list) temp = list; \
|
||||||
|
list = list->next; \
|
||||||
|
rse_free(temp); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_POP_BACK(list) \
|
||||||
|
if (list != NULL) { \
|
||||||
|
if (list->next == NULL) { \
|
||||||
|
rse_free(list); \
|
||||||
|
list = NULL; \
|
||||||
|
} else { \
|
||||||
|
typeof(list) *current = list; \
|
||||||
|
while (current->next->next != NULL) { \
|
||||||
|
current = current->next; \
|
||||||
|
} \
|
||||||
|
rse_free(current->next); \
|
||||||
|
current->next = NULL; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_FRONT(list) \
|
||||||
|
list->data
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_BACK(list) \
|
||||||
|
if (list != NULL) { \
|
||||||
|
typeof(list) *current = list; \
|
||||||
|
while (current->next != NULL) { \
|
||||||
|
current = current->next; \
|
||||||
|
} \
|
||||||
|
current->data; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_IS_EMPTY(list) \
|
||||||
|
list == NULL
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_SIZE(list) \
|
||||||
|
({ \
|
||||||
|
int size = 0; \
|
||||||
|
typeof(list) current = list; \
|
||||||
|
while (current != NULL) { \
|
||||||
|
size++; \
|
||||||
|
current = current->next; \
|
||||||
|
} \
|
||||||
|
size; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_CLEAR(list) \
|
||||||
|
while (list != NULL) { \
|
||||||
|
typeof(list) temp = list; \
|
||||||
|
list = list->next; \
|
||||||
|
rse_free(temp); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_FOREACH(list, i) \
|
||||||
|
for (typeof(list) i = list; i != NULL; i = i->next)
|
||||||
|
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_FOREACH_REVERSE(list, i) \
|
||||||
|
for (typeof(list) i = list; i != NULL; i = i->next)
|
||||||
|
|
||||||
|
#define RSE_LINKED_LIST_TO_ARRAY(list, array) \
|
||||||
|
({ \
|
||||||
|
int size = RSE_LINKED_LIST_SIZE(list); \
|
||||||
|
rse_malloc(array, size * sizeof(*(list))); \
|
||||||
|
int i = 0; \
|
||||||
|
RSE_LINKED_LIST_FOREACH(list, current) { \
|
||||||
|
array[i++] = current->data; \
|
||||||
|
} \
|
||||||
|
size; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif // LINKED_LIST_H
|
||||||
|
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_LOCALE_COMMON_H
|
#ifndef LOCALE_COMMON_H
|
||||||
#define RSE_LOCALE_COMMON_H
|
#define LOCALE_COMMON_H
|
||||||
|
|
||||||
#include "localization.h"
|
#include "localization.h"
|
||||||
|
|
||||||
@@ -28,4 +28,4 @@ static const char common_messages_nolocale[LAST_LANGUAGE][COMMON_ERROR_LAST_MESS
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* RSE_LOCALE_COMMON_H */
|
#endif /* LOCALE_COMMON_H */
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file localization.h
|
* @file localization.h
|
||||||
* @author Piotr Krygier (everyonencancode@gmail.com)
|
* @author Piotr Krygier (everyonencancode@gmail.com)
|
||||||
* @brief Simple localization header
|
* @brief Simple localization header. Gettext is used for localization
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
* @date 2022-02-15
|
* @date 2022-02-15
|
||||||
*
|
*
|
||||||
@@ -9,20 +9,12 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_LOCALIZATION_H
|
#ifndef LOCALIZATION_H
|
||||||
#define RSE_LOCALIZATION_H
|
#define LOCALIZATION_H
|
||||||
|
|
||||||
#define SELECTED_LANGUAGE EN_US
|
#include <libintl.h>
|
||||||
#define MAX_MESSAGE_LENGHT 128
|
|
||||||
|
|
||||||
/**
|
/* Enable localization */
|
||||||
* @brief Available languages
|
#define _(STRING) gettext(STRING)
|
||||||
*
|
|
||||||
*/
|
|
||||||
enum languages_t
|
|
||||||
{
|
|
||||||
EN_US = 0,
|
|
||||||
LAST_LANGUAGE
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* RSE_LOCALIZATION_H */
|
#endif /* LOCALIZATION_H */
|
||||||
+4
-4
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file log.h
|
* @file logger.h
|
||||||
* @author Piotr Krygier (everyonencancode@gmail.com)
|
* @author Piotr Krygier (everyonencancode@gmail.com)
|
||||||
* @brief Logging interfaces
|
* @brief Logging interfaces
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RSE_LOGGER_H
|
#ifndef LOGGER_H
|
||||||
#define RSE_LOGGER_H
|
#define LOGGER_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -42,4 +42,4 @@ enum log_level_t
|
|||||||
|
|
||||||
void _log_log(unsigned int level, const char* file, int line, const char* fmt, ...);
|
void _log_log(unsigned int level, const char* file, int line, const char* fmt, ...);
|
||||||
|
|
||||||
#endif /* RSE_LOGGER_H */
|
#endif /* LOGGER_H */
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file rse_task.h
|
|
||||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
|
||||||
* @brief Threads wrapper
|
|
||||||
* @version 0.1
|
|
||||||
* @date 2023-08-14
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RSE_THREADS_H
|
|
||||||
#define RSE_THREADS_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
#include <pthread.h>
|
|
||||||
typedef pthread_t rse_thread_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef void*(*thread_worker_t)(void*);
|
|
||||||
|
|
||||||
uint8_t rse_create_task(rse_thread_t* thread_id, thread_worker_t callback, void* args);
|
|
||||||
uint8_t rse_task_join(rse_thread_t* thread_id);
|
|
||||||
void rse_task_exit(void);
|
|
||||||
|
|
||||||
#endif /* RSE_THREADS_H */
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
void rse_read_file(const char* file_name, long* bytes_count, char* buffer)
|
void read_file(const char* file_name, size_t* bytes_count, char* buffer)
|
||||||
{
|
{
|
||||||
FILE* file;
|
FILE* file;
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ void rse_read_file(const char* file_name, long* bytes_count, char* buffer)
|
|||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rse_write_to_file(const char* file_name, long bytes_count, char* buffer)
|
void write_to_file(const char* file_name, size_t bytes_count, char* buffer)
|
||||||
{
|
{
|
||||||
FILE* file;
|
FILE* file;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "rse_task.h"
|
#include "task.h"
|
||||||
|
|
||||||
uint8_t rse_create_task(rse_thread_t* thread_id, thread_worker_t callback, void* args)
|
uint8_t create_task(thread_t* thread_id, thread_worker_t callback, void* args)
|
||||||
{
|
{
|
||||||
uint8_t result = 0;
|
uint8_t result = 0;
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ uint8_t rse_create_task(rse_thread_t* thread_id, thread_worker_t callback, void*
|
|||||||
return result; //TODO: Do error handling
|
return result; //TODO: Do error handling
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t rse_task_join(rse_thread_t* thread_id)
|
uint8_t task_join(thread_t* thread_id)
|
||||||
{
|
{
|
||||||
uint8_t result = 0;
|
uint8_t result = 0;
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ uint8_t rse_task_join(rse_thread_t* thread_id)
|
|||||||
return result; //TODO: Do error handling
|
return result; //TODO: Do error handling
|
||||||
}
|
}
|
||||||
|
|
||||||
void rse_task_exit()
|
void task_exit()
|
||||||
{
|
{
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* @file stack.h
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-05-01
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STACK_H
|
||||||
|
#define STACK_H
|
||||||
|
|
||||||
|
#define RSE_STACK_DEFINE(name, type, size) \
|
||||||
|
struct name { \
|
||||||
|
type data[size]; \
|
||||||
|
int top; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RSE_STACK_PUSH(stack, value) \
|
||||||
|
stack.data[++stack.top] = value
|
||||||
|
|
||||||
|
#define RSE_STACK_POP(stack) \
|
||||||
|
stack.data[stack.top--]
|
||||||
|
|
||||||
|
#define RSE_STACK_TOP(stack) \
|
||||||
|
stack.data[stack.top]
|
||||||
|
|
||||||
|
#define RSE_STACK_IS_EMPTY(stack) \
|
||||||
|
stack.top == -1
|
||||||
|
|
||||||
|
#define RSE_STACK_IS_FULL(stack, size) \
|
||||||
|
stack.top == size - 1
|
||||||
|
|
||||||
|
#define RSE_STACK_INIT(stack) \
|
||||||
|
stack.top = -1
|
||||||
|
|
||||||
|
#define RSE_STACK_SIZE(stack) \
|
||||||
|
stack.top + 1
|
||||||
|
|
||||||
|
#define RSE_STACK_CLEAR(stack) \
|
||||||
|
stack.top = -1
|
||||||
|
|
||||||
|
#endif // STACK_H
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* @file task.h
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief Threads wrapper
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-08-14
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef THREADS_H
|
||||||
|
#define THREADS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <pthread.h>
|
||||||
|
typedef pthread_t thread_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void*(*thread_worker_t)(void*);
|
||||||
|
|
||||||
|
uint8_t create_task(thread_t* thread_id, thread_worker_t callback, void* args);
|
||||||
|
uint8_t task_join(thread_t* thread_id);
|
||||||
|
void task_exit(void);
|
||||||
|
|
||||||
|
#endif /* THREADS_H */
|
||||||
Reference in new issue
Block a user