Continue working on pipeline

This commit is contained in:
Piotr Krygier committed 2025-06-20 13:44:33 +02:00
1 parent 45be08019e
commit bd05c03a12
28 files changed
+439 -409

No files matched your search

+13 -1
View File
@@ -1,2 +1,14 @@
CompileFlags:
Add: -ferror-limit=1000
Add: [
"-ferror-limit=0",
"-Wall",
"-Wpedantic",
"-Werror",
"-Wno-gnu-statement-expression",
"-I/home/nonadmin/workspace/RedScarfEngine/",
"-I/home/nonadmin/workspace/RedScarfEngine/graphics",
"-I/home/nonadmin/workspace/RedScarfEngine/utilites",
"-I/home/nonadmin/workspace/RedScarfEngine/third_party/include",
"-I/home/nonadmin/.conan2/p/stb19b77fb56ffd7/p/include/"
]
+1
View File
@@ -6,6 +6,7 @@ project("RedScarfEngine"
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
add_subdirectory(red_scarf_engine)
add_subdirectory(utilities)
+1 -1
View File
@@ -4,6 +4,6 @@
"conan": {}
},
"include": [
"build\\CMakePresets.json"
"build/CMakePresets.json"
]
}
+6
View File
@@ -1,9 +1,15 @@
[requires]
vulkan-headers/1.4.309.0
vulkan-loader/1.4.309.0
libgettext/0.22
glfw/3.4
freetype/2.13.3
stb/cci.20240531
sdl/3.2.14
[generators]
CMakeDeps
CMakeToolchain
[options]
sdl/*:wayland=False
+12 -5
View File
@@ -1,8 +1,12 @@
find_package(VulkanHeaders REQUIRED)
find_package(VulkanLoader REQUIRED)
# find_package(vulkan-validationlayers)
find_package(glfw3 REQUIRED)
find_package(freetype REQUIRED)
find_package(stb REQUIRED)
find_package(SDL3 REQUIRED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -g")
add_library(graphics SHARED)
@@ -11,9 +15,8 @@ ${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/third_party/include/
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}
${vma_INCLUDE_DIR}
${glfw3_INCLUDE_DIR}
${stb_INCLUDE_DIR}
${stb_INCLUDE_DIR}
${freetype_INCLUDE_DIR}
)
target_sources(graphics PRIVATE
@@ -21,10 +24,10 @@ src/vma_port.cpp
src/window.c
src/vulkan_base.c
src/vulkan_commands.c
src/vulkan_buffers.c
src/rse_graphics.c
src/math.c
src/mesh_controller.c
src/vulkan_buffers.c
src/vulkan_commons.c
src/vulkan_image.c
src/vulkan_render_pass.c
@@ -37,6 +40,10 @@ src/descriptor_builder.c
target_link_libraries(graphics PUBLIC
utilities
vulkan-headers::vulkan-headers
Vulkan::Loader
# vulkan-validationlayers::vulkan-validationlayers
glfw
Freetype::Freetype
stb::stb
sdl::sdl
)
+1 -1
View File
@@ -19,7 +19,7 @@ rse_err_t rse_graphics_init(struct rse_graphics_context_t** context);
*
* @return rse_err_t RSE_ERROR_NO_ERROR on success
*/
rse_err_t rse_graphics_run(struct rse_graphics_context_t* context);
int rse_graphics_run(void* arg);
/**
+1 -1
View File
@@ -1,7 +1,7 @@
#version 450
#extension GL_EXT_nonuniform_qualifier : enable
layout(set = 1, binding = 1) uniform sampler2D texSampler[];
layout(set = 0, binding = 1) uniform sampler2D texSampler[];
layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTexCoord;
+105 -11
View File
@@ -11,9 +11,11 @@
#include "descriptor_builder.h"
#include <stddef.h>
#include <stdint.h>
#include "src/graphics_context.h"
#include "src/vulkan_commons.h"
#include "utilities/commons.h"
#include "utilities/errors_common.h"
#include "utilities/linked_list.h"
@@ -30,7 +32,7 @@ struct descriptor_t
VkDescriptorType type;
uint32_t descriptor_count;
VkShaderStageFlags shader_stages;
VkSampler immutable_sampler;
VkSampler* immutable_sampler;
};
RSE_LINKED_LIST_DEFINE(descriptor_set_list_t, struct descriptor_t);
@@ -40,6 +42,7 @@ struct descriptor_set_handle_t
VkDescriptorSet descriptor_sets;
VkDescriptorPool descriptor_pool;
VkDescriptorSetLayout descriptor_sets_layout;
struct descriptor_set_list_t* descriptor_set_list;
};
/* FIXME: When new descriptors are introduced to Vulkan, this enum has to be
@@ -66,8 +69,38 @@ enum descriptor_type_id_t
DESCRIPTOR_TYPE_ID_MAX_ENUM,
};
rse_err_t descriptor_add_set(struct descriptor_set_list_t* descriptor_set_list, uint32_t binding, VkDescriptorType type,
uint32_t descriptor_count, VkShaderStageFlags shader_stages, VkSampler sampler)
rse_err_t descriptor_initialize_handle(struct descriptor_set_handle_t **descriptor_set_handle)
{
if (NULL != *descriptor_set_handle) {
LOGE(_("Desciptor already initialized\n"));
return RSE_ERROR_INVALID_PARAM;
}
rse_malloc(*descriptor_set_handle, sizeof(struct descriptor_set_handle_t));
(*descriptor_set_handle)->descriptor_set_list = NULL;
return RSE_ERROR_NO_ERROR;
}
rse_err_t descriptor_free_handle(struct descriptor_set_handle_t **descriptor_set_handle)
{
if (NULL == *descriptor_set_handle) {
LOGE(_("Provided NULL handle\n"));
return RSE_ERROR_INVALID_PARAM;
}
RSE_LINKED_LIST_CLEAR((*descriptor_set_handle)->descriptor_set_list);
rse_free(*descriptor_set_handle);
*descriptor_set_handle = NULL;
return RSE_ERROR_NO_ERROR;
}
rse_err_t descriptor_add_set(struct descriptor_set_handle_t* descriptor_set_handle, uint32_t binding, VkDescriptorType type,
uint32_t descriptor_count, VkShaderStageFlags shader_stages, VkSampler* sampler)
{
struct descriptor_t descriptor_sets = {.binding = binding,
.type = type,
@@ -75,13 +108,12 @@ rse_err_t descriptor_add_set(struct descriptor_set_list_t* descriptor_set_list,
.shader_stages = shader_stages,
.immutable_sampler = sampler};
RSE_LINKED_LIST_PUSH_BACK(descriptor_set_list, descriptor_sets);
RSE_LINKED_LIST_PUSH_BACK(descriptor_set_handle->descriptor_set_list, descriptor_sets);
return RSE_ERROR_NO_ERROR;
}
rse_err_t descriptors_build(struct graphics_context_t* context, struct descriptor_set_list_t* descriptors,
struct descriptor_set_handle_t* descriptor_set_handle)
rse_err_t descriptors_build(struct graphics_context_t* context, struct descriptor_set_handle_t* descriptor_set_handle)
{
size_t iterator = 0U;
size_t pool_size_count = 0U;
@@ -104,8 +136,20 @@ rse_err_t descriptors_build(struct graphics_context_t* context, struct descripto
return RSE_ERROR_NULL_POINTER;
}
if (NULL == descriptor_set_handle) {
LOGF(_("Descriptor set handle is null.\n"));
return RSE_ERROR_NULL_POINTER;
}
if (RSE_LINKED_LIST_IS_EMPTY(descriptor_set_handle->descriptor_set_list)) {
LOGF(_("Provided empty descriptors list\n"));
return RSE_ERROR_NULL_POINTER;
}
iterator = 0U;
RSE_LINKED_LIST_FOREACH(descriptors, descriptor)
RSE_LINKED_LIST_FOREACH(descriptor_set_handle->descriptor_set_list, descriptor)
{
switch (descriptor->data.type) {
case VK_DESCRIPTOR_TYPE_SAMPLER:
@@ -195,6 +239,7 @@ rse_err_t descriptors_build(struct graphics_context_t* context, struct descripto
layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_create_info.bindingCount = iterator;
layout_create_info.pBindings = layout_bindings;
if (VK_SUCCESS != vkCreateDescriptorSetLayout(context->device, &layout_create_info, NULL, &set_layout)) {
LOGF(_("Failed to create descriptor sets layout\n"));
return VULKAN_ERROR_DESCRIPTOR_SET_LAYOUT_CREATION_FAILED;
@@ -204,7 +249,7 @@ rse_err_t descriptors_build(struct graphics_context_t* context, struct descripto
* What I'm doing here is calculating minimum viable number of pool max sets. This is a bit tricky, as
* (unintuitively) we have to select the MINIMUM number of sets, not maximum. This makes sense, but is difficult to
* wrap headr around */
RSE_LINKED_LIST_FOREACH(descriptors, descriptor)
RSE_LINKED_LIST_FOREACH(descriptor_set_handle->descriptor_set_list, descriptor)
{
switch (descriptor->data.type) {
case VK_DESCRIPTOR_TYPE_SAMPLER:
@@ -308,10 +353,10 @@ rse_err_t descriptors_build(struct graphics_context_t* context, struct descripto
}
/* Allocate descriptors from the pool */
alloc_info.descriptorPool = &descriptor_pool;
alloc_info.descriptorPool = descriptor_pool;
alloc_info.descriptorSetCount =
pool_max_sets; /* TODO: Always allocating maximum number of sets? This might get weird */
alloc_info.pSetLayouts = set_layout;
alloc_info.pSetLayouts = &set_layout;
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
if (VK_SUCCESS != vkAllocateDescriptorSets(context->device, &alloc_info, &descriptor_sets)) {
@@ -323,7 +368,56 @@ rse_err_t descriptors_build(struct graphics_context_t* context, struct descripto
descriptor_set_handle->descriptor_sets = descriptor_sets;
descriptor_set_handle->descriptor_sets_layout = set_layout;
context->descriptor_sets = descriptor_set_handle;
return RSE_ERROR_NO_ERROR;
}
rse_err_t descriptor_get_layouts()
rse_err_t descriptor_get_layout(struct descriptor_set_handle_t* descriptor_set_handle,
VkDescriptorSetLayout* descriptor_sets_layout)
{
if (NULL == descriptor_set_handle->descriptor_sets_layout) {
LOGF(_("Requested descriptor set layout is NULL\n"));
return RSE_ERROR_NULL_POINTER;
}
*descriptor_sets_layout = descriptor_set_handle->descriptor_sets_layout;
return RSE_ERROR_NO_ERROR;
}
rse_err_t descriptor_get_vkhandle(struct descriptor_set_handle_t* descriptor_set_handle, VkDescriptorSet* descriptor_set)
{
if (NULL == descriptor_set_handle) {
LOGF(_("Provided handle is NULL\n"));
return RSE_ERROR_NULL_POINTER;
}
*descriptor_set = descriptor_set_handle->descriptor_sets;
return RSE_ERROR_NO_ERROR;
}
rse_err_t descriptor_attach_buffer(struct graphics_context_t* context, struct descriptor_set_handle_t* descriptor_set_handle, struct vulkan_buffer_t* buffer, uint32_t binding, VkDescriptorType type)
{
VkDescriptorBufferInfo buffer_info = {0};
VkWriteDescriptorSet write_set = {0};
buffer_info.buffer = buffer->buffer;
buffer_info.offset = 0U;
buffer_info.range = buffer->allocated_size;
write_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_set.pBufferInfo = &buffer_info;
write_set.dstSet = descriptor_set_handle->descriptor_sets;
write_set.dstBinding = binding;
write_set.dstArrayElement = 0U;
write_set.descriptorType = type;
write_set.descriptorCount = 1;
vkUpdateDescriptorSets(context->device, 1U, &write_set, 0, NULL);
return RSE_ERROR_NO_ERROR;
}
+43 -6
View File
@@ -12,13 +12,33 @@
#ifndef DESCRIPTOR_BUILDER_H
#define DESCRIPTOR_BUILDER_H
#include <vulkan/vulkan_core.h>
#include "src/graphics_context.h"
struct descriptor_set_handle_t;
struct descriptor_set_list_t;
/**
* @brief Initialize new descriptor set handle
*
* @param descriptor_set_handle Handle to initialize
* #return RSE_ERROR_NO_ERROR on success
*/
rse_err_t descriptor_initialize_handle(struct descriptor_set_handle_t **descriptor_set_handle);
/**
* @brief Destroy descritptor set handle
*
* @param descriptor_set_handle Handle to destroy
* @return RSE_ERROR_NO_ERROR on succes
*/
rse_err_t descriptor_free_handle(struct descriptor_set_handle_t **descriptor_set_handle);
/**
* @brief Add descriptor set to provided list
*
* @param descriptor_set_list List to be filled
* @param descriptor_set_handle Handle for given descriptor set
* @param binding Descriptors binding
* @param type Type of descriptors
* @param descriptor_count Number of descriptors in this set
@@ -26,18 +46,35 @@ struct descriptor_set_list_t;
* @param sampler If descriptor set is a sampler, provide it here
* @return rse_err_t RSE_ERROR_NO_ERROR on success, error code on failure
*/
rse_err_t descriptor_add_set(struct descriptor_set_list_t* descriptor_set_list, uint32_t binding, VkDescriptorType type,
uint32_t descriptor_count, VkShaderStageFlags shader_stages, VkSampler sampler);
rse_err_t descriptor_add_set(struct descriptor_set_handle_t* descriptor_set_handle, uint32_t binding, VkDescriptorType type,
uint32_t descriptor_count, VkShaderStageFlags shader_stages, VkSampler* sampler);
/**
* @brief Allocate descriptor sets from provided list. The data will be stored in opaque descriptor handle
*
* @param context Graphics context
* @param descriptors List of descriptors to build descriptor handle from.
* @param descriptor_set_handle Opaque descriptor handle object.
* @return rse_err_t RSE_ERROR_NO_ERROR on success, error code on failure
*/
rse_err_t descriptors_build(struct graphics_context_t* context, struct descriptor_set_list_t* descriptors,
struct descriptor_set_handle_t* descriptor_set_handle);
rse_err_t descriptors_build(struct graphics_context_t* context, struct descriptor_set_handle_t* descriptor_set_handle);
/**
* @brief Return descriptor set layouts from descritptor handle
*
* @param descriptor_set_handle Handle for descriptor set
* @return rse_err_t RSE_ERROR_NO_ERROR on success
*/
rse_err_t descriptor_get_layout(struct descriptor_set_handle_t* descriptor_set_handle,
VkDescriptorSetLayout* descritptor_sets_layout);
/**
* @brief Get VkDescriptorSet from descriptor handle
*
* @param descriptor_set_handle_t Handle to get VkDescriptorSet from
* @return rse_err_t RSE_ERROR_NO_ERROR on success
*/
rse_err_t descriptor_get_vkhandle(struct descriptor_set_handle_t* descriptor_set_handle, VkDescriptorSet* descriptor_set);
rse_err_t descriptor_attach_buffer(struct graphics_context_t* context, struct descriptor_set_handle_t* descriptor_set_handle, struct vulkan_buffer_t* buffer, uint32_t binding, VkDescriptorType type);
#endif // !DESCRIPTOR_BUILDER_H
+1 -3
View File
@@ -114,13 +114,11 @@ struct graphics_context_t
VkSemaphore render_finished_semaphores[SWAP_BUFFER_COUNT];
VkFence in_flight_fences[SWAP_BUFFER_COUNT];
struct pipeline_internal_t pipelines_data;
#ifndef NDEBUG
struct descriptor_set_handle_t* descriptor_sets;
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;
+11 -9
View File
@@ -14,7 +14,7 @@
#include <assert.h>
#include <stdint.h>
#include "descriptor_builder.h"
#include "src/descriptor_builder.h"
#include "src/graphics_context.h"
#include "utilities/commons.h"
#include "utilities/errors_common.h"
@@ -23,7 +23,6 @@
#include "utilities/localization.h"
#include "vulkan/vulkan_core.h"
#include "vulkan_errors.h"
#include "vulkan_image.h"
#define MAX_BINDLESS_RESOURCES 1000
@@ -58,6 +57,7 @@ struct pipeline_t
struct shader_attribute_list_t* shader_attributes;
struct dynamic_state_list_t* dynamic_states;
struct required_dynamic_states_t required_dynamic_states;
struct descriptor_set_handle_t* descriptor_sets;
};
/**
@@ -210,17 +210,19 @@ static rse_err_t pipeline_add_depth_stencil(struct pipeline_t* pipeline)
* VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED
*/
static rse_err_t create_pipeline_layout(struct graphics_context_t* context,
struct descriptors_set_handle_t* descriptor_set_handle)
struct descriptor_set_handle_t* descriptor_set_handle)
{
uint32_t descriptor_set_layouts_count = 0;
VkDescriptorSetLayout descriptor_set_layouts = VK_NULL_HANDLE;
rse_err_t status = RSE_ERROR_NO_ERROR;
VkDescriptorSetLayout descriptor_sets_layouts = VK_NULL_HANDLE;
STATUS_CHECK(descriptor_get_layout(descriptor_set_handle, &descriptor_sets_layouts));
VkPipelineLayoutCreateInfo create_info = {0};
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.setLayoutCount = 1; // FIXME: Make sure we can enable more than one layout
create_info.pSetLayouts = &descriptor_sets_layouts;
create_info.pushConstantRangeCount = 0U;
create_info.pPushConstantRanges = NULL;
@@ -385,7 +387,7 @@ rse_err_t pipeline_add_vertex_input_attribute(struct pipeline_t* pipeline, const
return RSE_ERROR_NO_ERROR;
}
rse_err_t pipelines_build(struct graphics_context_t* context, struct pipeline_infos_list_t* pipelines_infos_list)
rse_err_t pipelines_build(struct graphics_context_t* context, struct pipeline_infos_list_t* pipelines_infos_list, struct descriptor_set_handle_t* descriptor_set_handles)
{
assert(NULL != context);
assert(NULL != pipelines_infos_list);
@@ -397,7 +399,7 @@ rse_err_t pipelines_build(struct graphics_context_t* context, struct pipeline_in
context->pipelines_data.pipelines_count = pipelines_count;
STATUS_CHECK(create_pipeline_layout(context));
STATUS_CHECK(create_pipeline_layout(context, descriptor_set_handles));
rse_malloc(pipeline_infos, sizeof(VkGraphicsPipelineCreateInfo) * pipelines_count);
+3 -1
View File
@@ -15,6 +15,7 @@
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_core.h>
#include "descriptor_builder.h"
#include "graphics_context.h"
#include "utilities/commons.h"
#include "utilities/linked_list.h"
@@ -85,9 +86,10 @@ rse_err_t pipeline_add_dynamic_state(struct pipeline_t* pipeline, const VkDynami
*
* param[in/out] context Graphics context handle
* @param[in] pipeline Pipelines list to build
* @param[in] descriptor_set_handle Filled handle with descriptor sets
* @return RSE_SUCCESS on success, error code otherwise
*/
rse_err_t pipelines_build(struct graphics_context_t* context, struct pipeline_infos_list_t* pipelines);
rse_err_t pipelines_build(struct graphics_context_t* context, struct pipeline_infos_list_t* pipelines, struct descriptor_set_handle_t* descriptor_set_handle);
/**
* @brief Add pipeline to list of pipelines
+29 -16
View File
@@ -1,16 +1,20 @@
#include "rse_graphics.h"
#include <string.h>
#include <vulkan/vulkan_core.h>
#include "descriptor_builder.h"
#include "graphics_context.h"
#include "math.h"
#include "mesh_controller.h"
#include "pipeline_builder.h"
#include "src/vulkan_buffers.h"
#include "utilities/commons.h"
#include "utilities/errors_common.h"
#include "utilities/file_utils.h"
#include "utilities/localization.h"
#include "utilities/logger.h"
#include "vulkan_base.h"
#include "vulkan_commons.h"
#include "vulkan_image.h"
#include "window.h"
struct rse_graphics_context_t
@@ -41,15 +45,13 @@ rse_err_t rse_graphics_init(struct rse_graphics_context_t** context)
void rse_graphics_test_function(struct rse_graphics_context_t* rse_context)
{
char curr_path[4096] = {0};
struct graphics_context_t* context = rse_context->context;
// rse_err_t status = RSE_ERROR_NO_ERROR;
uint16_t tex_id_2 = 0;
size_t ubo_index = 0;
size_t sampler_index = 0;
struct pipeline_t* pipeline = NULL;
struct descriptor_set_list_t* descriptor_set_list;
struct descriptor_set_handle_t* descriptor_set_handle;
struct descriptor_set_handle_t* descriptor_set_handle = NULL;
struct pipeline_infos_list_t* pipeline_infos = NULL;
struct vulkan_buffer_t ubo = {};
// status = load_texture_from_file("../../test_image.jpg", &tex_id_2);
// if (status != RSE_ERROR_NO_ERROR) {
@@ -92,9 +94,12 @@ void rse_graphics_test_function(struct rse_graphics_context_t* rse_context)
/* 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);
get_curr_path(curr_path, 4096);
strncat(curr_path, "shader.vert.num", 4095);
pipeline_add_shader_stage(context, pipeline, curr_path, VK_SHADER_STAGE_VERTEX_BIT);
get_curr_path(curr_path, 4096);
strncat(curr_path, "solid_objects.frag.num", 4095);
pipeline_add_shader_stage(context, pipeline, curr_path, 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_binding(pipeline, 1, sizeof(struct vertex_t), VK_VERTEX_INPUT_RATE_INSTANCE);
@@ -115,25 +120,33 @@ void rse_graphics_test_function(struct rse_graphics_context_t* rse_context)
VkSampler sampler = VK_NULL_HANDLE;
create_sampler(context, sampler);
sampler_create(context, &sampler);
descriptor_add_set(descriptor_set_list, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, NULL);
descriptor_add_set(descriptor_set_list, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1,
VK_SHADER_STAGE_FRAGMENT_BIT, sampler);
descriptor_initialize_handle(&descriptor_set_handle);
descriptors_build(context, descriptor_set_list, descriptor_set_handle);
descriptor_add_set(descriptor_set_handle, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, NULL);
descriptor_add_set(descriptor_set_handle, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1,
VK_SHADER_STAGE_FRAGMENT_BIT, &sampler);
descriptors_build(context, descriptor_set_handle);
add_pipeline(context, pipeline, &pipeline_infos);
build_pipelines(context, pipeline_infos);
pipelines_build(context, pipeline_infos, descriptor_set_handle);
create_uniform_buffer(context, &ubo);
update_uniform_buffers(context, &ubo);
descriptor_attach_buffer(context, descriptor_set_handle, &ubo, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
// 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(struct rse_graphics_context_t* rse_context)
int rse_graphics_run(void* arg)
{
rse_err_t status = RSE_ERROR_NO_ERROR;
struct rse_graphics_context_t* rse_context = (struct rse_graphics_context_t*)arg;
struct graphics_context_t* context = rse_context->context;
STATUS_CHECK(run_vulkan(context));
+2 -16
View File
@@ -36,7 +36,6 @@
#define APPLICATION_NAME "RedScarfEngine PoC"
#define ENGINE_NAME "RedScarf Engine"
#ifndef NDEBUG
/**
* @brief Calback for debug messenger
*
@@ -145,8 +144,6 @@ static void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMesse
}
}
#endif /* DEBUG */
/**
* @brief Create the Vulkan Instance object
*
@@ -178,18 +175,15 @@ static rse_err_t create_instance(VkInstance* instance)
#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
#if 0
uint32_t enabled_instance_extensions_count = 3;
uint32_t enabled_instance_layers_count = 0;
const char* enabled_instance_layers_names[] = {};
@@ -261,11 +255,7 @@ static rse_err_t create_instance(VkInstance* instance)
create_info.flags = 0U;
create_info.pApplicationInfo = &application_info;
create_info.enabledLayerCount = enabled_instance_layers_count;
#ifndef NDEBUG
create_info.ppEnabledLayerNames = enabled_instance_layers_names;
#else
create_info.ppEnabledLayerNames = NULL;
#endif
create_info.enabledExtensionCount = enabled_instance_extensions_count;
create_info.ppEnabledExtensionNames = enabled_instance_extensions_names;
@@ -546,9 +536,7 @@ rse_err_t init_vulkan(struct graphics_context_t* context)
rse_err_t status = RSE_ERROR_NO_ERROR;
STATUS_CHECK(create_instance(&context->instance));
#ifndef NDEBUG
STATUS_CHECK(setup_debug_messenger(context->instance, &context->debug_messenger));
#endif
STATUS_CHECK(create_surface(context->instance, context->window_handle, &context->surface));
STATUS_CHECK(pick_physical_device(context->instance, &context->physical_device));
STATUS_CHECK(create_device(context));
@@ -599,7 +587,7 @@ rse_err_t draw_frame(struct graphics_context_t* context)
return VULKAN_ERROR_ACQUIRE_SWAPCHAIN_FAILED;
}
update_uniform_buffers(context);
// update_uniform_buffers(context);
/* Only reset the fence if we are submitting work */
vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
@@ -672,9 +660,7 @@ void deinit_vulkan(struct graphics_context_t* context)
vmaDestroyAllocator(context->allocator);
vkDestroyDevice(context->device, NULL);
#ifndef NDEBUG
DestroyDebugUtilsMessengerEXT(context->instance, context->debug_messenger, NULL);
#endif
vkDestroySurfaceKHR(context->instance, context->surface, NULL);
vkDestroyInstance(context->instance, NULL);
}
+82 -108
View File
@@ -1,18 +1,19 @@
#include "vulkan_buffers.h"
#include "src/graphics_context.h"
#include "src/vulkan_commons.h"
#include "utilities/commons.h"
#include "utilities/linked_list.h"
#include "vulkan_errors.h"
#include "utilities/logger.h"
#include "utilities/localization.h"
#include "utilities/errors_common.h"
#include "math.h"
#include "vulkan_commands.h"
#include <stdint.h>
#include <string.h>
#include <vulkan/vulkan_core.h>
#include "math.h"
#include "src/descriptor_builder.h"
#include "src/graphics_context.h"
#include "src/vulkan_commons.h"
#include "utilities/commons.h"
#include "utilities/errors_common.h"
#include "utilities/localization.h"
#include "utilities/logger.h"
#include "vulkan_commands.h"
#include "vulkan_errors.h"
#define MAX_VERTEX_BUFFER_SIZE 33554432 /* 32 MB*/
@@ -23,7 +24,8 @@
* @param dst Destination buffer
* @param size Size of buffer to copy
*/
static void copy_buffer(struct graphics_context_t* context, 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 */
VkBufferCopy copy_region = {0};
@@ -40,7 +42,6 @@ static void copy_buffer(struct graphics_context_t* context, VkBuffer src, VkBuff
end_single_time_comands(context, command_buffer);
}
/**
* @brief Create a buffer holding all vertex data
*
@@ -59,8 +60,7 @@ static rse_err_t create_vertex_buffer(struct graphics_context_t* context)
/* Create Vertex Buffer*/
STATUS_CHECK(create_buffer(context, buffer_size,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
0, /* Will not be mapped with vmaMapMemory */
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0, /* Will not be mapped with vmaMapMemory */
&context->vertex_buffer));
context->vertex_buffer.allocated_size = 0;
@@ -82,9 +82,9 @@ static rse_err_t create_index_buffer(struct graphics_context_t* context)
buffer_size = MAX_VERTEX_BUFFER_SIZE;
/* Create Index Buffer*/
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,
0, /* Will not be mapped with vmaMapMemory */
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, 0, /* Will not be mapped with vmaMapMemory */
&context->index_buffer));
context->index_buffer.allocated_size = 0;
@@ -113,43 +113,32 @@ static rse_err_t create_instance_buffers(struct graphics_context_t* context)
&context->instance_buffers[iter]));
context->instance_buffers[iter].allocated_size = 0;
}
STATUS_CHECK(create_buffer(context, sizeof(VkDrawIndexedIndirectCommand) * MAX_MESH_NUMBER,
VK_BUFFER_USAGE_TRANSFER_DST_BIT
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
| VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
STATUS_CHECK(create_buffer(
context, sizeof(VkDrawIndexedIndirectCommand) * MAX_MESH_NUMBER,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
&context->draw_indirect_command_buffer));
return RSE_ERROR_NO_ERROR;
}
/**
* @brief Create a Uniform Buffers
*
* @param context Graphics context handle
* @return rse_err_t RSE_ERROR_NO_ERROR on success.
*/
static rse_err_t create_uniform_buffer(struct graphics_context_t* context)
rse_err_t create_uniform_buffer(struct graphics_context_t* context, struct vulkan_buffer_t* buffer)
{
rse_err_t status = RSE_ERROR_NO_ERROR;
VkDeviceSize buffer_size = sizeof(struct uniform_buffer_object_t);
VkDeviceSize buffer_size =
sizeof(struct uniform_buffer_object_t); // TODO: Change later. Uniform buffer is not only MVP
for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) {
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,
&context->uniform_buffers[i]));
}
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, buffer));
return RSE_ERROR_NO_ERROR;
}
rse_err_t create_buffer(struct graphics_context_t* context, const VkDeviceSize size,
VkBufferUsageFlags buffer_usage,
VmaMemoryUsage memory_usage,
const VmaAllocationCreateFlags allocation_flags,
rse_err_t create_buffer(struct graphics_context_t* context, const VkDeviceSize size, VkBufferUsageFlags buffer_usage,
VmaMemoryUsage memory_usage, const VmaAllocationCreateFlags allocation_flags,
struct vulkan_buffer_t* buffer)
{
VkBufferCreateInfo vertex_buffer_info = {0};
@@ -173,16 +162,14 @@ rse_err_t create_buffer(struct graphics_context_t* context, const VkDeviceSize s
create_info.pUserData = VK_NULL_HANDLE;
create_info.priority = 0.0f;
if (VK_SUCCESS != vmaCreateBuffer(context->allocator,
&vertex_buffer_info,
&create_info,
&buffer->buffer,
&buffer->allocation,
&buffer->allocation_info)) {
if (VK_SUCCESS != vmaCreateBuffer(context->allocator, &vertex_buffer_info, &create_info, &buffer->buffer,
&buffer->allocation, &buffer->allocation_info)) {
LOGF(_("Failed to create a vertex buffer\n"));
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
buffer->allocated_size = size;
return RSE_ERROR_NO_ERROR;
}
@@ -191,8 +178,7 @@ void destroy_buffer(struct graphics_context_t* context, struct vulkan_buffer_t*
vmaDestroyBuffer(context->allocator, buffer->buffer, buffer->allocation);
}
void update_uniform_buffers(struct graphics_context_t* context)
void update_uniform_buffers(struct graphics_context_t* context, const struct vulkan_buffer_t* buffer)
{
struct uniform_buffer_object_t ubo = {0};
struct vec3_t eye = {0};
@@ -213,18 +199,13 @@ void update_uniform_buffers(struct graphics_context_t* context)
ubo.model = math_rotate(math_uniform_mat4(), math_deg_to_radians(0.0f), rotation_vec);
ubo.view = math_look_at(&eye, &center, &up);
ubo.proj = math_perspective(fovy,
context->swapchain_extent.width / (float)context->swapchain_extent.height,
z_near,
ubo.proj = math_perspective(fovy, context->swapchain_extent.width / (float)context->swapchain_extent.height, z_near,
z_far);
memcpy(context->uniform_buffers[context->current_frame].allocation_info.pMappedData, &ubo, sizeof(ubo));
memcpy(buffer->allocation_info.pMappedData, &ubo, sizeof(ubo));
}
rse_err_t add_vertices(struct graphics_context_t* context, uint16_t mesh_id,
const struct vertex_t* vertices,
const uint16_t* indices,
struct buffer_data_t* vertex_data,
struct buffer_data_t* index_data)
rse_err_t add_vertices(struct graphics_context_t* context, uint16_t mesh_id, const struct vertex_t* vertices,
const uint16_t* indices, struct buffer_data_t* vertex_data, struct buffer_data_t* index_data)
{
rse_err_t status = RSE_ERROR_NO_ERROR;
VkDrawIndexedIndirectCommand draw_indirect_command;
@@ -235,19 +216,14 @@ rse_err_t add_vertices(struct graphics_context_t* context, uint16_t mesh_id,
struct vulkan_buffer_t* index_buffer = &context->index_buffer;
/* Creating staging buffer*/
STATUS_CHECK(create_buffer(context, MAX_VERTEX_BUFFER_SIZE,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_MAPPED_BIT
| VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
&staging_buffer));
STATUS_CHECK(create_buffer(
context, MAX_VERTEX_BUFFER_SIZE, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, &staging_buffer));
/* Fill staging buffer with vertex data */
memset(staging_buffer.allocation_info.pMappedData, 0, MAX_VERTEX_BUFFER_SIZE);
memcpy(staging_buffer.allocation_info.pMappedData, vertices, vertices_size);
copy_buffer(context, staging_buffer.buffer,
context->vertex_buffer.buffer,
vertices_size,
copy_buffer(context, staging_buffer.buffer, context->vertex_buffer.buffer, vertices_size,
context->vertex_buffer.allocated_size);
vertex_data->buffer_offset = context->vertex_offset;
@@ -257,10 +233,7 @@ rse_err_t add_vertices(struct graphics_context_t* context, uint16_t mesh_id,
/* Fill staging buffer with index data */
memset(staging_buffer.allocation_info.pMappedData, 0, indices_size);
memcpy(staging_buffer.allocation_info.pMappedData, indices, indices_size);
copy_buffer(context, staging_buffer.buffer,
index_buffer->buffer,
indices_size,
index_buffer->allocated_size);
copy_buffer(context, staging_buffer.buffer, index_buffer->buffer, indices_size, index_buffer->allocated_size);
index_data->buffer_offset = index_buffer->allocated_size;
index_buffer->allocated_size += indices_size;
@@ -272,12 +245,15 @@ rse_err_t add_vertices(struct graphics_context_t* context, uint16_t mesh_id,
draw_indirect_command.vertexOffset = vertex_data->buffer_offset;
draw_indirect_command.firstInstance = 0;
memcpy(context->draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), &draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand));
memcpy((char*)context->draw_indirect_command_buffer.allocation_info.pMappedData +
(mesh_id * sizeof(VkDrawIndexedIndirectCommand)),
&draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand));
return RSE_ERROR_NO_ERROR;
}
rse_err_t update_mesh_instances(struct graphics_context_t* context, uint16_t mesh_id, struct 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;
VkDrawIndexedIndirectCommand draw_indirect_command;
@@ -286,27 +262,27 @@ rse_err_t update_mesh_instances(struct graphics_context_t* context, uint16_t mes
size_t instance_size = sizeof(struct instance_data_t);
/* Creating staging buffer*/
STATUS_CHECK(create_buffer(context, instance_size,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_MAPPED_BIT
| VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
&staging_buffer));
STATUS_CHECK(create_buffer(
context, instance_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, &staging_buffer));
/* Copy transformation information about instance */
memcpy(staging_buffer.allocation_info.pMappedData, instance_data, instance_size);
copy_buffer(context, staging_buffer.buffer,
instance_buffer->buffer,
instance_size,
copy_buffer(context, staging_buffer.buffer, instance_buffer->buffer, instance_size,
instance_buffer->allocated_size);
destroy_buffer(context, &staging_buffer);
instance_buffer->allocated_size += instance_size;
memcpy(&draw_indirect_command, context->draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), sizeof(VkDrawIndexedIndirectCommand));
memcpy(&draw_indirect_command,
(char*)context->draw_indirect_command_buffer.allocation_info.pMappedData +
(mesh_id * sizeof(VkDrawIndexedIndirectCommand)),
sizeof(VkDrawIndexedIndirectCommand));
draw_indirect_command.instanceCount++;
memcpy(context->draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), &draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand));
memcpy((char*)context->draw_indirect_command_buffer.allocation_info.pMappedData +
(mesh_id * sizeof(VkDrawIndexedIndirectCommand)),
&draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand));
return RSE_ERROR_NO_ERROR;
}
@@ -322,17 +298,17 @@ rse_err_t update_mesh_instances(struct graphics_context_t* context, uint16_t mes
rse_err_t record_command_buffer(struct graphics_context_t* context, uint32_t image_index)
{
VkCommandBuffer command_buffer = context->command_buffers[context->current_frame];
VkDescriptorSet* descriptor_sets = NULL;
VkCommandBufferBeginInfo begin_info = {};
VkRenderPassBeginInfo render_pass_info = {};
VkViewport viewport = {};
VkRect2D scissor = {};
VkCommandBufferBeginInfo begin_info = {0};
VkRenderPassBeginInfo render_pass_info = {0};
VkViewport viewport = {0};
VkRect2D scissor = {0};
VkDeviceSize offsets[] = {0};
VkClearValue clear_values[2] = {}; //For color and depth stencil
VkClearValue clear_values[2] = {0}; // For color and depth stencil
VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
size_t i = 0U;
RSE_LINKED_LIST_TO_ARRAY(context->pipelines_data.descriptor_sets, descriptor_sets);
// FIXME: Do something with this list
// RSE_LINKED_LIST_TO_ARRAY(context->pipelines_data.descriptor_sets, descriptor_sets);
clear_values[0].color.float32[0] = 0.0f;
clear_values[0].color.float32[1] = 0.0f;
@@ -345,6 +321,12 @@ rse_err_t record_command_buffer(struct graphics_context_t* context, uint32_t ima
begin_info.flags = 0;
begin_info.pInheritanceInfo = NULL;
if (RSE_ERROR_NO_ERROR != descriptor_get_vkhandle(context->descriptor_sets, &descriptor_set)) {
LOGF(_("Failed to get vk handle from descriptor set handle\n"));
return VULKAN_ERROR_RECORD_COMMAND_BEGIN_FAILED;
}
if (vkBeginCommandBuffer(command_buffer, &begin_info) != VK_SUCCESS) {
LOGF(_("Failed to start recording command buffer\n"));
return VULKAN_ERROR_RECORD_COMMAND_BEGIN_FAILED;
@@ -378,18 +360,16 @@ rse_err_t record_command_buffer(struct graphics_context_t* context, uint32_t ima
vkCmdBindVertexBuffers(command_buffer, 0, 1, &context->vertex_buffer.buffer, offsets);
vkCmdBindIndexBuffer(command_buffer, context->index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->pipelines_data.pipeline_layout, 0, 2,
descriptor_sets, 0, NULL);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->pipelines_data.pipeline_layout, 0,
1, &descriptor_set, 0, NULL);
for (i = 0; i < MAX_MESH_NUMBER; ++i) {
VkBuffer instance_buffer = {context->instance_buffers[i].buffer};
vkCmdBindVertexBuffers(command_buffer, 1, 1, &instance_buffer, offsets);
vkCmdDrawIndexedIndirect(command_buffer,
context->draw_indirect_command_buffer.buffer,
sizeof(VkDrawIndexedIndirectCommand) * i,
1,
vkCmdDrawIndexedIndirect(command_buffer, context->draw_indirect_command_buffer.buffer,
sizeof(VkDrawIndexedIndirectCommand) * i, 1,
0); /* Can be 0 since we are not doing multiple draws each loop */
}
@@ -410,7 +390,6 @@ rse_err_t create_buffers(struct graphics_context_t* context)
STATUS_CHECK(create_vertex_buffer(context));
STATUS_CHECK(create_index_buffer(context));
STATUS_CHECK(create_instance_buffers(context));
STATUS_CHECK(create_uniform_buffer(context));
return status;
}
@@ -420,22 +399,17 @@ void reset_command_buffer(struct graphics_context_t* context)
vkResetCommandBuffer(context->command_buffers[context->current_frame], /*VkCommandBufferResetFlagBits*/ 0);
}
void destroy_buffers(struct graphics_context_t* context)
{
size_t i = 0U;
for (i = 0; i < SWAP_BUFFER_COUNT; ++i) {
vmaDestroyBuffer(context->allocator,
context->uniform_buffers[i].buffer,
context->uniform_buffers[i].allocation);
}
vmaDestroyBuffer(context->allocator, context->vertex_buffer.buffer, context->vertex_buffer.allocation);
vmaDestroyBuffer(context->allocator, context->index_buffer.buffer, context->index_buffer.allocation);
vmaDestroyBuffer(context->allocator, context->draw_indirect_command_buffer.buffer, context->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) {
vmaDestroyBuffer(context->allocator, context->instance_buffers[i].buffer, context->instance_buffers[i].allocation);
for (i = 0; i < MAX_MESH_NUMBER; ++i) {
vmaDestroyBuffer(context->allocator, context->instance_buffers[i].buffer,
context->instance_buffers[i].allocation);
}
}
+11 -2
View File
@@ -18,13 +18,22 @@
*/
rse_err_t create_buffers(struct graphics_context_t* context);
/**
* @brief Create a Uniform Buffers
*
* @param context Graphics context handle
* @param buffer Buffer handle to hold new buffer
* @return rse_err_t RSE_ERROR_NO_ERROR on success.
*/
rse_err_t create_uniform_buffer(struct graphics_context_t* context, struct vulkan_buffer_t* buffer);
/**
* @brief Update uniform buffers
*
* @param context Graphics context handle
*
* @param buffer Uniform buffer to update
*/
void update_uniform_buffers(struct graphics_context_t* context);
void update_uniform_buffers(struct graphics_context_t* context, const struct vulkan_buffer_t* ubo);
/**
* @brief Add vertices and indices to vulkan buffers
-163
View File
@@ -1,163 +0,0 @@
#include "vulkan_descriptors.h"
#include "utilities/errors_common.h"
#include "utilities/localization.h"
#include "utilities/logger.h"
#include "vulkan_commons.h"
#include "vulkan_errors.h"
#include "vulkan_image.h"
/**
* @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)
{
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 create_descriptors(struct graphics_context_t* context)
{
rse_err_t status = RSE_ERROR_NO_ERROR;
STATUS_CHECK(create_descriptor_pool(context));
STATUS_CHECK(create_descriptor_sets(context));
return status;
}
void destroy_descriptors(struct graphics_context_t* context)
{
vkDestroyDescriptorPool(context->device, context->descriptor_pool, NULL);
vkDestroyDescriptorPool(context->device, context->descriptor_pool_bindless,
NULL);
vkDestroyDescriptorSetLayout(context->device,
context->descriptor_set_layout, NULL);
vkDestroyDescriptorSetLayout(context->device,
context->descriptor_set_layout_bindless, NULL);
}
-26
View File
@@ -1,26 +0,0 @@
#ifndef VULKAN_DESCRIPTORS_H
#define VULKAN_DESCRIPTORS_H
#include "utilities/commons.h"
#include "graphics_context.h"
#define MAX_BINDLESS_RESOURCES 16536
/**
* @brief Create descriptors
*
* @param context Graphics context handle
* @param vulkan_state
* @return rse_err_t RSE_ERROR_NO_ERROR on success
*/
rse_err_t create_descriptors(struct graphics_context_t* context);
/**
* @brief Destroy all descriptors
*
* @param context Graphics context handle
*/
void destroy_descriptors(struct graphics_context_t* context);
#endif /* VULKAN_DESCRIPTORS_H */
-1
View File
@@ -59,7 +59,6 @@ enum vulkan_error_t
VULKAN_ERROR_UNKNOWN_DESCRIPTOR_TYPE,
VULKAN_ERROR_DESCRIPTOR_SET_LAYOUT_CREATION_FAILED,
VULKAN_ERROR_DESCRIPTOR_SET_CREATION_FAILED,
VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED,
};
#endif
+5 -11
View File
@@ -4,7 +4,6 @@
#include "utilities/commons.h"
#include "utilities/errors_common.h"
#include "utilities/file_utils.h"
#include "utilities/localization.h"
#include "utilities/logger.h"
#include "vulkan/vulkan_core.h"
@@ -17,18 +16,12 @@
#include <stdlib.h>
#include <string.h>
#include "stb/stb_image.h"
#include "stb_image.h"
#define IMAGE_TAKEN 1U
#define IMAGE_FREE 0U
/**
* @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
*/
rse_err_t create_sampler(struct graphics_context_t* context, VkSampler sampler)
rse_err_t sampler_create(struct graphics_context_t* context, VkSampler* sampler)
{
VkSamplerCreateInfo create_info = {0};
@@ -51,7 +44,7 @@ rse_err_t create_sampler(struct graphics_context_t* context, VkSampler sampler)
create_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
create_info.unnormalizedCoordinates = VK_FALSE;
if (VK_SUCCESS != vkCreateSampler(context->device, &create_info, NULL, &sampler)) {
if (VK_SUCCESS != vkCreateSampler(context->device, &create_info, NULL, sampler)) {
LOGF("Failed to create image view");
return 1;
}
@@ -446,7 +439,8 @@ void destroy_textures(struct graphics_context_t* context)
{
size_t i = 0U;
vkDestroySampler(context->device, context->sampler, NULL);
//FIXME: This is not working for now
// vkDestroySampler(context->device, context->sampler, NULL);
for (i = 0U; i < RSE_MAX_IMAGE_COUNT; ++i) {
if (context->texture_images[i].id_taken == IMAGE_TAKEN) {
+7 -1
View File
@@ -83,6 +83,12 @@ 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);
rse_err_t create_sampler(struct graphics_context_t* context, VkSampler sampler);
/**
* @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
*/
rse_err_t sampler_create(struct graphics_context_t* context, VkSampler* sampler);
#endif /* TEXTURE_H */
+1 -2
View File
@@ -7,7 +7,6 @@
#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"
@@ -132,7 +131,7 @@ static rse_err_t create_framebuffers(struct graphics_context_t* context)
context->depth_image.image_view,
context->swapchain_image_views[i]};
VkFramebufferCreateInfo framebufferInfo = {};
VkFramebufferCreateInfo framebufferInfo = {0};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = context->render_pass;
framebufferInfo.attachmentCount = 3;
+12 -5
View File
@@ -1,22 +1,29 @@
#include "graphics/rse_graphics.h"
#include "utilities/task.h"
#include "utilities/errors_common.h"
#include "utilities/localization.h"
#include "utilities/logger.h"
#include "SDL3/SDL_thread.h"
int main(int argc, char** argv)
{
rse_err_t status = RSE_ERROR_NO_ERROR;
thread_t graphics_task;
struct rse_graphics_context_t* context = NULL;
SDL_Thread* graphics_task = NULL;
(void)argc;
(void)argv;
STATUS_CHECK(rse_graphics_init(&context));
rse_graphics_test_function(context);
create_task(&graphics_task, (thread_worker_t)rse_graphics_run, context);
task_join(&graphics_task);
task_exit();
graphics_task = SDL_CreateThread(rse_graphics_run, "graphics_task", (void*) context);
if (NULL == graphics_task) {
LOGE(_("Failed to create graphics task"));
exit(1);
}
SDL_WaitThread(graphics_task, NULL);
return 0;
}
+3 -1
View File
@@ -1,3 +1,5 @@
find_package(Intl)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
add_library(utilities SHARED)
@@ -12,4 +14,4 @@ target_sources(utilities PRIVATE
)
target_link_libraries(utilities PRIVATE
pthread)
Intl::Intl)
+2
View File
@@ -26,6 +26,8 @@ enum common_error_t
RSE_ERROR_NULL_POINTER,
RSE_ERROR_ALREADY_INITIALIZED,
RSE_COMMON_ERROR_MALLLOC_FAILED,
RSE_ERROR_INVALID_PARAM,
RSE_ERROR_INTERNAL_ERROR,
};
#define ERRORS_COMMON_H
+3
View File
@@ -2,6 +2,7 @@
#define FILE_UTILS_H
#include <stddef.h>
#include "utilities/commons.h"
/**
* @brief Reads file and puts its content into char buffer. If NULL is provided as buffer, than just bytes_count
@@ -15,5 +16,7 @@ void read_file(const char* file_path, size_t* bytes_count, char* buffer);
void write_to_file(const char* file_name, size_t bytes_count, char* buffer);
rse_err_t get_curr_path(char* path, size_t max_path_length);
#endif /* FILE_UTILS_H */
+10 -10
View File
@@ -30,21 +30,21 @@
}
#define RSE_LINKED_LIST_PUSH_FRONT(list, value) \
typeof(list) new_node = NULL; \
__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; \
__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; \
__typeof__(list) current = list; \
while (current->next != NULL) { \
current = current->next; \
} \
@@ -53,7 +53,7 @@
#define RSE_LINKED_LIST_POP_FRONT(list) \
if (list != NULL) { \
typeof(list) temp = list; \
__typeof__(list) temp = list; \
list = list->next; \
rse_free(temp); \
}
@@ -64,7 +64,7 @@
rse_free(list); \
list = NULL; \
} else { \
typeof(list) *current = list; \
__typeof__(list) *current = list; \
while (current->next->next != NULL) { \
current = current->next; \
} \
@@ -78,7 +78,7 @@
#define RSE_LINKED_LIST_BACK(list) \
if (list != NULL) { \
typeof(list) *current = list; \
__typeof__(list) *current = list; \
while (current->next != NULL) { \
current = current->next; \
} \
@@ -91,7 +91,7 @@
#define RSE_LINKED_LIST_SIZE(list) \
({ \
int size = 0; \
typeof(list) current = list; \
__typeof__(list) current = list; \
while (current != NULL) { \
size++; \
current = current->next; \
@@ -101,17 +101,17 @@
#define RSE_LINKED_LIST_CLEAR(list) \
while (list != NULL) { \
typeof(list) temp = list; \
__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)
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)
for (__typeof__(list) i = list; i != NULL; i = i->next)
#define RSE_LINKED_LIST_TO_ARRAY(list, array) \
({ \
+74 -8
View File
@@ -2,16 +2,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utilities/commons.h"
#include "utilities/errors_common.h"
#include "utilities/localization.h"
#include "utilities/logger.h"
#ifdef __linux__
#include <unistd.h>
#include <limits.h>
#endif /* ifndef __linux */
#define MAX_PATH_LENGTH (4096U)
void read_file(const char* file_name, size_t* bytes_count, char* buffer)
{
errno_t err = 0;
FILE* file = NULL;
err = fopen_s(&file, file_name, "rb");
file = fopen(file_name, "rb");
if (0 != err) {
perror("Failed to open file");
if (NULL == file) {
LOGE(_("Failed to open file for read: %s\n"), file_name);
return;
}
@@ -33,16 +44,71 @@ void read_file(const char* file_name, size_t* bytes_count, char* buffer)
void write_to_file(const char* file_name, size_t bytes_count, char* buffer)
{
errno_t err = 0;
FILE* file = NULL;
err = fopen_s(&file, file_name, "wb");
file = fopen(file_name, "wb");
if (0 != err) {
perror("Failed to open file.");
if (NULL == file) {
LOGE(_("Failed to open file for write: %s\n"), file_name);
return;
}
fwrite(buffer, bytes_count, 1, file);
fclose(file);
}
rse_err_t get_curr_path(char* path, size_t path_size)
{
char* last_sep = NULL;
char* tmp_path = NULL;
size_t binary_path_length = 0U;
size_t directory_path_length = 0U;
if (NULL == path) {
LOGE(_("Failed to get path. Provided pointer is NULL\n"));
return RSE_ERROR_NULL_POINTER;
}
if (0 == path_size) {
LOGE(_("Max path length cannot be 0\n"));
return RSE_ERROR_INVALID_PARAM;
}
rse_memset(path, '\0', path_size);
rse_malloc(tmp_path, MAX_PATH_LENGTH);
#ifdef __linux__
binary_path_length = readlink("/proc/self/exe", tmp_path, MAX_PATH_LENGTH - 1);
if (binary_path_length == -1) {
LOGF(_("Failed to read current binary path\n"));
return RSE_ERROR_NULL_POINTER;
}
tmp_path[binary_path_length] = '\0';
#endif /* ifdef __linux__ */
last_sep = strrchr(tmp_path, '/') + 1;
if (NULL == last_sep) {
LOGE(_("Failed to get last separator in path\n"));
return RSE_ERROR_INTERNAL_ERROR;
}
directory_path_length = last_sep - tmp_path;
if (directory_path_length > path_size) {
LOGE(_("Provided path buffer is too small\n"));
return RSE_ERROR_INTERNAL_ERROR;
}
strncpy(path, tmp_path, directory_path_length);
free(tmp_path);
return RSE_ERROR_NO_ERROR;
}