Fix T88456: DrawManager: Keep subset RenderMeshData around when geometry does not change.

Reuse loose geometry during selection (and other operations) from
previous calculation. Loose geometry stays the same, but was
recalculated to determine the size of GPU buffers. This patch would
reuse the previous loose geometry when geometry wasn't changed.

Although not the main bottleneck during selection it is measurable.

Master.
`rdata 46ms iter 55ms (frame 410ms)`

This patch.
`rdata 5ms iter 52ms (frame 342ms)`

Reviewed By: mano-wii

Differential Revision: https://developer.blender.org/D11339
This commit is contained in:
Jeroen Bakker 2021-05-31 09:32:37 +02:00 committed by Jeroen Bakker
parent a1556fa05c
commit 5f749a03ca
Notes: blender-bot 2023-02-13 18:37:34 +01:00
Referenced by issue #88550, Mesh Optimization Project Progress
Referenced by issue #88456, DrawManager: Keep subset RenderMeshData around when geometry does not change.
3 changed files with 122 additions and 73 deletions

View File

@ -150,6 +150,18 @@ typedef struct MeshBufferCache {
GPUIndexBuf **tris_per_mat;
} MeshBufferCache;
/**
* Data that are kept around between extractions to reduce rebuilding time.
*
* - Loose geometry.
*/
typedef struct MeshBufferExtractionCache {
int edge_loose_len;
int vert_loose_len;
int *lverts;
int *ledges;
} MeshBufferExtractionCache;
typedef enum DRWBatchFlag {
MBC_SURFACE = (1 << 0),
MBC_SURFACE_WEIGHTS = (1 << 1),
@ -195,6 +207,10 @@ typedef enum DRWBatchFlag {
typedef struct MeshBatchCache {
MeshBufferCache final, cage, uv_cage;
MeshBufferExtractionCache final_extraction_cache;
MeshBufferExtractionCache cage_extraction_cache;
MeshBufferExtractionCache uv_cage_extraction_cache;
struct {
/* Surfaces / Render */
GPUBatch *surface;
@ -271,6 +287,7 @@ typedef struct MeshBatchCache {
void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache mbc,
MeshBufferExtractionCache *extraction_cache,
Mesh *me,
const bool is_editmode,
const bool is_paint_mode,

View File

@ -134,79 +134,85 @@ typedef struct MeshRenderData {
int *lverts, *ledges;
} MeshRenderData;
static void mesh_render_data_update_loose_geom(MeshRenderData *mr,
const eMRIterType iter_type,
const eMRDataType UNUSED(data_flag))
static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferExtractionCache *cache)
{
mr->ledges = cache->ledges;
mr->lverts = cache->lverts;
mr->vert_loose_len = cache->vert_loose_len;
mr->edge_loose_len = cache->edge_loose_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,
MeshBufferExtractionCache *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->lverts) {
return;
}
cache->vert_loose_len = 0;
cache->edge_loose_len = 0;
if (mr->extract_type != MR_EXTRACT_BMESH) {
/* Mesh */
if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
mr->vert_loose_len = 0;
mr->edge_loose_len = 0;
BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__);
const MEdge *med = mr->medge;
for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
if (med->flag & ME_LOOSEEDGE) {
mr->ledges[mr->edge_loose_len++] = med_index;
}
/* Tag verts as not loose. */
BLI_BITMAP_ENABLE(lvert_map, med->v1);
BLI_BITMAP_ENABLE(lvert_map, med->v2);
cache->ledges = MEM_mallocN(mr->edge_len * sizeof(*cache->ledges), __func__);
const MEdge *med = mr->medge;
for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
if (med->flag & ME_LOOSEEDGE) {
cache->ledges[cache->edge_loose_len++] = med_index;
}
if (mr->edge_loose_len < mr->edge_len) {
mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
}
mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
for (int v = 0; v < mr->vert_len; v++) {
if (!BLI_BITMAP_TEST(lvert_map, v)) {
mr->lverts[mr->vert_loose_len++] = v;
}
}
if (mr->vert_loose_len < mr->vert_len) {
mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
}
MEM_freeN(lvert_map);
mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2);
/* Tag verts as not loose. */
BLI_BITMAP_ENABLE(lvert_map, med->v1);
BLI_BITMAP_ENABLE(lvert_map, med->v2);
}
if (cache->edge_loose_len < mr->edge_len) {
cache->ledges = MEM_reallocN(cache->ledges, cache->edge_loose_len * sizeof(*cache->ledges));
}
cache->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
for (int v = 0; v < mr->vert_len; v++) {
if (!BLI_BITMAP_TEST(lvert_map, v)) {
cache->lverts[cache->vert_loose_len++] = v;
}
}
if (cache->vert_loose_len < mr->vert_len) {
cache->lverts = MEM_reallocN(cache->lverts, cache->vert_loose_len * sizeof(*cache->lverts));
}
MEM_freeN(lvert_map);
}
else {
/* #BMesh */
BMesh *bm = mr->bm;
if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
int elem_id;
BMIter iter;
BMVert *eve;
BMEdge *ede;
mr->vert_loose_len = 0;
mr->edge_loose_len = 0;
int elem_id;
BMIter iter;
BMVert *eve;
BMEdge *ede;
mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
if (eve->e == NULL) {
mr->lverts[mr->vert_loose_len++] = elem_id;
}
}
if (mr->vert_loose_len < mr->vert_len) {
mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
cache->lverts = MEM_mallocN(mr->vert_len * sizeof(*cache->lverts), __func__);
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
if (eve->e == NULL) {
cache->lverts[cache->vert_loose_len++] = elem_id;
}
}
if (cache->vert_loose_len < mr->vert_len) {
cache->lverts = MEM_reallocN(cache->lverts, cache->vert_loose_len * sizeof(*cache->lverts));
}
mr->ledges = MEM_mallocN(mr->edge_len * sizeof(*mr->ledges), __func__);
BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
if (ede->l == NULL) {
mr->ledges[mr->edge_loose_len++] = elem_id;
}
cache->ledges = MEM_mallocN(mr->edge_len * sizeof(*cache->ledges), __func__);
BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
if (ede->l == NULL) {
cache->ledges[cache->edge_loose_len++] = elem_id;
}
if (mr->edge_loose_len < mr->edge_len) {
mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
}
mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2;
}
if (cache->edge_loose_len < mr->edge_len) {
cache->ledges = MEM_reallocN(cache->ledges, cache->edge_loose_len * sizeof(*cache->ledges));
}
}
}
@ -317,6 +323,7 @@ static void mesh_render_data_update_normals(MeshRenderData *mr,
* otherwise don't use modifiers as they are not from this object.
*/
static MeshRenderData *mesh_render_data_create(Mesh *me,
MeshBufferExtractionCache *cache,
const bool is_editmode,
const bool is_paint_mode,
const bool is_mode_active,
@ -325,8 +332,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
const bool do_uvedit,
const DRW_MeshCDMask *UNUSED(cd_used),
const ToolSettings *ts,
const eMRIterType iter_type,
const eMRDataType data_flag)
const eMRIterType iter_type)
{
MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
mr->toolsettings = ts;
@ -435,7 +441,11 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
mr->poly_len = bm->totface;
mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
}
mesh_render_data_update_loose_geom(mr, iter_type, data_flag);
if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
mesh_render_data_loose_geom_ensure(mr, cache);
mesh_render_data_loose_geom_load(mr, cache);
}
return mr;
}
@ -446,8 +456,9 @@ static void mesh_render_data_free(MeshRenderData *mr)
MEM_SAFE_FREE(mr->poly_normals);
MEM_SAFE_FREE(mr->loop_normals);
MEM_SAFE_FREE(mr->lverts);
MEM_SAFE_FREE(mr->ledges);
/* Loose geometry are owned by MeshBufferExtractionCache. */
mr->ledges = NULL;
mr->lverts = NULL;
MEM_freeN(mr);
}
@ -5908,6 +5919,7 @@ static void extract_task_create(struct TaskGraph *task_graph,
void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache mbc,
MeshBufferExtractionCache *extraction_cache,
Mesh *me,
const bool is_editmode,
@ -6017,6 +6029,7 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
#endif
MeshRenderData *mr = mesh_render_data_create(me,
extraction_cache,
is_editmode,
is_paint_mode,
is_mode_active,
@ -6025,8 +6038,7 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
do_uvedit,
cd_layer_used,
ts,
iter_flag,
data_flag);
iter_flag);
mr->use_hide = use_hide;
mr->use_subsurf_fdots = use_subsurf_fdots;
mr->use_final_mesh = do_final;

