commit 79e2c5d6ed704a7e372d24ff7f3978b65ce1e203
parent 8adebc64dcbd0735c27fd4f392a3ec0d81b884ee
Author: Samdal <samdal@protonmail.com>
Date: Thu, 27 Mar 2025 15:14:05 +0100
idraw2d index buffer
Diffstat:
7 files changed, 95 insertions(+), 48 deletions(-)
diff --git a/examples/simple_texture.c b/examples/simple_texture.c
@@ -20,8 +20,8 @@ f32 v_data[] = {
// Index data for quad
uint32_t i_data[] = {
- 0, 3, 2, // First Triangle
- 0, 1, 3 // Second Triangle
+ 0, 1, 2, // First Triangle
+ 1, 2, 3 // Second Triangle
};
rv_str8 v_src = S("#version 330 core\n" rv_strify(
diff --git a/src/render/impl/opengl.c b/src/render/impl/opengl.c
@@ -686,9 +686,9 @@ RV_INTERNAL void ogl_handle_command(rv_command_t* c) {
case 1: itype = GL_UNSIGNED_BYTE; break;
}
if (c->draw.instances) {
- glDrawElementsInstanced(prim, c->draw.count, itype, (void*)(s64)c->draw.first, c->draw.instances);
+ glDrawElementsInstanced(prim, c->draw.count, itype, (void*)(c->draw.first * ogl_ctx.bound_ibo->elem_size), c->draw.instances);
} else {
- glDrawElements(prim, c->draw.count, itype, (void*)(s64)c->draw.first);
+ glDrawElements(prim, c->draw.count, itype, (void*)(c->draw.first * ogl_ctx.bound_ibo->elem_size));
}
} else {
if (c->draw.instances) {
diff --git a/src/render/render.h b/src/render/render.h
@@ -29,8 +29,8 @@ typedef enum {
} rv_texture_wrap_t;
typedef enum {
- RV_TEXTURE_FILTER_LINEAR,
RV_TEXTURE_FILTER_NEAREST,
+ RV_TEXTURE_FILTER_LINEAR,
} rv_texture_filter_t;
typedef struct {
@@ -328,7 +328,7 @@ struct rv_command_t {
} obj;
struct {
rv_primitive_type_t primitive;
- s32 first;
+ s64 first; // first index
s64 count;
s64 instances;
} draw;
diff --git a/src/util/util_bump_cache.c b/src/util/util_bump_cache.c
@@ -8,39 +8,43 @@ RV_GLOBAL void rv_bump_cache_create(rv_bump_cache_ctx_t* bc, s64 element_size)
// TODO(Samdal):
// Check if the arena implementation supports virtual paging first...
- bc->bump_arena = rv_arena_alloc(.flags = rv_arena_flag_no_chain, .reserve_size = GB(1));
+ bc->arena = rv_arena_alloc(.flags = rv_arena_flag_no_chain, .reserve_size = GB(1));
}
RV_GLOBAL void rv_bump_cache_destroy(rv_bump_cache_ctx_t* bc)
{
- if (bc->bump_arena) {
- rv_arena_release(bc->bump_arena);
+ if (bc->arena) {
+ rv_arena_release(bc->arena);
}
*bc = (rv_bump_cache_ctx_t){0};
}
RV_GLOBAL void* rv_bump_cache_push(rv_bump_cache_ctx_t* bc, const void* new)
{
+ return rv_bump_cache_push_many(bc, new, 1);
+}
+RV_GLOBAL void* rv_bump_cache_push_many(rv_bump_cache_ctx_t* bc, const void* new, s64 count)
+{
rv_assert(bc->element_size > 0);
- void* res = rv_arena_push(bc->bump_arena, bc->element_size, 1);
- rv_mem_copy(res, new, bc->element_size);
+ void* res = rv_arena_push(bc->arena, bc->element_size * count, 1);
+ rv_mem_copy(res, new, bc->element_size * count);
- if (!bc->bump_begin) {
- bc->bump_begin = res;
- rv_assert(bc->bump_total_size == 0);
+ if (!bc->begin) {
+ bc->begin = res;
+ rv_assert(bc->total_count == 0);
rv_assert(bc->committed_so_far == 0);
}
- bc->current_count += 1;
- bc->bump_total_size += bc->element_size;
+ bc->current_count += count;
+ bc->total_count += count;
return res;
}
RV_GLOBAL void rv_bump_cache_break(rv_bump_cache_ctx_t* bc, s64* offset_out, s64* count_out) {
- *offset_out = bc->committed_so_far;
- *count_out = bc->current_count;
+ if (offset_out) *offset_out = bc->committed_so_far;
+ if (count_out) *count_out = bc->current_count;
rv_command_t res = {0};
@@ -52,14 +56,14 @@ RV_GLOBAL void rv_bump_cache_break(rv_bump_cache_ctx_t* bc, s64* offset_out, s64
RV_GLOBAL void rv_bump_cache_upload_and_reset(rv_bump_cache_ctx_t* bc, rv_arena* arena, void** data_out, s64* size_out)
{
// copy over data into new arena
- *data_out = rv_arena_push(arena, bc->bump_total_size, 8);
- rv_mem_copy(*data_out, bc->bump_begin, bc->bump_total_size);
- *size_out = bc->bump_total_size;
+ *data_out = rv_arena_push(arena, bc->total_count * bc->element_size, 8);
+ rv_mem_copy(*data_out, bc->begin, bc->total_count * bc->element_size);
+ *size_out = bc->total_count * bc->element_size;
// reset
- rv_arena_clear(bc->bump_arena);
- bc->bump_begin = NULL;
+ rv_arena_clear(bc->arena);
+ bc->begin = NULL;
bc->current_count = 0;
bc->committed_so_far = 0;
- bc->bump_total_size = 0;
+ bc->total_count = 0;
}
diff --git a/src/util/util_bump_cache.h b/src/util/util_bump_cache.h
@@ -4,21 +4,22 @@
typedef struct {
// initialization
s64 element_size;
- rv_arena* bump_arena;
+ rv_arena* arena;
// construction
s64 current_count;
s64 committed_so_far;
// upload
- void* bump_begin;
- s64 bump_total_size;
+ void* begin;
+ s64 total_count;
} rv_bump_cache_ctx_t;
RV_GLOBAL void rv_bump_cache_create(rv_bump_cache_ctx_t* bc, s64 element_size);
RV_GLOBAL void rv_bump_cache_destroy(rv_bump_cache_ctx_t* bc);
RV_GLOBAL void* rv_bump_cache_push(rv_bump_cache_ctx_t* bc, const void* new);
+RV_GLOBAL void* rv_bump_cache_push_many(rv_bump_cache_ctx_t* bc, const void* new, s64 count);
RV_GLOBAL void rv_bump_cache_break(rv_bump_cache_ctx_t* bc, s64* offset_out, s64* count_out);
// returns draw command with filled data
diff --git a/src/util/util_idraw2d.c b/src/util/util_idraw2d.c
@@ -57,6 +57,7 @@ RV_GLOBAL void rvi2d_create(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_lis
// make render objects
ctx->vbo = rv_push_compound(ctx->permanent_arena, rv_vbo_t, {.usage = RV_BUFFER_USAGE_DYNAMIC});
+ ctx->ibo = rv_push_compound(ctx->permanent_arena, rv_ibo_t, {.usage = RV_BUFFER_USAGE_DYNAMIC, .elem_size = sizeof(u32)});
rv_shader_t* vert = rv_push_compound(ctx->permanent_arena, rv_shader_t, {.source = rv_idraw2d_v_src, .type = RV_SHADER_TYPE_VERTEX});
rv_shader_t* frag = rv_push_compound(ctx->permanent_arena, rv_shader_t, {.source = rv_idraw2d_f_src, .type = RV_SHADER_TYPE_FRAGMENT});
ctx->pip = rv_push(ctx->permanent_arena, rv_pipeline_t);
@@ -73,17 +74,23 @@ RV_GLOBAL void rvi2d_create(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_lis
// add creation commands
rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, ctx->vbo);
+ rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_CREATE, ctx->ibo);
rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, vert);
rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, frag);
rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE, ctx->pip);
rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_DESTROY, frag); // don't need anymore
rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_DESTROY, vert); // don't need anymore
- rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, ctx->pip);
- rv_cmd_push_uniform_update(arena, create_commands, ctx->u_omit_tex, {.v_f32 = 1.0f});
- rv_cmd_push_uniform_update(arena, create_commands, ctx->u_resolution, {.v_vec2 = rv_v2(1,1)});
- rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL);
+ { // set default uniforms
+ rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, ctx->pip);
+ rv_cmd_push_uniform_update(arena, create_commands, ctx->u_omit_tex, {.v_f32 = 1.0f});
+ ctx->u_omit_tex_last = 1.0f;
+ rv_cmd_push_uniform_update(arena, create_commands, ctx->u_resolution, {.v_vec2 = rv_v2(1,1)});
+ ctx->u_resolution_last = rv_v2(1,1);
+ rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL);
+ }
rv_bump_cache_create(&ctx->vertex, sizeof(rv_vec2) + sizeof(rv_vec2) + sizeof(rv_vec4));
+ rv_bump_cache_create(&ctx->index, sizeof(u32));
ctx->default_binds = rv_push(ctx->permanent_arena, rv_command_list_node_t);
rv_cmd_push_obj(ctx->permanent_arena, &ctx->default_binds->commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, ctx->pip);
@@ -101,11 +108,13 @@ RV_GLOBAL void rvi2d_destroy(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_li
rv_pipeline_t* pip_copy = rv_push_copy(arena, rv_pipeline_t, ctx->ibo);
rv_cmd_push_obj(arena, destroy_commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_DESTROY, vbo_vertex_copy);
+ rv_cmd_push_obj(arena, destroy_commands, RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_DESTROY, ibo_copy);
rv_cmd_push_obj(arena, destroy_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_DESTROY, pip_copy);
rv_arena_release(ctx->arena);
rv_arena_release(ctx->permanent_arena);
rv_bump_cache_destroy(&ctx->vertex);
+ rv_bump_cache_destroy(&ctx->index);
*ctx = (rv_idraw2d_ctx){0};
}
@@ -118,13 +127,22 @@ RV_GLOBAL rv_command_t* rvi2d_draw_and_reset(rv_idraw2d_ctx* ctx, rv_arena* aren
{
rv_command_t* res = rvi2d_break(ctx);
- rv_command_t update_cmd = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_UPDATE, ctx->vbo);
+ { // update vbo
+ rv_command_t update_vbo_cmd = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_UPDATE, ctx->vbo);
+ rv_bump_cache_upload_and_reset(&ctx->vertex, arena, &update_vbo_cmd.obj.vbo_update.data, &update_vbo_cmd.obj.vbo_update.size);
+ rv_cmd_push_copy(arena, render_commands, update_vbo_cmd);
+ }
- rv_bump_cache_upload_and_reset(&ctx->vertex, arena, &update_cmd.obj.vbo_update.data, &update_cmd.obj.vbo_update.size);
- rv_cmd_push_copy(arena, render_commands, update_cmd);
+ { // update ibo
+ rv_command_t update_ibo_cmd = rv_cmd_obj(RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_UPDATE, ctx->ibo);
+ rv_bump_cache_upload_and_reset(&ctx->index, arena, &update_ibo_cmd.obj.ibo_update.data, &update_ibo_cmd.obj.ibo_update.size);
+ rv_cmd_push_copy(arena, render_commands, update_ibo_cmd);
+ }
+ // push draw commands
rv_render_copy_commands(arena, render_commands, &ctx->commands);
+ // check that custom binds steck is where it started
if (ctx->custom_binds_stack->next) {
rv_unreachable();
ctx->custom_binds_stack = NULL;
@@ -148,8 +166,9 @@ RV_GLOBAL rv_command_t* rvi2d_break(rv_idraw2d_ctx* ctx)
if (ctx->last_bind != ctx->custom_binds_stack) {
rv_render_copy_commands(ctx->arena, &ctx->commands, &ctx->custom_binds_stack->commands);
- // force rebind vbo
+ // force rebind vbo and ibo
rv_cmd_push_obj(ctx->arena, &ctx->commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, ctx->vbo);
+ rv_cmd_push_obj(ctx->arena, &ctx->commands, RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_BIND, ctx->ibo);
// force update all uniforms
rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_resolution, {.v_vec2 = ctx->u_resolution_last});
rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_tex, {.v_tex = ctx->u_tex_last});
@@ -159,9 +178,10 @@ RV_GLOBAL rv_command_t* rvi2d_break(rv_idraw2d_ctx* ctx)
}
s64 first, count;
- rv_bump_cache_break(&ctx->vertex, &first, &count);
+ rv_bump_cache_break(&ctx->vertex, NULL, NULL);
+ rv_bump_cache_break(&ctx->index, &first, &count);
- if (count > 0 ) {
+ if (count > 0) {
rv_command_t draw_cmd = {
.type = RV_COMMAND_DRAW,
.draw = {
@@ -209,7 +229,7 @@ RV_GLOBAL rv_command_t* rvi2d_tex_ex(rv_idraw2d_ctx* ctx, rv_texture_t* tex, boo
if (tex) {
rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_omit_tex, {.v_f32 = is_red_channel ? -1.0f : 0.0f});
- ctx->u_omit_tex_last = 0.0f;
+ ctx->u_omit_tex_last = is_red_channel ? -1.0f : 0.0f;
} else {
rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_omit_tex, {.v_f32 = 1.0f});
ctx->u_omit_tex_last = 1.0f;
@@ -251,9 +271,11 @@ RV_GLOBAL rv_command_t* rvi2d_custom_binds_pop(rv_idraw2d_ctx* ctx)
RV_GLOBAL void rvi2d_triangle(rv_idraw2d_ctx* ctx,
rv_vec2 pos_a, rv_vec2 pos_b, rv_vec2 pos_c,
- rv_vec2 uv_a, rv_vec2 uv_b, rv_vec2 uv_c,
+ rv_vec2 uv_a, rv_vec2 uv_b, rv_vec2 uv_c,
rv_color_t color)
{
+ u32 last_index = ctx->vertex.total_count;
+
rv_vec4 c = rv_vec4_from_color(color);
struct {
rv_vec2 pos, uv;
@@ -263,9 +285,10 @@ RV_GLOBAL void rvi2d_triangle(rv_idraw2d_ctx* ctx,
{.pos = pos_b, .uv = uv_b, .color = c},
{.pos = pos_c, .uv = uv_c, .color = c},
};
- rv_bump_cache_push(&ctx->vertex, ©_from[0]);
- rv_bump_cache_push(&ctx->vertex, ©_from[1]);
- rv_bump_cache_push(&ctx->vertex, ©_from[2]);
+ rv_bump_cache_push_many(&ctx->vertex, ©_from, 3);
+
+ u32 indices[3] = {last_index + 0, last_index + 1, last_index + 2};
+ rv_bump_cache_push_many(&ctx->index, &indices, 3);
}
RV_GLOBAL void rvi2d_quad(rv_idraw2d_ctx* ctx,
@@ -273,10 +296,29 @@ RV_GLOBAL void rvi2d_quad(rv_idraw2d_ctx* ctx,
rv_vec2 uv_tl, rv_vec2 uv_tr, rv_vec2 uv_bl, rv_vec2 uv_br,
rv_color_t color)
{
- rvi2d_triangle(ctx, pos_tl, pos_tr, pos_bl,
- uv_tl, uv_tr, uv_bl, color);
- rvi2d_triangle(ctx, pos_tr, pos_bl, pos_br,
- uv_tr, uv_bl, uv_br, color);
+ u32 index_begin = ctx->vertex.total_count;
+
+ rv_vec4 c = rv_vec4_from_color(color);
+ struct {
+ rv_vec2 pos, uv;
+ rv_vec4 color;
+ } copy_from[4] = {
+ {.pos = pos_tl, .uv = uv_tl, .color = c},
+ {.pos = pos_tr, .uv = uv_tr, .color = c},
+ {.pos = pos_bl, .uv = uv_bl, .color = c},
+ {.pos = pos_br, .uv = uv_br, .color = c},
+ };
+ rv_bump_cache_push_many(&ctx->vertex, ©_from, 4);
+
+ u32 indices[6] = {
+ index_begin + 0, // tl +--+
+ index_begin + 1, // tr | /
+ index_begin + 2, // bl +/
+ index_begin + 1, // tr /+
+ index_begin + 2, // bl / |
+ index_begin + 3, // br +--+
+ };
+ rv_bump_cache_push_many(&ctx->index, &indices, 6);
}
//////////////////////////////////////////////////////////////////
diff --git a/src/util/util_idraw2d.h b/src/util/util_idraw2d.h
@@ -2,7 +2,6 @@
// util_idraw2d.h
//
// TODO(Samdal):
-// Use an index buffer (?)
// Implement line drawing
// Implement circle drawing
@@ -29,6 +28,7 @@ typedef struct {
// state
rv_bump_cache_ctx_t vertex;
+ rv_bump_cache_ctx_t index;
rv_command_list_t commands;
rv_command_t* last_commited_command;
rv_texture_t* last_tex;
@@ -72,7 +72,7 @@ RV_GLOBAL rv_command_t* rvi2d_custom_binds_push(rv_idraw2d_ctx* ctx, rv_command_
RV_GLOBAL rv_command_t* rvi2d_custom_binds_pop(rv_idraw2d_ctx* ctx);
RV_GLOBAL void rvi2d_triangle(rv_idraw2d_ctx* ctx,
rv_vec2 pos_a, rv_vec2 pos_b, rv_vec2 pos_c,
- rv_vec2 uv_a, rv_vec2 uv_b, rv_vec2 uv_c,
+ rv_vec2 uv_a, rv_vec2 uv_b, rv_vec2 uv_c,
rv_color_t color);
RV_GLOBAL void rvi2d_quad(rv_idraw2d_ctx* ctx,
rv_vec2 pos_tl, rv_vec2 pos_tr, rv_vec2 pos_bl, rv_vec2 pos_br,