Cleanup: Use Array and Span for mesh draw buffer cache data

Use C++ types for more automatic memory management, simpler code,
and easier potential performance improvements. Also document each
item in the cache and access a named struct by pointer for the "poly
sorted" instead of using an identical unnamed struct.
This commit is contained in:
Hans Goudey
2023-03-19 18:39:02 -04:00
committed by Hans Goudey
parent 21e3b4483f
commit 638709b0ed
7 changed files with 101 additions and 118 deletions

View File

@@ -222,10 +222,19 @@ ENUM_OPERATORS(DRWBatchFlag, MBC_SURFACE_PER_MAT);
BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields");
struct MeshExtractLooseGeom {
int edge_len;
int vert_len;
int *verts;
int *edges;
/** Indices of all vertices not used by edges in the #Mesh or #BMesh. */
blender::Array<int> verts;
/** Indices of all edges not used by faces in the #Mesh or #BMesh. */
blender::Array<int> edges;
};
struct SortedPolyData {
/** The first triangle index for each polygon, sorted into slices by material. */
blender::Array<int> tri_first_index;
/** The number of visible triangles assigned to each material. */
blender::Array<int> mat_tri_len;
/* The total number of visible triangles (a sum of the values in #mat_tri_len). */
int visible_tri_len;
};
/**
@@ -238,11 +247,7 @@ struct MeshBufferCache {
MeshExtractLooseGeom loose_geom;
struct {
int *tri_first_index;
int *mat_tri_len;
int visible_tri_len;
} poly_sorted;
SortedPolyData poly_sorted;
};
#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \

View File

@@ -397,13 +397,13 @@ BLI_INLINE void extract_task_range_run_iter(const MeshRenderData *mr,
stop = mr->poly_len;
break;
case MR_ITER_LEDGE:
range_data.loose_elems = mr->ledges;
range_data.loose_elems = mr->ledges.data();
range_data.elems = is_mesh ? mr->edges.data() : (void *)mr->bm->etable;
func = is_mesh ? extract_range_iter_ledge_mesh : extract_range_iter_ledge_bm;
stop = mr->edge_loose_len;
break;
case MR_ITER_LVERT:
range_data.loose_elems = mr->lverts;
range_data.loose_elems = mr->lverts.data();
range_data.elems = is_mesh ? mr->vert_positions.data() : (void *)mr->bm->vtable;
func = is_mesh ? extract_range_iter_lvert_mesh : extract_range_iter_lvert_bm;
stop = mr->vert_loose_len;

View File

@@ -39,21 +39,11 @@ static void mesh_render_data_ledges_bm(const MeshRenderData *mr,
static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBufferCache *cache);
static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, MeshBufferCache *cache);
static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferCache *cache)
{
mr->ledges = cache->loose_geom.edges;
mr->lverts = cache->loose_geom.verts;
mr->vert_loose_len = cache->loose_geom.vert_len;
mr->edge_loose_len = cache->loose_geom.edge_len;
mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2);
}
static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr, MeshBufferCache *cache)
{
/* Early exit: Are loose geometry already available.
* Only checking for loose verts as loose edges and verts are calculated at the same time. */
if (cache->loose_geom.verts) {
if (!cache->loose_geom.verts.is_empty()) {
return;
}
mesh_render_data_loose_geom_build(mr, cache);
@@ -61,9 +51,6 @@ static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr, MeshBuf
static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, MeshBufferCache *cache)
{
cache->loose_geom.vert_len = 0;
cache->loose_geom.edge_len = 0;
if (mr->extract_type != MR_EXTRACT_BMESH) {
/* Mesh */
mesh_render_data_loose_geom_mesh(mr, cache);
@@ -83,14 +70,13 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe
const bke::LooseEdgeCache &loose_edges = mr->me->loose_edges();
if (loose_edges.count > 0) {
cache->loose_geom.edges = static_cast<int *>(
MEM_malloc_arrayN(loose_edges.count, sizeof(int), __func__));
cache->loose_geom.edges.reinitialize(loose_edges.count);
cache->loose_geom.edge_len = 0;
int count = 0;
for (const int64_t i : loose_edges.is_loose_bits.index_range()) {
if (loose_edges.is_loose_bits[i]) {
cache->loose_geom.edges[cache->loose_geom.edge_len] = int(i);
cache->loose_geom.edge_len++;
cache->loose_geom.edges[count] = int(i);
count++;
}
}
}
@@ -101,16 +87,19 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe
BLI_BITMAP_ENABLE(lvert_map, edge.v2);
}
cache->loose_geom.verts = static_cast<int *>(
MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__));
int count = 0;
Array<int> loose_verts(mr->vert_len);
for (int v = 0; v < mr->vert_len; v++) {
if (!BLI_BITMAP_TEST(lvert_map, v)) {
cache->loose_geom.verts[cache->loose_geom.vert_len++] = v;
loose_verts[count] = v;
count++;
}
}
if (cache->loose_geom.vert_len < mr->vert_len) {
cache->loose_geom.verts = static_cast<int *>(MEM_reallocN(
cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)));
if (count < mr->vert_len) {
cache->loose_geom.verts = loose_verts.as_span().take_front(count);
}
else {
cache->loose_geom.verts = std::move(loose_verts);
}
MEM_freeN(lvert_map);
@@ -118,37 +107,45 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe
static void mesh_render_data_lverts_bm(const MeshRenderData *mr, MeshBufferCache *cache, BMesh *bm)
{
using namespace blender;
int elem_id;
BMIter iter;
BMVert *eve;
cache->loose_geom.verts = static_cast<int *>(
MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__));
int count = 0;
Array<int> loose_verts(mr->vert_len);
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
if (eve->e == nullptr) {
cache->loose_geom.verts[cache->loose_geom.vert_len++] = elem_id;
loose_verts[count] = elem_id;
count++;
}
}
if (cache->loose_geom.vert_len < mr->vert_len) {
cache->loose_geom.verts = static_cast<int *>(MEM_reallocN(
cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)));
if (count < mr->vert_len) {
cache->loose_geom.verts = loose_verts.as_span().take_front(count);
}
else {
cache->loose_geom.verts = std::move(loose_verts);
}
}
static void mesh_render_data_ledges_bm(const MeshRenderData *mr, MeshBufferCache *cache, BMesh *bm)
{
using namespace blender;
int elem_id;
BMIter iter;
BMEdge *ede;
cache->loose_geom.edges = static_cast<int *>(
MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__));
int count = 0;
Array<int> loose_edges(mr->edge_len);
BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
if (ede->l == nullptr) {
cache->loose_geom.edges[cache->loose_geom.edge_len++] = elem_id;
loose_edges[count] = elem_id;
count++;
}
}
if (cache->loose_geom.edge_len < mr->edge_len) {
cache->loose_geom.edges = static_cast<int *>(MEM_reallocN(
cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)));
if (count < mr->edge_len) {
cache->loose_geom.edges = loose_edges.as_span().take_front(count);
}
else {
cache->loose_geom.edges = std::move(loose_edges);
}
}
@@ -159,7 +156,12 @@ void mesh_render_data_update_loose_geom(MeshRenderData *mr,
{
if ((iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) || (data_flag & MR_DATA_LOOSE_GEOM)) {
mesh_render_data_loose_geom_ensure(mr, cache);
mesh_render_data_loose_geom_load(mr, cache);
mr->ledges = cache->loose_geom.edges;
mr->lverts = cache->loose_geom.verts;
mr->vert_loose_len = cache->loose_geom.verts.size();
mr->edge_loose_len = cache->loose_geom.edges.size();
mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2);
}
}
@@ -171,10 +173,10 @@ void mesh_render_data_update_loose_geom(MeshRenderData *mr,
* Contains polygon indices sorted based on their material.
* \{ */
static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache);
static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache);
static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache);
static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr);
static void mesh_render_data_mat_tri_len_build(MeshRenderData *mr,
blender::MutableSpan<int> mat_tri_len);
void mesh_render_data_update_polys_sorted(MeshRenderData *mr,
MeshBufferCache *cache,
@@ -182,20 +184,13 @@ void mesh_render_data_update_polys_sorted(MeshRenderData *mr,
{
if (data_flag & MR_DATA_POLYS_SORTED) {
mesh_render_data_polys_sorted_ensure(mr, cache);
mesh_render_data_polys_sorted_load(mr, cache);
mr->poly_sorted = &cache->poly_sorted;
}
}
static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache)
{
mr->poly_sorted.tri_first_index = cache->poly_sorted.tri_first_index;
mr->poly_sorted.mat_tri_len = cache->poly_sorted.mat_tri_len;
mr->poly_sorted.visible_tri_len = cache->poly_sorted.visible_tri_len;
}
static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache)
{
if (cache->poly_sorted.tri_first_index) {
if (!cache->poly_sorted.tri_first_index.is_empty()) {
return;
}
mesh_render_data_polys_sorted_build(mr, cache);
@@ -203,9 +198,12 @@ static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferC
static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache)
{
int *tri_first_index = static_cast<int *>(
MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__));
int *mat_tri_len = mesh_render_data_mat_tri_len_build(mr);
using namespace blender;
cache->poly_sorted.tri_first_index.reinitialize(mr->poly_len);
cache->poly_sorted.mat_tri_len.reinitialize(mr->mat_len);
mesh_render_data_mat_tri_len_build(mr, cache->poly_sorted.mat_tri_len);
const Span<int> mat_tri_len = cache->poly_sorted.mat_tri_len;
/* Apply offset. */
int visible_tri_len = 0;
@@ -216,6 +214,9 @@ static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCa
visible_tri_len += mat_tri_len[i];
}
}
cache->poly_sorted.visible_tri_len = visible_tri_len;
MutableSpan<int> tri_first_index = cache->poly_sorted.tri_first_index;
/* Sort per material. */
int mat_last = mr->mat_len - 1;
@@ -247,10 +248,6 @@ static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCa
}
}
}
cache->poly_sorted.tri_first_index = tri_first_index;
cache->poly_sorted.mat_tri_len = mat_tri_len;
cache->poly_sorted.visible_tri_len = visible_tri_len;
}
static void mesh_render_data_mat_tri_len_bm_range_fn(void *__restrict userdata,
@@ -296,35 +293,33 @@ static void mesh_render_data_mat_tri_len_reduce_fn(const void *__restrict userda
}
}
static int *mesh_render_data_mat_tri_len_build_threaded(MeshRenderData *mr,
static void mesh_render_data_mat_tri_len_build_threaded(MeshRenderData *mr,
int face_len,
TaskParallelRangeFunc range_func)
TaskParallelRangeFunc range_func,
blender::MutableSpan<int> mat_tri_len)
{
/* Extending the #MatOffsetUserData with an int per material slot. */
size_t mat_tri_len_size = sizeof(int) * mr->mat_len;
int *mat_tri_len = static_cast<int *>(MEM_callocN(mat_tri_len_size, __func__));
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.userdata_chunk = mat_tri_len;
settings.userdata_chunk_size = mat_tri_len_size;
settings.userdata_chunk = mat_tri_len.data();
settings.userdata_chunk_size = mat_tri_len.as_span().size_in_bytes();
settings.min_iter_per_thread = MIN_RANGE_LEN;
settings.func_reduce = mesh_render_data_mat_tri_len_reduce_fn;
BLI_task_parallel_range(0, face_len, mr, range_func, &settings);
return mat_tri_len;
}
/* Count how many triangles for each material. */
static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr)
static void mesh_render_data_mat_tri_len_build(MeshRenderData *mr,
blender::MutableSpan<int> mat_tri_len)
{
if (mr->extract_type == MR_EXTRACT_BMESH) {
BMesh *bm = mr->bm;
return mesh_render_data_mat_tri_len_build_threaded(
mr, bm->totface, mesh_render_data_mat_tri_len_bm_range_fn);
mesh_render_data_mat_tri_len_build_threaded(
mr, bm->totface, mesh_render_data_mat_tri_len_bm_range_fn, mat_tri_len);
}
else {
mesh_render_data_mat_tri_len_build_threaded(
mr, mr->poly_len, mesh_render_data_mat_tri_len_mesh_range_fn, mat_tri_len);
}
return mesh_render_data_mat_tri_len_build_threaded(
mr, mr->poly_len, mesh_render_data_mat_tri_len_mesh_range_fn);
}
/** \} */
@@ -594,11 +589,6 @@ MeshRenderData *mesh_render_data_create(Object *object,
void mesh_render_data_free(MeshRenderData *mr)
{
/* Loose geometry are owned by #MeshBufferCache. */
mr->ledges = nullptr;
mr->lverts = nullptr;
MEM_delete(mr);
}

View File

@@ -575,15 +575,13 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me)
static void mesh_batch_cache_init(Object *object, Mesh *me)
{
MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache);
if (!cache) {
me->runtime->batch_cache = MEM_cnew<MeshBatchCache>(__func__);
cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache);
if (!me->runtime->batch_cache) {
me->runtime->batch_cache = MEM_new<MeshBatchCache>(__func__);
}
else {
memset(cache, 0, sizeof(*cache));
*static_cast<MeshBatchCache *>(me->runtime->batch_cache) = {};
}
MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache);
cache->is_editmode = me->edit_mesh != nullptr;
@@ -798,14 +796,8 @@ static void mesh_buffer_cache_clear(MeshBufferCache *mbc)
{
mesh_buffer_list_clear(&mbc->buff);
MEM_SAFE_FREE(mbc->loose_geom.verts);
MEM_SAFE_FREE(mbc->loose_geom.edges);
mbc->loose_geom.edge_len = 0;
mbc->loose_geom.vert_len = 0;
MEM_SAFE_FREE(mbc->poly_sorted.tri_first_index);
MEM_SAFE_FREE(mbc->poly_sorted.mat_tri_len);
mbc->poly_sorted.visible_tri_len = 0;
mbc->loose_geom = {};
mbc->poly_sorted = {};
}
static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache)
@@ -846,10 +838,9 @@ static void mesh_batch_cache_clear(MeshBatchCache *cache)
void DRW_mesh_batch_cache_free(void *batch_cache)
{
if (batch_cache) {
mesh_batch_cache_clear(static_cast<MeshBatchCache *>(batch_cache));
MEM_freeN(batch_cache);
}
MeshBatchCache *cache = static_cast<MeshBatchCache *>(batch_cache);
mesh_batch_cache_clear(cache);
MEM_delete(cache);
}
/** \} */

