From a5adfacdfd6dbb52bd5d1438eef90a370976531e Mon Sep 17 00:00:00 2001 From: Roz K Date: Tue, 3 Jan 2023 14:05:25 +0100 Subject: [PATCH] Use mesh indices in batch. --- __init__.py | 18 +- cpp/render.hpp | 14 +- cpp/render/render_opengles.cpp | 331 +++++++++++++++++---------------- cpp/render/render_opengles.hpp | 4 +- 4 files changed, 184 insertions(+), 183 deletions(-) diff --git a/__init__.py b/__init__.py index c32024f..bbbd4c9 100644 --- a/__init__.py +++ b/__init__.py @@ -391,6 +391,15 @@ create_batch.argtypes = ( ctypes.c_uint, # max_size ctypes.c_char_p) # params_format +fill_batch = _engine.rk_fill_batch +fill_batch.restype = None +fill_batch.argtypes = ( + ctypes.c_void_p, # batch + ctypes.c_uint, # count + ctypes.POINTER(ctypes.c_ubyte), # flags + ctypes.POINTER(ctypes.c_ushort), # meshes + ctypes.POINTER(ctypes.c_void_p)) # params + clear_buffer = _engine.rk_clear_buffer clear_buffer.restype = None clear_buffer.argtypes = ( @@ -450,15 +459,6 @@ draw_triangles.restype = None draw_triangles.argtypes = ( ctypes.c_void_p,) # triangles -fill_batch = _engine.rk_fill_batch -fill_batch.restype = None -fill_batch.argtypes = ( - ctypes.c_void_p, # batch - ctypes.c_uint, # count - ctypes.POINTER(ctypes.c_ubyte), # flags - ctypes.POINTER(ctypes.c_uint), # meshes - ctypes.POINTER(ctypes.c_void_p)) # params - draw_batch = _engine.rk_draw_batch draw_batch.restype = None draw_batch.argtypes = ( diff --git a/cpp/render.hpp b/cpp/render.hpp index 6773a66..efdde96 100644 --- a/cpp/render.hpp +++ b/cpp/render.hpp @@ -125,6 +125,13 @@ RK_EXPORT rk_batch_t rk_create_batch( rk_uint max_size, rk_param_format const * params_format); +RK_EXPORT void rk_fill_batch( + rk_batch_t batch, + rk_uint count, + rk_instance_flags const * flags, + rk_ushort const * meshes, + rk_ubyte const * const * params); + RK_EXPORT void rk_clear_buffer( rk_bool pixels, rk_bool depth, @@ -164,13 +171,6 @@ RK_EXPORT void rk_select_texture( RK_EXPORT void rk_draw_triangles( rk_triangles_t triangles); -RK_EXPORT void rk_fill_batch( - rk_batch_t batch, - rk_uint count, - rk_instance_flags const * flags, - rk_mesh const * meshes, - rk_ubyte const * const * params); - RK_EXPORT void rk_draw_batch( rk_batch_t batch); diff --git a/cpp/render/render_opengles.cpp b/cpp/render/render_opengles.cpp index b0a1407..0d0246e 100644 --- a/cpp/render/render_opengles.cpp +++ b/cpp/render/render_opengles.cpp @@ -548,12 +548,12 @@ rk_batch_t rk_create_batch( batch->ncommands = 0; batch->ninstances = 0; batch->max_size = max_size; - batch->max_meshes = vertices->nmeshes; batch->nparams = nparams; + batch->vertices = vertices; batch->flags = new rk_instance_flags[max_size]; - batch->meshes = new rk_mesh[max_size]; + batch->meshes = new rk_ushort[max_size]; batch->indices = new rk_ushort[max_size]; - batch->commands = new rk_command[batch->max_meshes]; + batch->commands = new rk_command[vertices->nmeshes]; if (nparams) { batch->params = new rk_parameter[nparams]; } else { @@ -577,7 +577,7 @@ rk_batch_t rk_create_batch( if (rk_MultiDrawElementsIndirect) { glGenBuffers(1, &batch->commands_buffer); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, batch->commands_buffer); - glBufferData(GL_DRAW_INDIRECT_BUFFER, batch->max_meshes * sizeof(rk_command), nullptr, GL_DYNAMIC_DRAW); + glBufferData(GL_DRAW_INDIRECT_BUFFER, vertices->nmeshes * sizeof(rk_command), nullptr, GL_DYNAMIC_DRAW); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); } if (nparams) { @@ -690,6 +690,168 @@ rk_batch_t rk_create_batch( return reinterpret_cast(batch); } +static void rk_sort_batch( + rk_batch const & batch) { + rk_instance_flags const * flags = batch.flags; + rk_ushort * indices = batch.indices; + for (unsigned index = 0; index < batch.count; ++index, ++flags) { + if ((*flags & RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) == RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) { + *indices++ = index; + } + } + batch.ninstances = indices - batch.indices; + batch.ncommands = 0; + if (batch.ninstances) { + rk_command * const last_command = batch.commands + batch.vertices->nmeshes; + rk_command * command = batch.commands; + rk_ushort * base = batch.indices; + rk_ushort * const last = batch.indices + batch.ninstances; + for (rk_ushort * first = batch.indices; first < last && command < last_command; base = first, ++command) { + unsigned const mesh_index = batch.meshes[*first++]; + for ( ; first < last && mesh_index == batch.meshes[*first]; ++first) { + } + for (rk_ushort * second = first; second < last; ++second) { + unsigned const index = *second; + if (mesh_index == batch.meshes[index]) { + *second = *first; + *first++ = index; + } + } + rk_mesh const & mesh = batch.vertices->meshes[mesh_index]; + command->nvertices = static_cast(mesh.ntriangles) * 3; + command->ninstances = first - base; + command->base_index = mesh.base_index; + command->base_vertex = 0; + command->base_instance = base - batch.indices; + } + batch.ncommands = command - batch.commands; + if (rk_MultiDrawElementsIndirect && batch.ncommands) { + glBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, batch.ncommands * sizeof(rk_command), batch.commands); + } + } + batch.state = RK_BATCH_STATE_SORTED; +} + +static void rk_pack_batch( + rk_batch const & batch) { + if (batch.nparams) { + glBindBuffer(GL_ARRAY_BUFFER, batch.params_buffer); + for (rk_parameter const * param = batch.params; param < batch.params + batch.nparams; ++param) { + if (param->dirty) { + param->dirty = false; + if (batch.ninstances) { + rk_ubyte * const dst = reinterpret_cast( + glMapBufferRange(GL_ARRAY_BUFFER, param->offset, batch.ninstances * param->dst_size, + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT)); + if (dst) { + param->packer(batch.ninstances, batch.indices, dst, param->source); + glUnmapBuffer(GL_ARRAY_BUFFER); + } + } + } + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + batch.state = RK_BATCH_STATE_PACKED; +} + +static bool rk_compare_replace( + void * __restrict _dst, + void const * __restrict _src, + unsigned const size) { + rk_ulong hash = 0; + rk_ulong * dst = reinterpret_cast(_dst); + rk_ulong const * src = reinterpret_cast(_src); + unsigned count = size / sizeof(rk_ulong); + unsigned remain = (size - count * sizeof(rk_ulong)); + if (count) { + do { + hash |= *dst ^ *src; + *dst++ = *src++; + } while(--count > 0); + } + rk_ubyte * rdst = reinterpret_cast(dst); + rk_ubyte const * rsrc = reinterpret_cast(src); + if (remain) { + do { + hash |= *rdst ^ *rsrc; + *rdst++ = *rsrc++; + } while(--remain > 0); + } + return (hash != 0); +} + +void rk_fill_batch( + rk_batch_t _batch, + rk_uint count, + rk_instance_flags const * flags, + rk_ushort const * meshes, + rk_ubyte const * const * params) { + rk_batch const * const batch = reinterpret_cast(_batch); + if (!batch || !count || count > batch->max_size) { + rk_printf("rk_fill_batch(): invalid params."); + return; + } + bool got_any_params = false; + bool got_all_params = !batch->nparams; + if (batch->nparams) { + got_all_params = (params != nullptr); + if (params) { + for (rk_ubyte const * const * param = params; param < params + batch->nparams; ++param) { + bool const got_param = (*param != nullptr); + got_any_params |= got_param; + got_all_params &= got_param; + } + } + } + bool const is_empty = (batch->state < RK_BATCH_STATE_FILLED); + bool const resized = (count != batch->count); + bool const got_everything = (flags && meshes && got_all_params); + if (is_empty && !got_everything) { + rk_printf("rk_fill_batch(): cannot freeze and empty batch."); + return; + } else if (count > batch->count && !got_everything) { + rk_printf("rk_fill_batch(): cannot grow a frozen batch."); + return; + } + batch->count = count; + bool const cmp_flags = + (flags && rk_compare_replace(batch->flags, flags, batch->count * sizeof(rk_instance_flags))); + bool const cmp_meshes = + (meshes && rk_compare_replace(batch->meshes, meshes, batch->count * sizeof(rk_mesh))); + bool const need_sorting = (cmp_flags || cmp_meshes || resized); + if (batch->nparams) { + rk_parameter const * const last_param = batch->params + batch->nparams; + if (got_any_params) { + rk_ubyte const * const * src = params; + for (rk_parameter const * dst = batch->params; dst < last_param; ++dst, ++src) { + dst->dirty = + (*src && rk_compare_replace(dst->source, *src, batch->count * dst->src_size)) || need_sorting; + } + } else if (need_sorting) { + for (rk_parameter const * dst = batch->params; dst < last_param; ++dst) { + dst->dirty = true; + } + } + } + if (is_empty) { + glBindVertexArray(batch->vertex_array); + if (rk_MultiDrawElementsIndirect) { + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, batch->commands_buffer); + } + rk_sort_batch(*batch); + rk_pack_batch(*batch); + if (rk_MultiDrawElementsIndirect) { + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); + } + glBindVertexArray(0); + } else if (need_sorting) { + batch->state = RK_BATCH_STATE_FILLED; + } else { + batch->state = RK_BATCH_STATE_SORTED; + } +} + void rk_clear_buffer( rk_bool pixels, rk_bool depth, @@ -785,167 +947,6 @@ RK_EXPORT void rk_draw_triangles( } } -static void rk_sort_batch( - rk_batch const & batch) { - rk_instance_flags const * flags = batch.flags; - rk_ushort * indices = batch.indices; - for (unsigned index = 0; index < batch.count; ++index, ++flags) { - if ((*flags & RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) == RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) { - *indices++ = index; - } - } - batch.ninstances = indices - batch.indices; - batch.ncommands = 0; - if (batch.ninstances) { - rk_command * const last_command = batch.commands + batch.max_meshes; - rk_command * command = batch.commands; - rk_ushort * base = batch.indices; - rk_ushort * const last = batch.indices + batch.ninstances; - for (rk_ushort * first = batch.indices; first < last && command < last_command; base = first, ++command) { - rk_mesh const & mesh = batch.meshes[*first++]; - for ( ; first < last && batch.meshes[*first].packed == mesh.packed; ++first) { - } - for (rk_ushort * second = first; second < last; ++second) { - unsigned const index = *second; - if (batch.meshes[index].packed == mesh.packed) { - *second = *first; - *first++ = index; - } - } - command->nvertices = static_cast(mesh.ntriangles) * 3; - command->ninstances = first - base; - command->base_index = mesh.base_index; - command->base_vertex = 0; - command->base_instance = base - batch.indices; - } - batch.ncommands = command - batch.commands; - if (rk_MultiDrawElementsIndirect && batch.ncommands) { - glBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, batch.ncommands * sizeof(rk_command), batch.commands); - } - } - batch.state = RK_BATCH_STATE_SORTED; -} - -static void rk_pack_batch( - rk_batch const & batch) { - if (batch.nparams) { - glBindBuffer(GL_ARRAY_BUFFER, batch.params_buffer); - for (rk_parameter const * param = batch.params; param < batch.params + batch.nparams; ++param) { - if (param->dirty) { - param->dirty = false; - if (batch.ninstances) { - rk_ubyte * const dst = reinterpret_cast( - glMapBufferRange(GL_ARRAY_BUFFER, param->offset, batch.ninstances * param->dst_size, - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT)); - if (dst) { - param->packer(batch.ninstances, batch.indices, dst, param->source); - glUnmapBuffer(GL_ARRAY_BUFFER); - } - } - } - } - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - batch.state = RK_BATCH_STATE_PACKED; -} - -static bool rk_compare_replace( - void * __restrict _dst, - void const * __restrict _src, - unsigned const size) { - rk_ulong hash = 0; - rk_ulong * dst = reinterpret_cast(_dst); - rk_ulong const * src = reinterpret_cast(_src); - unsigned count = size / sizeof(rk_ulong); - unsigned remain = (size - count * sizeof(rk_ulong)); - if (count) { - do { - hash |= *dst ^ *src; - *dst++ = *src++; - } while(--count > 0); - } - rk_ubyte * rdst = reinterpret_cast(dst); - rk_ubyte const * rsrc = reinterpret_cast(src); - if (remain) { - do { - hash |= *rdst ^ *rsrc; - *rdst++ = *rsrc++; - } while(--remain > 0); - } - return (hash != 0); -} - -void rk_fill_batch( - rk_batch_t _batch, - rk_uint count, - rk_instance_flags const * flags, - rk_mesh const * meshes, - rk_ubyte const * const * params) { - rk_batch const * const batch = reinterpret_cast(_batch); - if (!batch || !count || count > batch->max_size) { - rk_printf("rk_fill_batch(): invalid params."); - return; - } - bool got_any_params = false; - bool got_all_params = !batch->nparams; - if (batch->nparams) { - got_all_params = (params != nullptr); - if (params) { - for (rk_ubyte const * const * param = params; param < params + batch->nparams; ++param) { - bool const got_param = (*param != nullptr); - got_any_params |= got_param; - got_all_params &= got_param; - } - } - } - bool const is_empty = (batch->state < RK_BATCH_STATE_FILLED); - bool const resized = (count != batch->count); - bool const got_everything = (flags && meshes && got_all_params); - if (is_empty && !got_everything) { - rk_printf("rk_fill_batch(): cannot freeze and empty batch."); - return; - } else if (count > batch->count && !got_everything) { - rk_printf("rk_fill_batch(): cannot grow a frozen batch."); - return; - } - batch->count = count; - bool const cmp_flags = - (flags && rk_compare_replace(batch->flags, flags, batch->count * sizeof(rk_instance_flags))); - bool const cmp_meshes = - (meshes && rk_compare_replace(batch->meshes, meshes, batch->count * sizeof(rk_mesh))); - bool const need_sorting = (cmp_flags || cmp_meshes || resized); - if (batch->nparams) { - rk_parameter const * const last_param = batch->params + batch->nparams; - if (got_any_params) { - rk_ubyte const * const * src = params; - for (rk_parameter const * dst = batch->params; dst < last_param; ++dst, ++src) { - dst->dirty = - (*src && rk_compare_replace(dst->source, *src, batch->count * dst->src_size)) || need_sorting; - } - } else if (need_sorting) { - for (rk_parameter const * dst = batch->params; dst < last_param; ++dst) { - dst->dirty = true; - } - } - } - if (is_empty) { - glBindVertexArray(batch->vertex_array); - if (rk_MultiDrawElementsIndirect) { - glBindBuffer(GL_DRAW_INDIRECT_BUFFER, batch->commands_buffer); - } - rk_sort_batch(*batch); - rk_pack_batch(*batch); - if (rk_MultiDrawElementsIndirect) { - glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); - } - glBindVertexArray(0); - } else if (need_sorting) { - batch->state = RK_BATCH_STATE_FILLED; - } else { - batch->state = RK_BATCH_STATE_SORTED; - } -} - void rk_draw_batch( rk_batch_t _batch) { rk_batch const * const batch = reinterpret_cast(_batch); diff --git a/cpp/render/render_opengles.hpp b/cpp/render/render_opengles.hpp index f7466a8..18cd3a9 100644 --- a/cpp/render/render_opengles.hpp +++ b/cpp/render/render_opengles.hpp @@ -115,10 +115,10 @@ struct rk_batch { mutable unsigned ninstances; mutable unsigned ncommands; unsigned max_size; - unsigned max_meshes; unsigned nparams; + rk_vertices const * vertices; rk_instance_flags * flags; - rk_mesh * meshes; + rk_ushort * meshes; rk_ushort * indices; rk_command * commands; rk_parameter * params;