revolver

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit a5ca020c10ea2ae58feaaf1a1e89472d2095bf73
parent efcc620832e3f1851f4798cf501c5f3305633eb7
Author: Samdal <samdal@protonmail.com>
Date:   Mon, 24 Mar 2025 19:16:47 +0100

vertex cache

Diffstat:
Mbuild.sh | 1+
Aexamples/vertex_cache.c | 196+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/platform/platform_arena.c | 17+++++++++--------
Msrc/platform/platform_arena.h | 18+++++++++---------
Msrc/platform/platform_core.c | 162++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/platform/platform_core.h | 2+-
Msrc/platform/platform_cracker.h | 15++++++++-------
Msrc/platform/platform_math.c | 10++++------
Msrc/platform/platform_math.h | 3++-
Msrc/platform/platform_types.h | 2+-
Msrc/render/impl/opengl.c | 57++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/render/render.h | 44+++++++++++++++++++++++++++++---------------
Dsrc/render/render_imdraw.h | 2--
Msrc/render/render_inc.c | 1+
Msrc/render/render_inc.h | 1+
Asrc/render/render_vertex_cache.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/render/render_vertex_cache.h | 26++++++++++++++++++++++++++
17 files changed, 485 insertions(+), 148 deletions(-)

diff --git a/build.sh b/build.sh @@ -14,6 +14,7 @@ do "simple_texture") sources=(./examples/simple_texture.c) ;; "hello_window") sources=(./examples/hello_window.c) ;; "instancing") sources=(./examples/instancing.c) ;; + "vertex_cache") sources=(./examples/vertex_cache.c) ;; esac done diff --git a/examples/vertex_cache.c b/examples/vertex_cache.c @@ -0,0 +1,196 @@ +////////////////////////////////////////////////////////////////// +// vertex_cache.c + +#include "revolver_inc.h" +#include "revolver_inc.c" + +////////////////////////////////////////////////////////////////// +// data + +f32 v_data[] = { + 0.00, 0.05, 1, 0, 0, + -0.05, -0.05, 0, 1, 0, + 0.05, -0.05, 0, 0, 1, +}; + +rv_str8 v_src = S("#version 330 core\n" rv_strify( + layout(location = 0) in vec2 a_pos; + layout(location = 1) in vec3 a_color; + layout(location = 2) in vec2 a_offset; + precision mediump float; + out vec3 f_color; + void main() + { + gl_Position = vec4(a_pos + a_offset, 0.0, 1.0); + f_color = a_color; + } +)); + +rv_str8 f_src = S("#version 330 core\n" rv_strify( + precision mediump float; + in vec3 f_color; + out vec4 frag_color; + void main() + { + frag_color = vec4(f_color, 1.0); + } +)); + +////////////////////////////////////////////////////////////////// + +int main(void) { + rv_window_desc_t desc = {.name = S("App"), .attach_render = true}; + rv_window_handle_t* window = rv_create_window(desc); + + rv_arena* arena = rv_arena_alloc(); + rv_render_pass_list_t rpass_list = {0}; + + // make render objects + rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); + rv_vbo_t* vboi = rv_push_compound(arena, rv_vbo_t, {.usage = RV_BUFFER_USAGE_DYNAMIC}); + rv_shader_t* vertex = rv_push_compound(arena, rv_shader_t, {.source = v_src, .type = RV_SHADER_TYPE_VERTEX}); + rv_shader_t* fragment = rv_push_compound(arena, rv_shader_t, {.source = f_src, .type = RV_SHADER_TYPE_FRAGMENT}); + rv_pipeline_t* pip = rv_push(arena, rv_pipeline_t); + + // construct pipeline + rv_pipeline_push_shader(arena, pip, vertex); + rv_pipeline_push_shader(arena, pip, fragment); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT2, 0, 0); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT3, 0, 0); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT2, 1, 1); + + // instructions to create render objects + rv_command_list_t create_instructions = {0}; + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, vbo); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, vboi); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, vertex); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, fragment); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE, pip); + + // copy over create commands + rv_render_pass_t* create_rpass = rv_render_push_render_pass(arena, &rpass_list); + rv_render_copy_commands(arena, &create_rpass->commands, &create_instructions); + + // create vertex cache + rv_vertex_cache_ctx_t vc = {0}; + rv_vertex_cache_create(&vc, // vertex cache context + vboi, // vertex buffer to change and bind + sizeof(rv_vec2) // element size + ); + + while(1) { + rv_temp_arena scratch = rv_scratch_begin(0, 0); + + // pick renderpass + rv_render_pass_t* rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); + + // process events + for (rv_event_t* e = rv_get_events(scratch.arena, 0); e; e = e->next) { + if (e->type == RV_EVENT_WINDOW_CLOSE) { + if (e->window_close == window) { + goto exit_program; + } + } + if (e->type == RV_EVENT_WINDOW_RESIZE) { + // set viewport + rv_command_t* viewport = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_SET_VIEWPORT); + viewport->viewport = rv_v4(.xy = {0, 0}, .zw = rv_window_size(window)); + } + } + + + { // clear + rv_command_t* clear = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_CLEAR); + rv_render_clear_desc_t* clear_desc = rv_render_push_clear_desc(scratch.arena, clear, RV_RENDER_CLEAR_FLAG_COLOR); + clear_desc->color_v = rv_v4(0.1, 0.1, 0.1, 1.0); + } + + { // draw using vertex cache + // bind pipeline + rv_cmd_push_obj(arena, &rpass->commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, pip); + rv_cmd_push_obj(arena, &rpass->commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); + + { // draw custom shader first time + { // Translation data + int32_t index = 0; + float offset = 0.1f; + s32 peak_to_peak = 9.0; + for (int32_t y = -peak_to_peak; y < peak_to_peak; y += 2) { + if (sinf(rv_time()*5) * 9.0f < y) + break; + for (int32_t x = -peak_to_peak; x < peak_to_peak; x += 2) { + if (cosf(rv_time()*5) * 9.0f < x) + break; + rv_vec2 vertex = {0}; + vertex.x = (float)x / 10.0f + offset; + vertex.y = (float)y / 10.0f + offset; + rv_vertex_cache_push(&vc, &vertex); + index++; + } + } + } + + // insert break, push draw command + rv_command_t bind_command; + rv_command_t draw_command = rv_cmd(RV_COMMAND_DRAW, {.draw.count = 3}); + + rv_vertex_cache_break(&vc, &bind_command, &draw_command.draw.instances); + bind_command.obj.vbo_bind.bind_index = 1; + + if (draw_command.draw.instances) { + rv_cmd_push_copy(scratch.arena, &rpass->commands, bind_command); + rv_cmd_push_copy(scratch.arena, &rpass->commands, draw_command); + } + } + + { // draw custom shader second time + { // Translation data + rv_vec2 extra_offset = rv_v2(sinf(rv_time()*10) * 0.05, cosf(rv_time()*10) * 0.05); + int32_t index = 0; + float offset = 0.1f; + s32 peak_to_peak = 10; + for (int32_t y = -peak_to_peak; y < peak_to_peak; y += 2) { + for (int32_t x = -peak_to_peak; x < peak_to_peak; x += 2) { + rv_vec2 vertex = {0}; + vertex.x = (float)x / 10.0f + offset + extra_offset.x; + vertex.y = (float)y / 10.0f + offset + extra_offset.y; + rv_vertex_cache_push(&vc, &vertex); + index++; + } + } + } + + // insert break, push draw command + rv_command_t bind_command; + rv_command_t draw_command = rv_cmd(RV_COMMAND_DRAW, {.draw.count = 3}); + + rv_vertex_cache_break(&vc, &bind_command, &draw_command.draw.instances); + bind_command.obj.vbo_bind.bind_index = 1; + + if (draw_command.draw.instances) { + rv_cmd_push_copy(scratch.arena, &rpass->commands, bind_command); + rv_cmd_push_copy(scratch.arena, &rpass->commands, draw_command); + } + } + + // unbind pipeline + rv_cmd_push_obj(arena, &rpass->commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); + + { + // when done, upload all the data + // must be done before render commands of course + rv_command_t change_command = rv_vetex_cache_upload_and_reset(&vc, scratch.arena); + rv_cmd_insert_copy(scratch.arena, &rpass->commands, rpass->commands.first, change_command); + } + } + + if (window) { // render screen + rv_window_render_commit(window, &rpass_list); + } + rv_scratch_end(scratch); + rpass_list = (rv_render_pass_list_t){0}; + } +exit_program: + + return 0; +} diff --git a/src/platform/platform_arena.c b/src/platform/platform_arena.c @@ -28,11 +28,11 @@ RV_INTERNAL void rv_arena_pop_to(rv_arena* arena, u64 pos) { } // Arena Push/Pop Helpers -RV_INTERNAL void arena_clear(rv_arena* arena) +RV_INTERNAL void rv_arena_clear(rv_arena* arena) { } -RV_INTERNAL void arena_pop(rv_arena* arena, u64 amt) +RV_INTERNAL void rv_arena_pop(rv_arena* arena, u64 amt) { } @@ -92,8 +92,8 @@ rv_arena_alloc_(rv_arena_params* params) { arena->free_size = 0; arena->free_last = 0; #endif - RV_ASAN_POISOIN(base, commit_size); - RV_ASAN_UNPOISOIN(base, RV_ARENA_HEADER_SIZE); + RV_ASAN_POISON(base, commit_size); + RV_ASAN_UNPOISON(base, RV_ARENA_HEADER_SIZE); return arena; } @@ -111,6 +111,7 @@ rv_arena_release(rv_arena* arena) RV_INTERNAL void* rv_arena_push(rv_arena* arena, u64 size, u64 align) { + rv_assert(align > 0); rv_arena* current = arena->current; u64 pos_pre = rv_align_pow2(current->pos, align); u64 pos_pst = pos_pre + size; @@ -129,7 +130,7 @@ rv_arena_push(rv_arena* arena, u64 size, u64 align) arena->free_last = new_block->prev; } arena->free_size -= new_block->res_size; - RV_ASAN_UNPOISOIN((u8*)new_block + RV_ARENA_HEADER_SIZE, new_block->res_size - RV_ARENA_HEADER_SIZE); + RV_ASAN_UNPOISON((u8*)new_block + RV_ARENA_HEADER_SIZE, new_block->res_size - RV_ARENA_HEADER_SIZE); break; } } @@ -175,7 +176,7 @@ rv_arena_push(rv_arena* arena, u64 size, u64 align) if (current->cmt >= pos_pst) { result = (u8 *)current+pos_pre; current->pos = pos_pst; - RV_ASAN_UNPOISOIN(result, size); + RV_ASAN_UNPOISON(result, size); } if (result == 0) { @@ -205,7 +206,7 @@ rv_arena_pop_to(rv_arena* arena, u64 pos) current->pos = RV_ARENA_HEADER_SIZE; arena->free_size += current->res_size; RV_STACK_PUSH_N(arena->free_last, current, prev); - RV_ASAN_POISOIN((u8*)current + RV_ARENA_HEADER_SIZE, current->res_size - RV_ARENA_HEADER_SIZE); + RV_ASAN_POISON((u8*)current + RV_ARENA_HEADER_SIZE, current->res_size - RV_ARENA_HEADER_SIZE); } #else for (rv_arena* prev = 0; current->base_pos >= big_pos; current = prev) { @@ -216,7 +217,7 @@ rv_arena_pop_to(rv_arena* arena, u64 pos) arena->current = current; u64 new_pos = big_pos - current->base_pos; rv_assert(new_pos <= current->pos); - RV_ASAN_POISOIN((u8*)current + new_pos, (current->pos - new_pos)); + RV_ASAN_POISON((u8*)current + new_pos, (current->pos - new_pos)); current->pos = new_pos; } diff --git a/src/platform/platform_arena.h b/src/platform/platform_arena.h @@ -70,8 +70,8 @@ RV_INTERNAL u64 rv_arena_pos(rv_arena* arena); RV_INTERNAL void rv_arena_pop_to(rv_arena* arena, u64 pos); // Arena Push/Pop Helpers -RV_INTERNAL void arena_clear(rv_arena* arena); -RV_INTERNAL void arena_pop(rv_arena* arena, u64 amt); +RV_INTERNAL void rv_arena_clear(rv_arena* arena); +RV_INTERNAL void rv_arena_pop(rv_arena* arena, u64 amt); // Temporary Arena Scopes RV_INTERNAL rv_temp_arena rv_temp_begin(rv_arena* arena); @@ -79,19 +79,19 @@ RV_INTERNAL void rv_temp_end(rv_temp_arena temp); // Push Helper Macros #define rv_push_no_zero_aligned(a, T, align) (T*)rv_arena_push((a), sizeof(T), (align)) -#define rv_push_no_zero(a, T) rv_push_no_zero_aligned(a, T, rv_max(8, rv_alignof(T))) +#define rv_push_no_zero(a, T) rv_push_no_zero_aligned(a, T, rv_alignof(T)) #define rv_push_aligned(a, T, align) (T*)rv_mem_zero(rv_push_no_zero_aligned(a, T, align), sizeof(T)) -#define rv_push(a, T) rv_push_aligned(a, T, rv_max(8, rv_alignof(T))) +#define rv_push(a, T) rv_push_aligned(a, T, rv_alignof(T)) -#define rv_push_compound(a, T, ...) rv_mem_copy(rv_push_no_zero_aligned(a, T, rv_max(8, rv_alignof(T))), &(T)__VA_ARGS__, sizeof(T)) -#define rv_push_copy(a, T, v) rv_mem_copy(rv_push_no_zero_aligned(a, T, rv_max(8, rv_alignof(T))), (T*)v, sizeof(T)) +#define rv_push_compound(a, T, ...) rv_mem_copy(rv_push_no_zero_aligned(a, T, rv_alignof(T)), &(T)__VA_ARGS__, sizeof(T)) +#define rv_push_copy(a, T, v) rv_mem_copy(rv_push_no_zero_aligned(a, T, rv_alignof(T)), (T*)v, sizeof(T)) #define rv_push_array_no_zero_aligned(a, T, c, align) (T*)rv_arena_push((a), sizeof(T)*(c), (align)) -#define rv_push_array_no_zero(a, T, c) rv_push_array_no_zero_aligned(a, T, c, rv_max(8, rv_alignof(T))) +#define rv_push_array_no_zero(a, T, c) rv_push_array_no_zero_aligned(a, T, c, rv_alignof(T)) #define rv_push_array_aligned(a, T, c, align) (T*)rv_mem_zero(rv_push_array_no_zero_aligned(a, T, c, align), sizeof(T)*(c)) -#define rv_push_array(a, T, c) rv_push_array_aligned(a, T, c, rv_max(8, rv_alignof(T))) +#define rv_push_array(a, T, c) rv_push_array_aligned(a, T, c, rv_alignof(T)) -#define rv_push_array_compound(a, T, c, ...) rv_mem_copy(rv_push_array_no_zero_aligned(a, T, c, rv_max(8, rv_alignof(T))), (T[c])__VA_ARGS__, sizeof(T)*c) +#define rv_push_array_compound(a, T, c, ...) rv_mem_copy(rv_push_array_no_zero_aligned(a, T, c, rv_alignof(T)), (T[c])__VA_ARGS__, sizeof(T)*c) // Scratch RV_GLOBAL rv_arena* rv_scratch_begin_(rv_arena **conflicts, u64 count); diff --git a/src/platform/platform_core.c b/src/platform/platform_core.c @@ -13,34 +13,34 @@ RV_GLOBAL void rv_abort_msg_(const char* file, const char* func, s32 line_no, s3 vsnprintf(buf, sizeof(buf), message, args); va_end(args); - fprintf(stderr, "rv_abort[%d]: '%s' at %s:%d (%s)\n", exit_code, buf, file, line_no, func); + fprintf(stderr, "rv_abort[%d]: '%s' at %s:%d (%s)\n", exit_code, buf, file, line_no, func); #if RV_OS_WINDOWS - ExitProcess(exit_code); + ExitProcess(exit_code); #else - _exit(exit_code); + _exit(exit_code); #endif } f64 rv_time(void) { - f64 res = 0; + f64 res = 0; #if RV_OS_WINDOWS - s64 wintime; - GetSystemTimeAsFileTime((FILETIME*)&wintime); - wintime -= 116444736000000000i64; // 1jan1601 to 1jan1970 - res += wintime / 10000000i64; // seconds - res += (wintime % 10000000i64 * 100) * 1e-9; // nano-seconds + s64 wintime; + GetSystemTimeAsFileTime((FILETIME*)&wintime); + wintime -= 116444736000000000i64; // 1jan1601 to 1jan1970 + res += wintime / 10000000i64; // seconds + res += (wintime % 10000000i64 * 100) * 1e-9; // nano-seconds #else - struct timespec ts_now; - clock_gettime(CLOCK_MONOTONIC, &ts_now); + struct timespec ts_now; + clock_gettime(CLOCK_MONOTONIC, &ts_now); - res = ts_now.tv_sec; - res += ts_now.tv_nsec * 1e-9; + res = ts_now.tv_sec; + res += ts_now.tv_nsec * 1e-9; #endif - return res; + return res; } ////////////////////////////////////////////////////////////////// @@ -48,26 +48,26 @@ f64 rv_time(void) { RV_GLOBAL void* rv_mem_reserve(s64 size) { - void* result = NULL; + void* result = NULL; #if RV_OS_WINDOWS result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE); #else result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, (off_t)0); - if (result == MAP_FAILED) result = 0; + if (result == MAP_FAILED) result = 0; #endif - return result; + return result; } RV_GLOBAL void* rv_mem_reserve_large(s64 size) { - void* result = NULL; + void* result = NULL; #if RV_OS_WINDOWS - // we commit on reserve because windows - result = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGES, PAGE_READWRITE); + // we commit on reserve because windows + result = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGES, PAGE_READWRITE); #else result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, (off_t)0); - if (result == MAP_FAILED) result = 0; + if (result == MAP_FAILED) result = 0; #endif - return result; + return result; } RV_GLOBAL void rv_mem_commit(void* ptr, s64 size) @@ -108,104 +108,104 @@ RV_GLOBAL void rv_mem_release(void* ptr, s64 size) RV_GLOBAL s64 rv_mem_get_page_size(bool32 is_large) { - s64 result = 0; + s64 result = 0; #if RV_OS_WINDOWS - if (is_large) { - result = GetLargePageMinimum(); - } else { - SYSTEM_INFO sysinfo = {0}; - GetSystemInfo(&sysinfo); - result = sysinfo.dwPageSiz; - } + if (is_large) { + result = GetLargePageMinimum(); + } else { + SYSTEM_INFO sysinfo = {0}; + GetSystemInfo(&sysinfo); + result = sysinfo.dwPageSiz; + } #else - if (is_large) { - // I hate this + if (is_large) { + // I hate this - rv_str8 filename = S("/proc/meminfo"); + rv_str8 filename = S("/proc/meminfo"); - int readerr; - long val; + int readerr; + long val; - rv_temp_arena scratch = rv_scratch_begin(0, 0); + rv_temp_arena scratch = rv_scratch_begin(0, 0); - char* buffer = rv_push_array(scratch.arena, char, KB(4)); - FILE* f = fopen("/proc/meminfo", "rb"); - if (f) { - fread(buffer, KB(4) - 1, 1, f); - } - rv_str8 proc_meminfo = rv_str8_from_cstr(buffer); + char* buffer = rv_push_array(scratch.arena, char, KB(4)); + FILE* f = fopen("/proc/meminfo", "rb"); + if (f) { + fread(buffer, KB(4) - 1, 1, f); + } + rv_str8 proc_meminfo = rv_str8_from_cstr(buffer); - rv_str8 tag = S("Hugepagesize:"); - rv_str8 found = rv_str8_skip(proc_meminfo, rv_str8_find_needle(proc_meminfo, 0, tag, 0) + tag.len); + rv_str8 tag = S("Hugepagesize:"); + rv_str8 found = rv_str8_skip(proc_meminfo, rv_str8_find_needle(proc_meminfo, 0, tag, 0) + tag.len); - // chop around number + byte size - found = rv_str8_skip_chop_whitespace(found); - found = rv_str8_prefix(found, rv_str8_find_needle(found, 0, S("\n"), 0)); + // chop around number + byte size + found = rv_str8_skip_chop_whitespace(found); + found = rv_str8_prefix(found, rv_str8_find_needle(found, 0, S("\n"), 0)); - bool32 kb = rv_str8_find_needle(found, 0, S("kb"), rv_str8_match_flag_case_insensetive) < found.len; - bool32 mb = rv_str8_find_needle(found, 0, S("mb"), rv_str8_match_flag_case_insensetive) < found.len; - bool32 gb = rv_str8_find_needle(found, 0, S("gb"), rv_str8_match_flag_case_insensetive) < found.len; + bool32 kb = rv_str8_find_needle(found, 0, S("kb"), rv_str8_match_flag_case_insensetive) < found.len; + bool32 mb = rv_str8_find_needle(found, 0, S("mb"), rv_str8_match_flag_case_insensetive) < found.len; + bool32 gb = rv_str8_find_needle(found, 0, S("gb"), rv_str8_match_flag_case_insensetive) < found.len; - // remove byte part - found = rv_str8_prefix(found, rv_str8_find_needle(found, 0, S(" "), 0)); + // remove byte part + found = rv_str8_prefix(found, rv_str8_find_needle(found, 0, S(" "), 0)); - result = rv_s64_from_str8(found, 10); - if (kb) result = KB(result); - if (mb) result = MB(result); - if (gb) result = GB(result); + result = rv_s64_from_str8(found, 10); + if (kb) result = KB(result); + if (mb) result = MB(result); + if (gb) result = GB(result); - rv_scratch_end(scratch); - } else { - result = getpagesize(); - } + rv_scratch_end(scratch); + } else { + result = getpagesize(); + } #endif - return result; + return result; } RV_GLOBAL void* rv_mem_set(void* mem, u8 set_byte, s64 size) { - u8* bytes = mem; - for (s64 i = 0; i < size; i++) { - bytes[i] = set_byte; - } - return mem; + u8* bytes = mem; + for (s64 i = 0; i < size; i++) { + bytes[i] = set_byte; + } + return mem; } RV_GLOBAL void* rv_mem_zero(void* mem, s64 size) { - return rv_mem_set(mem, 0, size); + return rv_mem_set(mem, 0, size); } RV_GLOBAL void* rv_mem_copy(void* restrict target, const void* restrict source, s64 size) { - u8* t = target; - const u8* s = source; - for (s64 i = 0; i < size; i++) { - t[i] = s[i]; - } - return target; + u8* t = target; + const u8* s = source; + for (s64 i = 0; i < size; i++) { + t[i] = s[i]; + } + return target; } RV_GLOBAL void* rv_mem_move(void* target, const void* source, s64 size) { - rv_temp_arena scratch = rv_scratch_begin(0, 0); + rv_temp_arena scratch = rv_scratch_begin(0, 0); - u8* temp = rv_push_array_no_zero(scratch.arena, u8, size); + u8* temp = rv_push_array_no_zero(scratch.arena, u8, size); - rv_mem_copy(temp, source, size); - rv_mem_copy(target, temp, size); + rv_mem_copy(temp, source, size); + rv_mem_copy(target, temp, size); - rv_scratch_end(scratch); + rv_scratch_end(scratch); - return target; + return target; } #if !defined(RV_NO_GLOBAL_ALLOC) -RV_GLOBAL void* rv_mem_global_alloc_nz_(s64 size, s64 align) { return malloc(size); } +RV_GLOBAL void* rv_mem_global_alloc_nz_(s64 size, s64 align) { return malloc(size); } RV_GLOBAL void* rv_mem_global_realloc_nz_(void* old_ptr, s64 new_size, s64 align) { return realloc(old_ptr, new_size);} -RV_GLOBAL void rv_mem_global_alloc_free(void* ptr, s64 size) { free(ptr); } +RV_GLOBAL void rv_mem_global_alloc_free(void* ptr, s64 size) { free(ptr); } #endif diff --git a/src/platform/platform_core.h b/src/platform/platform_core.h @@ -86,7 +86,7 @@ #define rv_align_pow2(x,b) (((x) + (b) - 1)&(~((b) - 1))) -#define rv_array_size(__ARR) sizeof(__ARR) / sizeof(__ARR[0]) +#define rv_array_size(...) sizeof(__VA_ARGS__) / sizeof(__VA_ARGS__[0]) #define rv_abort(exit_code) rv_abort_msg_(__FILE__, __FUNCTION__, __LINE__, exit_code, "(no message)") #define rv_abort_msg(exit_code, ...) rv_abort_msg_(__FILE__, __FUNCTION__, __LINE__, exit_code, __VA_ARGS__) diff --git a/src/platform/platform_cracker.h b/src/platform/platform_cracker.h @@ -28,8 +28,8 @@ // Address sanitizer: // RV_ASAN_ENABLED // RV_NO_ASAN -// RV_ASAN_POISOIN(ptr, sz) -// RV_ASAN_UNPOISOIN(ptr, sz) +// RV_ASAN_POISON(ptr, sz) +// RV_ASAN_UNPOISON(ptr, sz) // // Language: // RV_LANG_C @@ -410,11 +410,11 @@ #if RV_ASAN_ENABLED #include <sanitizer/asan_interface.h> - #define RV_ASAN_POISOIN(ptr, sz) ASAN_POISON_MEMORY_REGION(ptr, sz) - #define RV_ASAN_UNPOISOIN(ptr, sz) ASAN_UNPOISON_MEMORY_REGION(ptr, sz) + #define RV_ASAN_POISON(ptr, sz) ASAN_POISON_MEMORY_REGION(ptr, sz) + #define RV_ASAN_UNPOISON(ptr, sz) ASAN_UNPOISON_MEMORY_REGION(ptr, sz) #else - #define RV_ASAN_POISOIN(ptr, sz) ((void)(ptr), (void)(sz)) - #define RV_ASAN_UNPOISOIN(ptr, sz) ((void)(ptr), (void)(sz)) + #define RV_ASAN_POISON(ptr, sz) ((void)(ptr), (void)(sz)) + #define RV_ASAN_UNPOISON(ptr, sz) ((void)(ptr), (void)(sz)) #endif #if RV_COMPILER_CL @@ -425,7 +425,8 @@ #define rv_alignof(T) __alignof__(T) #else #if !defined(rv_alignof) - #error alignof not defined for this compiler, try doing '#define rv_alignof(T) _Alignof(T)' + #define rv_alignof(T) offsetof(struct {char _; T z;}, z) + #warning alignof not defined for this compiler, try doing '#define rv_alignof(T) _Alignof(T)'? #endif #endif diff --git a/src/platform/platform_math.c b/src/platform/platform_math.c @@ -482,15 +482,13 @@ RV_GLOBAL rv_mat4 rv_mat4_mul(rv_mat4 m0, rv_mat4 m1) return m_res; } -RV_GLOBAL rv_mat4 rv_mat4_mul_list(s32 count, ...) +RV_GLOBAL rv_mat4 rv_mat4_mul_list_(rv_mat4* m_list, s64 m_list_len) { va_list ap; rv_mat4 m = rv_mat4_identity(); - va_start(ap, count); - for (uint32_t i = 0; i < count; ++i) { - m = rv_mat4_mul(m, va_arg(ap, rv_mat4)); + for (uint32_t i = 0; i < m_list_len; ++i) { + m = rv_mat4_mul(m, m_list[i]); } - va_end(ap); return m; } RV_GLOBAL rv_vec4 rv_mat4_mul_vec4(rv_mat4 m, rv_vec4 v) @@ -584,7 +582,7 @@ RV_GLOBAL rv_mat4 rv_mat4_recompose(rv_vec3 translation, rv_vec3 rotation, rv_ve rot[i] = rv_mat4_rotatev(rv_deg2rad(rotation.xyz[i]), direction_unary[i]); } - mat = rv_mat4_mul_list(3, rot[2], rot[1], rot[0]); + mat = rv_mat4_mul_list(rot[2], rot[1], rot[0]); float valid_scale[3] = {0}; for (uint32_t i = 0; i < 3; ++i) { diff --git a/src/platform/platform_math.h b/src/platform/platform_math.h @@ -103,7 +103,8 @@ RV_GLOBAL rv_mat4 rv_mat4_inverse(rv_mat4 m); RV_GLOBAL rv_mat4 rv_mat4_look_at(rv_vec3 position, rv_vec3 target, rv_vec3 up); RV_GLOBAL rv_mat4 rv_mat4_mul(rv_mat4 m0, rv_mat4 m1); -RV_GLOBAL rv_mat4 rv_mat4_mul_list(s32 count, ...); +RV_GLOBAL rv_mat4 rv_mat4_mul_list_(rv_mat4* m_list, s64 m_list_len); +#define rv_mat4_mul_list(...) rv_mat4_mul_list_((rv_mat4[]){__VA_ARGS__}, rv_array_size((rv_mat4[]){__VA_ARGS__})) RV_GLOBAL rv_vec4 rv_mat4_mul_vec4(rv_mat4 m, rv_vec4 v); RV_GLOBAL rv_vec3 rv_mat4_mul_vec3(rv_mat4 m, rv_vec3 v); diff --git a/src/platform/platform_types.h b/src/platform/platform_types.h @@ -96,7 +96,7 @@ typedef struct { #define rv_v4(...) ((rv_vec4){__VA_ARGS__}) #define rv_v4s(...) (rv_vec4){(s), (s), (s), (s)}) -typedef struct gs_mat4 { +typedef struct { union { rv_vec4 rows[4]; f32 m[4][4]; diff --git a/src/render/impl/opengl.c b/src/render/impl/opengl.c @@ -177,36 +177,59 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas case RV_RENDER_OBJ_OP_BIND: { if (ogl_state.bound_pip) { s32 bind_index = c->obj.vbo_bind.bind_index; + s32 base_offset = c->obj.vbo_bind.base_offset; + rv_vattr_bind_t* vattr_bind_override_list = c->obj.vbo_bind.vattr_override_first; glBindBuffer(GL_ARRAY_BUFFER, vbo->handle.u); // set vattrs - s64 stride = 0; + s32 auto_stride = 0; for (rv_vattr_t* v = ogl_state.bound_pip->vattr_first; v; v = v->next) { if (v->bind_index == bind_index) { - stride += rv_vattr_type_size(v->type); + bool32 found_override = false; + for (rv_vattr_bind_t* vo = vattr_bind_override_list; vo; vo = vo->next) { + if (vo->desc == v) { + found_override = true; + break; + } + } + if (!found_override) + auto_stride += rv_vattr_type_size(v->type); } } - s64 offset = 0; - s64 i = 0; + s32 auto_offset = 0; + s32 i = 0; for (rv_vattr_t* v = ogl_state.bound_pip->vattr_first; v; v = v->next, i++) { if (v->bind_index == bind_index) { glEnableVertexAttribArray(i); + s32 offset = auto_offset; + s32 stride = auto_stride; + s32 divisor = v->divisor; + bool32 found_override = false; + for (rv_vattr_bind_t* vo = vattr_bind_override_list; vo; vo = vo->next) { + if (vo->desc == v) { + offset = vo->offset; + stride = vo->stride; + divisor = vo->divisor; + break; + } + } switch (v->type) { - case RV_VATTR_TYPE_FLOAT4: glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; - case RV_VATTR_TYPE_FLOAT3: glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; - case RV_VATTR_TYPE_FLOAT2: glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; - case RV_VATTR_TYPE_FLOAT: glVertexAttribPointer(i, 1, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; - case RV_VATTR_TYPE_UINT4: glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, stride, (void*)offset); break; - case RV_VATTR_TYPE_UINT3: glVertexAttribIPointer(i, 3, GL_UNSIGNED_INT, stride, (void*)offset); break; - case RV_VATTR_TYPE_UINT2: glVertexAttribIPointer(i, 2, GL_UNSIGNED_INT, stride, (void*)offset); break; - case RV_VATTR_TYPE_UINT: glVertexAttribIPointer(i, 1, GL_UNSIGNED_INT, stride, (void*)offset); break; - case RV_VATTR_TYPE_BYTE: glVertexAttribPointer(i, 1, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; - case RV_VATTR_TYPE_BYTE2: glVertexAttribPointer(i, 2, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; - case RV_VATTR_TYPE_BYTE3: glVertexAttribPointer(i, 3, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; - case RV_VATTR_TYPE_BYTE4: glVertexAttribPointer(i, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; + case RV_VATTR_TYPE_FLOAT4: glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_FLOAT3: glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_FLOAT2: glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_FLOAT: glVertexAttribPointer(i, 1, GL_FLOAT, GL_FALSE, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_UINT4: glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_UINT3: glVertexAttribIPointer(i, 3, GL_UNSIGNED_INT, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_UINT2: glVertexAttribIPointer(i, 2, GL_UNSIGNED_INT, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_UINT: glVertexAttribIPointer(i, 1, GL_UNSIGNED_INT, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_BYTE: glVertexAttribPointer(i, 1, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_BYTE2: glVertexAttribPointer(i, 2, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_BYTE3: glVertexAttribPointer(i, 3, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)(s64)(base_offset + offset)); break; + case RV_VATTR_TYPE_BYTE4: glVertexAttribPointer(i, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)(s64)(base_offset + offset)); break; default: rv_unreachable(); break; } - offset += rv_vattr_type_size(v->type); + if (!found_override) + auto_offset += rv_vattr_type_size(v->type); if (v->divisor) { glVertexAttribDivisor(i, v->divisor); } diff --git a/src/render/render.h b/src/render/render.h @@ -100,22 +100,20 @@ typedef enum { RV_BUFFER_USAGE_STREAM, } rv_buffer_usage_t; -typedef struct rv_vbo_t rv_vbo_t; -struct rv_vbo_t { +typedef struct { void* data; s32 size; rv_buffer_usage_t usage; rv_render_handle_t handle; -}; +} rv_vbo_t; -typedef struct rv_ibo_t rv_ibo_t; -struct rv_ibo_t { +typedef struct { void* data; s32 size; s32 elem_size; rv_buffer_usage_t usage; rv_render_handle_t handle; -}; +} rv_ibo_t; typedef enum { RV_SHADER_TYPE_INVALID, @@ -159,6 +157,15 @@ struct rv_vattr_t { s32 divisor; }; +typedef struct rv_vattr_bind_t rv_vattr_bind_t; +struct rv_vattr_bind_t { + rv_vattr_bind_t* next; + rv_vattr_t* desc; + s32 offset; + s32 stride; + s32 divisor; +}; + typedef struct { rv_uniform_t* uniform_desc_first; rv_shader_node_t* shader_first; @@ -250,7 +257,11 @@ struct rv_command_t { struct {void* data; s64 size;} ibo_update; struct {void* data; s64 size;} vbo_update; - struct { s32 bind_index; } vbo_bind; + struct { + s32 bind_index; + s32 base_offset; + rv_vattr_bind_t* vattr_override_first; + } vbo_bind; struct { void* data; @@ -326,17 +337,20 @@ RV_GLOBAL rv_command_t rv_cmd_type(rv_command_type_t type); RV_GLOBAL rv_command_t rv_cmd_obj(rv_command_type_t type, rv_command_obj_operation_t operation, void* obj); RV_GLOBAL rv_command_t rv_cmd_uniform_update(rv_uniform_t* uniform, rv_uniform_variant_t value); -#define rv_cmd_push_type(arena, commands, _type) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd_type(_type)) -#define rv_cmd_insert_type(arena, commands, after, _type) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd_type(_type)) +#define rv_cmd_push_copy(arena, commands, ...) rv_cmd_copy(rv_cmd_push(arena, commands), (rv_command_t)__VA_ARGS__) +#define rv_cmd_insert_copy(arena, commands, after, ...) rv_cmd_copy(rv_cmd_insert(arena, commands, after), (rv_command_t)__VA_ARGS__) + +#define rv_cmd_push_type(arena, commands, _type) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd_type(_type)) +#define rv_cmd_insert_type(arena, commands, after, _type) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd_type(_type)) -#define rv_cmd_push_compound(arena, commands, _type, ...) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd(_type, __VA_ARGS__)) -#define rv_cmd_insert_compound(arena, commands, after, _type, ...) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd(_type, __VA_ARGS__)) +#define rv_cmd_push_compound(arena, commands, _type, ...) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd(_type, __VA_ARGS__)) +#define rv_cmd_insert_compound(arena, commands, after, _type, ...) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd(_type, __VA_ARGS__)) -#define rv_cmd_push_obj(arena, commands, _type, op, obj) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd_obj(_type, op, obj)) -#define rv_cmd_insert_obj(arena, commands, after, _type, op, obj) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd_obj(_type, op, obj)) +#define rv_cmd_push_obj(arena, commands, _type, op, obj) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd_obj(_type, op, obj)) +#define rv_cmd_insert_obj(arena, commands, after, _type, op, obj) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd_obj(_type, op, obj)) -#define rv_cmd_push_uniform_update(arena, commands, uniform, ...) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd_uniform_update(uniform, (rv_uniform_variant_t)__VA_ARGS__)) -#define rv_cmd_insert_uniform_update(arena, commands, after, uniform, ...) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd_uniform_update(uniform, (rv_uniform_variant_t)__VA_ARGS__)) +#define rv_cmd_push_uniform_update(arena, commands, uniform, ...) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd_uniform_update(uniform, (rv_uniform_variant_t)__VA_ARGS__)) +#define rv_cmd_insert_uniform_update(arena, commands, after, uniform, ...) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd_uniform_update(uniform, (rv_uniform_variant_t)__VA_ARGS__)) // command modification helpers RV_GLOBAL rv_render_clear_desc_t* rv_render_push_clear_desc(rv_arena* arena, rv_command_t* clear, rv_graphics_clear_flag_t flags); diff --git a/src/render/render_imdraw.h b/src/render/render_imdraw.h @@ -1,2 +0,0 @@ -////////////////////////////////////////////////////////////////// -// render_imdraw.h diff --git a/src/render/render_inc.c b/src/render/render_inc.c @@ -3,6 +3,7 @@ #if RV_WIN_ENABLED #include "render_helpers.c" + #include "render_vertex_cache.c" #if RV_RENDER_OPENGL #include "impl/opengl.c" diff --git a/src/render/render_inc.h b/src/render/render_inc.h @@ -3,4 +3,5 @@ #if RV_WIN_ENABLED #include "render.h" + #include "render_vertex_cache.h" #endif // RV_WIN_ENABLED diff --git a/src/render/render_vertex_cache.c b/src/render/render_vertex_cache.c @@ -0,0 +1,76 @@ +////////////////////////////////////////////////////////////////// +// render_vertex_cache.c + +RV_GLOBAL void rv_vertex_cache_create(rv_vertex_cache_ctx_t* vc, rv_vbo_t* vbo, s64 vertex_element_size) +{ + rv_vertex_cache_destroy(vc); + vc->vertex_element_size = vertex_element_size; + vc->vbo = vbo; + + // TODO(Samdal): + // Check if the arena implementation supports virtual paging first... + vc->vertex_arena = rv_arena_alloc(.flags = rv_arena_flag_no_chain, .reserve_size = GB(1)); +} + +RV_GLOBAL void rv_vertex_cache_destroy(rv_vertex_cache_ctx_t* vc) +{ + if (vc->vertex_arena) { + rv_arena_release(vc->vertex_arena); + } + *vc = (rv_vertex_cache_ctx_t){0}; +} + +RV_GLOBAL void* rv_vertex_cache_push(rv_vertex_cache_ctx_t* vc, const void* new) +{ + rv_assert(vc->vertex_element_size > 0); + + void* res = rv_arena_push(vc->vertex_arena, vc->vertex_element_size, 1); + rv_mem_copy(res, new, vc->vertex_element_size); + + if (!vc->vertex_begin) { + vc->vertex_begin = res; + rv_assert(vc->vertex_total_size == 0); + rv_assert(vc->committed_vertecies_so_far == 0); + } + + vc->current_instance_count += 1; + vc->vertex_total_size += vc->vertex_element_size; + + return res; +} + +RV_GLOBAL void rv_vertex_cache_break(rv_vertex_cache_ctx_t* vc, rv_command_t* bind_out, s64* instances_out) { + + *bind_out = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vc->vbo); + bind_out->obj.vbo_bind.base_offset = vc->committed_vertecies_so_far; + + *instances_out = vc->current_instance_count; + + rv_command_t res = {0}; + + vc->committed_vertecies_so_far += vc->current_instance_count * vc->vertex_element_size; + + vc->current_instance_count = 0; +} + +RV_GLOBAL rv_command_t rv_vetex_cache_upload_and_reset(rv_vertex_cache_ctx_t* vc, rv_arena* arena) +{ + // make and push command + rv_command_t update_cmd = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_UPDATE, vc->vbo); + + // copy over data into new arena + + void* data = rv_arena_push(arena, vc->vertex_total_size, 8); + rv_mem_copy(data, vc->vertex_begin, vc->vertex_total_size); + update_cmd.obj.vbo_update.data = data; + update_cmd.obj.vbo_update.size = vc->vertex_total_size; + + // reset + rv_arena_clear(vc->vertex_arena); + vc->vertex_begin = NULL; + vc->current_instance_count = 0; + vc->committed_vertecies_so_far = 0; + vc->vertex_total_size = 0; + + return update_cmd; +} diff --git a/src/render/render_vertex_cache.h b/src/render/render_vertex_cache.h @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////// +// render_vertex_cache.h + +typedef struct { + // initialization + s64 vertex_element_size; + rv_arena* vertex_arena; + rv_vbo_t* vbo; + + // construction + s64 current_instance_count; + s64 committed_vertecies_so_far; + + // upload + void* vertex_begin; + s64 vertex_total_size; +} rv_vertex_cache_ctx_t; + +RV_GLOBAL void rv_vertex_cache_create(rv_vertex_cache_ctx_t* vc, rv_vbo_t* vbo, s64 vertex_element_size); +RV_GLOBAL void rv_vertex_cache_destroy(rv_vertex_cache_ctx_t* vc); + +RV_GLOBAL void* rv_vertex_cache_push(rv_vertex_cache_ctx_t* vc, const void* new); +RV_GLOBAL void rv_vertex_cache_break(rv_vertex_cache_ctx_t* vc, rv_command_t* bind_out, s64* instances_out); +// returns draw command with filled data + +RV_GLOBAL rv_command_t rv_vetex_cache_upload_and_reset(rv_vertex_cache_ctx_t* vc, rv_arena* arena);