rtengine/src/renderer/command_list.c
Kevin Trogant beba96b915
Some checks failed
Ubuntu Cross to Win64 / Cross Compile with ming64 (1.4.0, ubuntu-latest) (push) Failing after 1m41s
feat(renderer): Basic command list managemnent
2024-08-02 17:12:35 +02:00

104 lines
3.6 KiB
C

#include "command_list.h"
#include "backend_api.h"
#include <runtime/config.h>
#include <runtime/mem_arena.h>
#include <runtime/threading.h>
#include <string.h>
RT_CVAR_SZ(r_PerFrameCommandListMemory, "Amount of memory to allocate for single frame command list management."
" The total amount of memory will be this times the maximum number of frames in flight. (Default: 16 MB)",
RT_MB(16));
static rt_arena _list_arenas[3];
static rt_arena *_current_arena = &_list_arenas[0];
static unsigned int _current_arena_idx = 0;
static rt_mutex *_mutex;
rt_result InitCommandLists(void) {
_mutex = rtCreateMutex();
if (!_mutex)
return RT_UNKNOWN_ERROR;
for (unsigned int i = 0; i < RT_ARRAY_COUNT(_list_arenas); ++i) {
rt_create_arena_result arena_res = rtCreateArena(NULL, r_PerFrameCommandListMemory.sz);
if (!arena_res.ok) {
rtDestroyMutex(_mutex);
return RT_OUT_OF_MEMORY;
}
_list_arenas[i] = arena_res.arena;
}
return RT_SUCCESS;
}
void ShutdownCommandLists(void) {
for (unsigned int i = 0; i < RT_ARRAY_COUNT(_list_arenas); ++i) {
rtReleaseArena(&_list_arenas[i]);
}
rtDestroyMutex(_mutex);
}
void CommandListsOnBeginFrame(void) {
_current_arena_idx = (_current_arena_idx + 1) % RT_ARRAY_COUNT(_list_arenas);
_current_arena = &_list_arenas[_current_arena_idx];
rtArenaClear(_current_arena);
}
#define COMMAND_LIST_CAPACITY RT_KB(512)
#define AVERAGE_COMMAND_DATA_SIZE sizeof(rt_draw_indirect_data)
#define COMMAND_LIST_MAX_LENGTH (COMMAND_LIST_CAPACITY / AVERAGE_COMMAND_DATA_SIZE)
/* Get a new render command list. */
RT_DLLEXPORT rt_begin_render_command_list_result rtBeginRenderCommandList(void) {
size_t mem_required = COMMAND_LIST_MAX_LENGTH * sizeof(rt_render_command_header) + COMMAND_LIST_CAPACITY;
rtLockMutex(_mutex);
void *mem = rtArenaPush(_current_arena, mem_required);
rtUnlockMutex(_mutex);
if (!mem) {
rtReportError("RENDERER", "Ran out of memory for command lists.");
return (rt_begin_render_command_list_result){.result = RT_OUT_OF_MEMORY};
}
rt_render_command_list list = {
.headers = mem,
.data = (void *)((rt_render_command_header *)mem + COMMAND_LIST_MAX_LENGTH),
.length = 0u,
.data_capacity = COMMAND_LIST_CAPACITY,
.data_end = 0u
};
return (rt_begin_render_command_list_result){
.result = RT_SUCCESS,
.list = list
};
}
/* Lowlevel function that writes the data to the queue. */
RT_DLLEXPORT rt_result rtEncodeRenderCommand(rt_render_command_list *list, rt_render_command_type type, rt_render_queue queue, const void *data) {
size_t data_size = 0u;
switch (type) {
case RT_RENDER_COMMAND_DRAW_INDIRECT:
data_size = sizeof(rt_draw_indirect_data);
break;
default:
rtReportError("RENDERER", "Invalid render command type %u", type);
return RT_INVALID_VALUE;
}
if (list->length == COMMAND_LIST_MAX_LENGTH || (list->data_end + data_size) > list->data_capacity) {
rtReportError("RENDERER", "Reached maximum lenght or capacity of command list.");
return RT_OUT_OF_MEMORY;
}
list->headers[list->length].type = type;
list->headers[list->length].target_queue = queue;
++list->length;
char *dest = (char *)list->data + list->data_end;
memcpy(dest, data, data_size);
list->data_end += data_size;
return RT_SUCCESS;
}
/* Submit a finished command list to the graphics device. The list will not be usable after this function is done. */
RT_DLLEXPORT rt_result rtSubmitCommandList(rt_render_command_list *list) {
return g_device_i.SubmitCommandList(g_device_i.o, list);
}