View File

@ -707,6 +707,26 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
}
}
static void mesh_buffer_cache_clear(MeshBufferCache *mbufcache)
{
GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo;
GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo;
for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); i++) {
GPU_VERTBUF_DISCARD_SAFE(vbos[i]);
}
for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); i++) {
GPU_INDEXBUF_DISCARD_SAFE(ibos[i]);
}
}
static void mesh_buffer_extraction_cache_clear(MeshBufferExtractionCache *extraction_cache)
{
MEM_SAFE_FREE(extraction_cache->lverts);
MEM_SAFE_FREE(extraction_cache->ledges);
extraction_cache->edge_loose_len = 0;
extraction_cache->vert_loose_len = 0;
}
static void mesh_batch_cache_clear(Mesh *me)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@ -714,16 +734,13 @@ static void mesh_batch_cache_clear(Mesh *me)
return;
}
FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo;
GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo;
for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); i++) {
GPU_VERTBUF_DISCARD_SAFE(vbos[i]);
}
for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); i++) {
GPU_INDEXBUF_DISCARD_SAFE(ibos[i]);
}
mesh_buffer_cache_clear(mbufcache);
}
mesh_buffer_extraction_cache_clear(&cache->final_extraction_cache);
mesh_buffer_extraction_cache_clear(&cache->cage_extraction_cache);
mesh_buffer_extraction_cache_clear(&cache->uv_cage_extraction_cache);
for (int i = 0; i < cache->mat_len; i++) {
GPU_INDEXBUF_DISCARD_SAFE(cache->final.tris_per_mat[i]);
}
@ -1543,6 +1560,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_buffer_cache_create_requested(task_graph,
cache,
cache->uv_cage,
&cache->uv_cage_extraction_cache,
me,
is_editmode,
is_paint_mode,
@ -1561,6 +1579,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_buffer_cache_create_requested(task_graph,
cache,
cache->cage,
&cache->cage_extraction_cache,
me,
is_editmode,
is_paint_mode,
@ -1578,6 +1597,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_buffer_cache_create_requested(task_graph,
cache,
cache->final,
&cache->final_extraction_cache,
me,
is_editmode,
is_paint_mode,