Files
RedScarfEngine/graphics/src/rse_graphics.c
T
Piotr Krygier b7a472fe45 Descriptor update
Updated descriptor set build to use function parameters instead of
global vars

Signed-off-by: Piotr Krygier <piotrkrygier@everyonecancode@xyz>
2026-02-10 10:24:50 +01:00

253 lines
9.7 KiB
C

#include "rse_graphics.h"
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_log.h>
#include <SDL3/SDL_render.h>
#include <cglm/util.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vulkan/vulkan_core.h>
#include "descriptor_builder.h"
#include "font_manager.h"
#include "graphics_context.h"
#include "mesh_controller.h"
#include "pipeline_builder.h"
#include "src/renderer.h"
#include "src/vulkan_buffers.h"
#include "utilities/commons.h"
#include "utilities/errors_common.h"
#include "vulkan_base.h"
#include "vulkan_commons.h"
#include "vulkan_image.h"
#include "window.h"
struct rse_graphics_context_t
{
struct graphics_context_t* context;
};
static rse_err_t render_static_mesh(struct graphics_context_t* context, uint32_t renderer_id)
{
VkCommandBuffer command_buffer = context->vulkan_handles.command_buffers[context->current_frame];
VkDeviceSize offsets[] = {0};
(void)renderer_id;
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->pipelines_data.pipelines[0]);
vkCmdBindIndexBuffer(command_buffer, context->render_targets[RENDER_TARGET_3D].index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdBindVertexBuffers(command_buffer, 0, 1, &context->render_targets[RENDER_TARGET_3D].vertex_buffer.buffer, offsets);
/* FIXME: Currently we can only bind one descriptor set */
vkCmdBindDescriptorSets(command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
context->pipelines_data.pipeline_layouts[0],
0,
1,
&context->descriptor_data.descriptor_sets[0],
0,
NULL);
vkCmdDrawIndexedIndirect(command_buffer,
context->render_targets[RENDER_TARGET_3D].draw_indirect_command_buffer.buffer,
0,
context->mesh_data.mesh_count,
sizeof(VkDrawIndexedIndirectCommand));
return RSE_ERROR_NO_ERROR;
}
static void model_view_projection_update(struct graphics_context_t* context, const struct vulkan_buffer_t* buffer)
{
struct uniform_buffer_object_t ubo = {0};
vec3 eye = {0};
vec3 center = {0};
vec3 up = {0};
vec3 rotation_vec = {1.0f, 0.0f, 0.0f};
float fovy;
float z_near;
float z_far;
eye[2] = -5.0f;
up[1] = 1.0f;
fovy = glm_rad(45.0f);
z_near = 0.1f;
z_far = 20.0f;
glm_mat4_identity(ubo.model);
glm_rotate(ubo.model, glm_rad(0.0f), rotation_vec);
glm_lookat(eye, center, up, ubo.view);
glm_perspective(
fovy,
context->swapchain_data.swapchain_extent.width / (float)context->swapchain_data.swapchain_extent.height,
z_near,
z_far,
ubo.proj);
memcpy(buffer->allocation_info.pMappedData, &ubo, sizeof(ubo));
}
rse_err_t rse_graphics_init(struct rse_graphics_context_t** context)
{
rse_err_t status = RSE_ERROR_NO_ERROR;
struct rse_graphics_context_t* ctx_ptr = NULL;
if (*context != NULL) {
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Graphics already initialized!");
return RSE_ERROR_ALREADY_INITIALIZED;
}
rse_malloc(*context, sizeof(struct rse_graphics_context_t));
ctx_ptr = *context;
rse_malloc(ctx_ptr->context, sizeof(struct graphics_context_t));
rse_memset(ctx_ptr->context, 0, sizeof(struct graphics_context_t));
STATUS_CHECK(window_init(&ctx_ptr->context->window_handle, &ctx_ptr->context->is_framebuffer_resized));
STATUS_CHECK(init_vulkan(ctx_ptr->context));
return status;
}
rse_err_t 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;
uint16_t textures[2] = {0};
struct pipeline_t pipeline;
uint32_t descriptor_set_handle = 0;
struct descriptor_set_layout_bindings_t layout_bindings = {0};
struct pipeline_infos_t pipeline_infos = {0};
struct vulkan_buffer_t model_view_projection_buffer = {0};
uint32_t mesh_id_1, mesh_id_2 = 0;
uint32_t font_id = 0;
uint32_t static_mesh_renderer = 0U;
uint16_t vertex_shader_id, fragment_shader_id;
load_texture_from_file(context, "../../test_image.jpg", &textures[0]);
load_texture_from_file(context, "../../test_image_2.jpg", &textures[1]);
STATUS_CHECK(fonts_init());
STATUS_CHECK(fonts_load_from_file(context, "../../NotoSansMono-Regular.ttf", &font_id));
STATUS_CHECK(fonts_set_font_size(context, font_id, 16));
// FIXME: Temporary array of vertices, for testing purposes
struct vertex_t vertices[] = {{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.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}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}};
struct vertex_t vertices2[] = {{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.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}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}};
// FIXME: Temporary array of vertices, for testing purposes
uint16_t indices[] = {0, 1, 2, 2, 3, 0};
create_mesh(context, vertices, indices, 4, 6, &mesh_id_1);
if (RSE_ERROR_NO_ERROR !=
create_mesh_instance(context,
mesh_id_1,
(struct instance_data_t){{0.0f, 0.0f, 2.4f}, {0.0f, 0.0f, 0.0}, 1.0f, textures[1]})) {
exit(1);
}
if (RSE_ERROR_NO_ERROR !=
create_mesh_instance(
context,
mesh_id_1,
(struct instance_data_t){{-0.5f, 0.0f, -1.0f}, {0.0f, 0.0f, glm_rad(10.0f)}, 1.0f, textures[0]})) {
exit(1);
}
create_mesh(context, vertices2, indices, 4, 6, &mesh_id_2);
if (RSE_ERROR_NO_ERROR !=
create_mesh_instance(
context,
mesh_id_2,
(struct instance_data_t){{1.0f, 1.0f, 0.0f}, {0.0f, 0.0f, glm_rad(0.0f)}, 1.0f, textures[0]})) {
exit(1);
}
create_uniform_buffer(context, &model_view_projection_buffer, sizeof(struct uniform_buffer_object_t));
model_view_projection_update(context, &model_view_projection_buffer);
buffers_update(context);
sampler_create(context, &context->vulkan_handles.sampler);
descriptor_pool_add_type(context, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2);
descriptor_pool_add_type(context, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2);
descriptor_pool_initialize(context);
/* Normal rendering */
descriptor_create_new_set(context, &descriptor_set_handle);
descriptor_add_layout(&layout_bindings, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
descriptor_add_layout(&layout_bindings, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
descriptor_add_layout(&layout_bindings, 2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, VK_SHADER_STAGE_FRAGMENT_BIT);
descriptor_set_finish(context, &layout_bindings, descriptor_set_handle);
descriptor_build_sets(context);
descriptor_attach_buffer(context,
descriptor_set_handle,
&model_view_projection_buffer,
0,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
descriptor_attach_buffer(context,
descriptor_set_handle,
&context->render_targets[RENDER_TARGET_3D].instance_buffer,
1,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
descriptor_attach_images(context, descriptor_set_handle, textures, 2, context->vulkan_handles.sampler, 2);
/* Initialize pipeline */
pipeline_builder_init(&pipeline);
shader_create_module(context, &vertex_shader_id, "shader.vert.num", VK_SHADER_STAGE_VERTEX_BIT);
pipeline_add_shader_stage(context, &pipeline, vertex_shader_id);
shader_create_module(context, &fragment_shader_id, "solid_objects.frag.num", VK_SHADER_STAGE_FRAGMENT_BIT);
pipeline_add_shader_stage(context, &pipeline, fragment_shader_id);
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, 0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct vertex_t, color));
pipeline_add_vertex_input_attribute(&pipeline, 0, 2, VK_FORMAT_R32G32_SFLOAT, offsetof(struct vertex_t, tex_coords));
pipeline_add_dynamic_state(&pipeline, VK_DYNAMIC_STATE_VIEWPORT);
pipeline_add_dynamic_state(&pipeline, VK_DYNAMIC_STATE_SCISSOR);
pipeline_add_descriptor_sets(context, &pipeline, descriptor_set_handle);
add_pipeline(context, &pipeline, &pipeline_infos);
pipelines_build(context, &pipeline_infos);
renderer_get_new_id(context, &static_mesh_renderer);
renderer_set_render_function(context, static_mesh_renderer, render_static_mesh);
return RSE_ERROR_NO_ERROR;
}
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));
STATUS_CHECK(window_loop(context));
deinit_vulkan(context);
window_terminate(context->window_handle);
rse_free(context->debug_overlay.pixels);
rse_free(context);
rse_free(rse_context);
return status;
}