View File

@@ -2188,8 +2188,8 @@ static bool draw_subdiv_create_requested_buffers(Object *ob,
void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cache)
{
const int coarse_loose_vert_len = cache->loose_geom.vert_len;
const int coarse_loose_edge_len = cache->loose_geom.edge_len;
const int coarse_loose_vert_len = cache->loose_geom.verts.size();
const int coarse_loose_edge_len = cache->loose_geom.edges.size();
if (coarse_loose_vert_len == 0 && coarse_loose_edge_len == 0) {
/* Nothing to do. */

View File

@@ -97,16 +97,13 @@ struct MeshRenderData {
const bool *select_poly;
const bool *sharp_faces;
blender::Array<blender::float3> loop_normals;
int *lverts, *ledges;
blender::Span<int> lverts;
blender::Span<int> ledges;
const SortedPolyData *poly_sorted;
const char *active_color_name;
const char *default_color_name;
struct {
int *tri_first_index;
int *mat_tri_len;
int visible_tri_len;
} poly_sorted;
};
BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me)

View File

@@ -30,7 +30,7 @@ static void extract_tris_init(const MeshRenderData *mr,
void *tls_data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr->poly_sorted.visible_tri_len, mr->loop_len);
GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr->poly_sorted->visible_tri_len, mr->loop_len);
}
static void extract_tris_iter_poly_bm(const MeshRenderData *mr,
@@ -38,7 +38,7 @@ static void extract_tris_iter_poly_bm(const MeshRenderData *mr,
const int f_index,
void *_data)
{
int tri_first_index = mr->poly_sorted.tri_first_index[f_index];
int tri_first_index = mr->poly_sorted->tri_first_index[f_index];
if (tri_first_index == -1) {
return;
}
@@ -64,7 +64,7 @@ static void extract_tris_iter_poly_mesh(const MeshRenderData *mr,
const int poly_index,
void *_data)
{
int tri_first_index = mr->poly_sorted.tri_first_index[poly_index];
int tri_first_index = mr->poly_sorted->tri_first_index[poly_index];
if (tri_first_index == -1) {
return;
}
@@ -99,7 +99,7 @@ static void extract_tris_finish(const MeshRenderData *mr,
if (cache->tris_per_mat[i] == nullptr) {
cache->tris_per_mat[i] = GPU_indexbuf_calloc();
}
const int mat_tri_len = mr->poly_sorted.mat_tri_len[i];
const int mat_tri_len = mr->poly_sorted->mat_tri_len[i];
/* Multiply by 3 because these are triangle indices. */
const int start = mat_start * 3;
const int len = mat_tri_len * 3;