Sculpt-dev: new PBVH caching system

* Still experimental
* PBVHs are cached in a global map keyed by
  object name (though at the moment only one pbvh
  is cached at a time).
* ss->pmap is now freed managed by pbvh.
* ss->bm is freed by the pbvh cache in some
  circumstances but is stilled owned by SculptSession.
This commit is contained in:
Joseph Eagar 2022-03-18 21:12:43 -07:00
parent 371a6799c4
commit 307f13aee5
19 changed files with 680 additions and 120 deletions

View File

@ -767,6 +767,8 @@ typedef struct SculptSession {
/* PBVH acceleration structure */
struct PBVH *pbvh;
struct PBVH *last_pbvh;
bool show_mask;
bool show_face_sets;

View File

@ -80,8 +80,8 @@ BLI_INLINE SculptFaceRef BKE_pbvh_make_fref(intptr_t i)
typedef struct PBVHTri {
int v[3]; // references into PBVHTriBuf->verts
intptr_t l[3]; // loops
int eflag; // bitmask of which edges in the tri are real edges in the mesh
intptr_t l[3]; // loops
float no[3];
SculptFaceRef f;
@ -323,6 +323,7 @@ void BKE_pbvh_update_offsets(PBVH *pbvh,
void BKE_pbvh_free(PBVH *pbvh);
void BKE_pbvh_set_bm_log(PBVH *pbvh, struct BMLog *log);
struct BMLog *BKE_pbvh_get_bm_log(PBVH *pbvh);
/* update MSculptVerts, doesn't take pbvh argument to allow usage if pbvh doesn't currently exist
*/
@ -1127,3 +1128,17 @@ void BKE_pbvh_pmap_to_edges(PBVH *pbvh,
void BKE_pbvh_set_vemap(PBVH *pbvh, struct MeshElemMap *vemap);
void BKE_pbvh_ignore_uvs_set(PBVH *pbvh, bool value);
bool BKE_pbvh_cache_is_valid(const struct Object *ob, const struct Mesh *me, const PBVH *old, int pbvh_type);
bool BKE_pbvh_cache(const struct Mesh *me, PBVH *pbvh);
PBVH *BKE_pbvh_get_or_free_cached(struct Object *ob, struct Mesh *me, PBVHType pbvh_type);
void BKE_pbvh_set_cached(struct Object *ob, PBVH *pbvh);
void BKE_pbvh_set_face_areas(PBVH *pbvh, float *face_areas);
void BKE_pbvh_set_sculpt_verts(PBVH *pbvh, struct MSculptVert *sverts);
void BKE_pbvh_set_pmap(PBVH *pbvh, struct MeshElemMap *pmap, void *pmap_mem);
struct MeshElemMap *BKE_pbvh_get_pmap(PBVH *pbvh);
struct MeshElemMap *BKE_pbvh_get_pmap_ex(PBVH *pbvh, int **r_mem);
void BKE_pbvh_cache_remove(PBVH *pbvh);
void BKE_pbvh_set_bmesh(PBVH *pbvh, struct BMesh *bm);
void BKE_pbvh_free_bmesh(PBVH *pbvh, struct BMesh *bm);
void BKE_pbvh_system_init();
void BKE_pbvh_system_exit();

View File

@ -34,6 +34,7 @@
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_pbvh.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@ -76,6 +77,7 @@ void BKE_blender_free(void)
DEG_free_node_types();
BKE_brush_system_exit();
BKE_pbvh_system_exit();
RE_texture_rng_exit();
BKE_callback_global_finalize();

View File

@ -528,10 +528,19 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
ob->mode &= ~OB_MODE_EDIT;
}
PBVH *cached_pbvh = ob->cached_pbvh2;
if (!is_undo) {
ob->cached_pbvh2 = NULL;
}
/* write LibData */
BLO_write_id_struct(writer, Object, id_address, &ob->id);
BKE_id_blend_write(writer, &ob->id);
if (!is_undo) {
ob->cached_pbvh2 = cached_pbvh;
}
if (ob->adt) {
BKE_animdata_blend_write(writer, ob->adt);
}
@ -4959,6 +4968,8 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
runtime->crazyspace_deform_imats = nullptr;
runtime->crazyspace_deform_cos = nullptr;
object->cached_pbvh2 = runtime->cached_pbvh = NULL;
}
void BKE_object_runtime_free_data(Object *object)

View File

@ -272,6 +272,8 @@ void BKE_object_sync_to_original(Depsgraph *depsgraph, Object *object)
object_orig->transflag = object->transflag;
object_orig->flag = object->flag;
//object_orig->cached_pbvh2 = object->cached_pbvh2;
/* Copy back error messages from modifiers. */
for (ModifierData *md = object->modifiers.first, *md_orig = object_orig->modifiers.first;
md != NULL && md_orig != NULL;

View File

@ -1448,15 +1448,16 @@ static void sculptsession_free_pbvh(Object *object)
}
if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
BKE_pbvh_set_cached(object, ss->pbvh);
ss->pbvh = NULL;
}
else {
MEM_SAFE_FREE(ss->pmap);
MEM_SAFE_FREE(ss->pmap_mem);
}
MEM_SAFE_FREE(ss->face_areas);
MEM_SAFE_FREE(ss->pmap);
MEM_SAFE_FREE(ss->pmap_mem);
MEM_SAFE_FREE(ss->epmap);
MEM_SAFE_FREE(ss->epmap_mem);
@ -1516,21 +1517,24 @@ void BKE_sculptsession_free(Object *ob)
SCULPT_on_sculptsession_bmesh_free(ss);
BKE_sculptsession_bm_to_me(ob, true);
BM_mesh_free(ss->bm);
ss->bm = NULL;
// BM_mesh_free(ss->bm);
}
CustomData_free(&ss->temp_vdata, ss->temp_vdata_elems);
CustomData_free(&ss->temp_pdata, ss->temp_pdata_elems);
if (!ss->pbvh) {
MEM_SAFE_FREE(ss->pmap);
MEM_SAFE_FREE(ss->pmap_mem);
}
sculptsession_free_pbvh(ob);
for (int i = 0; i < SCULPT_SCL_LAYER_MAX; i++) {
MEM_SAFE_FREE(ss->custom_layers[i]);
}
MEM_SAFE_FREE(ss->pmap);
MEM_SAFE_FREE(ss->pmap_mem);
MEM_SAFE_FREE(ss->epmap);
MEM_SAFE_FREE(ss->epmap_mem);
@ -1822,16 +1826,26 @@ static void sculpt_update_object(Depsgraph *depsgraph,
BKE_pbvh_face_sets_color_set(ss->pbvh, me->face_sets_color_seed, me->face_sets_color_default);
if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
BKE_mesh_vert_poly_map_create(&ss->pmap,
&ss->pmap_mem,
me->mvert,
me->medge,
me->mpoly,
me->mloop,
me->totvert,
me->totpoly,
me->totloop,
false);
if (!ss->pmap && ss->pbvh) {
ss->pmap = BKE_pbvh_get_pmap_ex(ss->pbvh, &ss->pmap_mem);
}
if (!ss->pmap) {
BKE_mesh_vert_poly_map_create(&ss->pmap,
&ss->pmap_mem,
me->mvert,
me->medge,
me->mpoly,
me->mloop,
me->totvert,
me->totpoly,
me->totloop,
false);
if (ss->pbvh) {
BKE_pbvh_set_pmap(ss->pbvh, ss->pmap, ss->pmap_mem);
}
}
}
pbvh_show_mask_set(ss->pbvh, ss->show_mask);
@ -2396,42 +2410,72 @@ void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object)
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
}
static PBVH *build_pbvh_for_dynamic_topology(Object *ob, bool update_sculptverts)
ATTR_NO_OPT static PBVH *build_pbvh_for_dynamic_topology(Object *ob, bool update_sculptverts)
{
PBVH *pbvh = BKE_pbvh_new();
Mesh *me = BKE_object_get_original_mesh(ob);
PBVH *pbvh = BKE_pbvh_get_or_free_cached(ob, me, PBVH_BMESH);
if (!pbvh) {
pbvh = BKE_pbvh_new();
BKE_pbvh_build_bmesh(pbvh,
BKE_object_get_original_mesh(ob),
ob->sculpt->bm,
ob->sculpt->bm_smooth_shading,
ob->sculpt->bm_log,
ob->sculpt->cd_vert_node_offset,
ob->sculpt->cd_face_node_offset,
ob->sculpt->cd_sculpt_vert,
ob->sculpt->cd_face_areas,
ob->sculpt->fast_draw,
update_sculptverts);
}
else {
BMesh *bm = BKE_pbvh_get_bmesh(pbvh);
if (bm && bm != ob->sculpt->bm) {
printf("%s: ss->bm != bm!\n", __func__);
ob->sculpt->bm = bm;
if (ob->sculpt->bm_log) {
BM_log_set_bm(bm, ob->sculpt->bm_log);
}
}
else if (!bm) {
BKE_pbvh_set_bmesh(pbvh, ob->sculpt->bm);
}
}
if (ob->sculpt->bm_log) {
BKE_pbvh_set_bm_log(pbvh, ob->sculpt->bm_log);
}
BKE_pbvh_set_symmetry(pbvh, 0, (int)BKE_get_fset_boundary_symflag(ob));
BKE_pbvh_build_bmesh(pbvh,
BKE_object_get_original_mesh(ob),
ob->sculpt->bm,
ob->sculpt->bm_smooth_shading,
ob->sculpt->bm_log,
ob->sculpt->cd_vert_node_offset,
ob->sculpt->cd_face_node_offset,
ob->sculpt->cd_sculpt_vert,
ob->sculpt->cd_face_areas,
ob->sculpt->fast_draw,
update_sculptverts);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, false);
BKE_pbvh_set_cached(ob, pbvh);
return pbvh;
}
static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool respect_hide)
ATTR_NO_OPT static PBVH *build_pbvh_from_regular_mesh(Object *ob,
Mesh *me_eval_deform,
bool respect_hide)
{
SculptSession *ss = ob->sculpt;
Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
PBVH *pbvh = BKE_pbvh_new();
BKE_pbvh_respect_hide_set(pbvh, respect_hide);
MLoopTri *looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__);
PBVH *pbvh = BKE_pbvh_get_or_free_cached(ob, me, PBVH_FACES);
BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
struct MeshElemMap *BKE_pbvh_get_pmap_ex(PBVH * pbvh, int **r_mem);
BKE_sculpt_sync_face_set_visibility(me, NULL);
if (!ss->pmap && pbvh) {
ss->pmap = BKE_pbvh_get_pmap_ex(pbvh, &ss->pmap_mem);
}
if (!ss->pmap) {
BKE_mesh_vert_poly_map_create(&ss->pmap,
@ -2446,29 +2490,43 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
false);
}
if (!pbvh) {
pbvh = BKE_pbvh_new();
MLoopTri *looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__);
BKE_pbvh_respect_hide_set(pbvh, respect_hide);
BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
BKE_sculpt_sync_face_set_visibility(me, NULL);
BKE_pbvh_build_mesh(pbvh,
me,
me->mpoly,
me->mloop,
me->mvert,
ss->mdyntopo_verts,
me->totvert,
&me->vdata,
&me->ldata,
&me->pdata,
looptri,
looptris_num,
ss->fast_draw,
ss->face_areas,
ss->pmap);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
}
BKE_pbvh_set_pmap(pbvh, ss->pmap, ss->pmap_mem);
BKE_sculptsession_check_sculptverts(ob->sculpt, pbvh, me->totvert);
MEM_SAFE_FREE(ss->face_areas);
ss->face_areas = MEM_calloc_arrayN(me->totpoly, sizeof(float) * 2, "ss->face_areas");
BKE_pbvh_build_mesh(pbvh,
me,
me->mpoly,
me->mloop,
me->mvert,
ss->mdyntopo_verts,
me->totvert,
&me->vdata,
&me->ldata,
&me->pdata,
looptri,
looptris_num,
ss->fast_draw,
ss->face_areas,
ss->pmap);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
BKE_pbvh_set_face_areas(pbvh, ss->face_areas);
BKE_pbvh_set_sculpt_verts(pbvh, ss->mdyntopo_verts);
const bool is_deformed = check_sculpt_object_deformed(ob, true);
if (is_deformed && me_eval_deform != NULL) {
@ -2478,6 +2536,8 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
MEM_freeN(v_cos);
}
BKE_pbvh_set_cached(ob, pbvh);
return pbvh;
}
@ -2487,30 +2547,40 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
CCGKey key;
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
PBVH *pbvh = BKE_pbvh_new();
BKE_pbvh_respect_hide_set(pbvh, respect_hide);
Mesh *me = BKE_object_get_original_mesh(ob);
PBVH *pbvh = BKE_pbvh_get_or_free_cached(ob, me, PBVH_GRIDS);
Mesh *base_mesh = BKE_mesh_from_object(ob);
BKE_sculpt_sync_face_set_visibility(base_mesh, subdiv_ccg);
int totgridfaces = base_mesh->totpoly * (key.grid_size - 1) * (key.grid_size - 1);
MEM_SAFE_FREE(ss->face_areas);
ss->face_areas = MEM_calloc_arrayN(totgridfaces, sizeof(float) * 2, "ss->face_areas");
BKE_sculpt_sync_face_set_visibility(base_mesh, subdiv_ccg);
if (!pbvh) {
pbvh = BKE_pbvh_new();
BKE_pbvh_respect_hide_set(pbvh, respect_hide);
BKE_pbvh_build_grids(pbvh,
subdiv_ccg->grids,
subdiv_ccg->num_grids,
&key,
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden,
ob->sculpt->fast_draw,
ss->face_areas);
}
BKE_pbvh_set_face_areas(pbvh, ss->face_areas);
BKE_pbvh_set_sculpt_verts(pbvh, ss->mdyntopo_verts);
CustomData_reset(&ob->sculpt->temp_vdata);
CustomData_reset(&ob->sculpt->temp_pdata);
BKE_pbvh_build_grids(pbvh,
subdiv_ccg->grids,
subdiv_ccg->num_grids,
&key,
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden,
ob->sculpt->fast_draw,
ss->face_areas);
ss->temp_vdata_elems = BKE_pbvh_get_grid_num_vertices(pbvh);
ss->temp_pdata_elems = ss->totfaces;
@ -2519,6 +2589,8 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
BKE_pbvh_set_cached(ob, pbvh);
return pbvh;
}
@ -2655,25 +2727,36 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
bool is_dyntopo = (mesh_orig->flag & ME_SCULPT_DYNAMIC_TOPOLOGY);
if (is_dyntopo) {
BMesh *bm = BKE_sculptsession_empty_bmesh_create();
/* check if the pbvh cache has a valid bmesh */
pbvh = BKE_pbvh_get_or_free_cached(ob, mesh_orig, PBVH_BMESH);
BMesh *bm = NULL;
if (pbvh) {
bm = BKE_pbvh_get_bmesh(pbvh);
}
if (!bm) {
bm = BKE_sculptsession_empty_bmesh_create();
BM_mesh_bm_from_me(NULL,
bm,
mesh_orig,
(&(struct BMeshFromMeshParams){.calc_face_normal = true,
.use_shapekey = true,
.active_shapekey = ob->shapenr,
.create_shapekey_layers = true,
.ignore_id_layers = false,
.copy_temp_cdlayers = true,
.cd_mask_extra = CD_MASK_DYNTOPO_VERT}));
}
ob->sculpt->bm = bm;
BM_mesh_bm_from_me(NULL,
bm,
mesh_orig,
(&(struct BMeshFromMeshParams){.calc_face_normal = true,
.use_shapekey = true,
.active_shapekey = ob->shapenr,
.create_shapekey_layers = true,
.ignore_id_layers = false,
.copy_temp_cdlayers = true,
.cd_mask_extra = CD_MASK_DYNTOPO_VERT}));
BKE_sculptsession_bmesh_add_layers(ob);
SCULPT_undo_ensure_bmlog(ob);
/* Note build_pbvh_for_dynamic_topology respects the pbvh cache. */
pbvh = build_pbvh_for_dynamic_topology(ob, true);
BKE_sculptsession_update_attr_refs(ob);
@ -3295,11 +3378,11 @@ static bool sculpt_attr_get_layer(SculptSession *ss,
}
bool BKE_sculptsession_attr_get_layer(Object *ob,
AttributeDomain domain,
int proptype,
const char *name,
SculptCustomLayer *scl,
SculptLayerParams *params)
AttributeDomain domain,
int proptype,
const char *name,
SculptCustomLayer *scl,
SculptLayerParams *params)
{
SculptSession *ss = ob->sculpt;

View File

@ -9,10 +9,13 @@
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
#include "BLI_array.h"
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_string.h"
#include "BLI_task.h"
#include "DNA_mesh_types.h"
@ -24,10 +27,13 @@
#include "BKE_ccg.h"
#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_subdiv_ccg.h"
#include "DEG_depsgraph_query.h"
#include "PIL_time.h"
#include "GPU_buffers.h"
@ -633,6 +639,16 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
build_sub(pbvh, 0, cb, prim_bbc, 0, totprim, 0);
}
void BKE_pbvh_set_face_areas(PBVH *pbvh, float *face_areas)
{
pbvh->face_areas = face_areas;
}
void BKE_pbvh_set_sculpt_verts(PBVH *pbvh, MSculptVert *sverts)
{
pbvh->mdyntopo_verts = sverts;
}
void BKE_pbvh_build_mesh(PBVH *pbvh,
Mesh *mesh,
const MPoly *mpoly,
@ -776,7 +792,7 @@ PBVH *BKE_pbvh_new(void)
return pbvh;
}
void BKE_pbvh_free(PBVH *pbvh)
ATTR_NO_OPT void BKE_pbvh_free(PBVH *pbvh)
{
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *node = &pbvh->nodes[i];
@ -832,6 +848,9 @@ void BKE_pbvh_free(PBVH *pbvh)
MEM_SAFE_FREE(pbvh->vert_bitmap);
MEM_SAFE_FREE(pbvh->pmap);
MEM_SAFE_FREE(pbvh->pmap_mem);
MEM_freeN(pbvh);
}
@ -1148,9 +1167,8 @@ static void pbvh_update_normals_clear_task_cb(void *__restrict userdata,
}
}
static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
ATTR_NO_OPT static void pbvh_update_normals_accum_task_cb(
void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
{
PBVHUpdateData *data = userdata;
@ -1564,6 +1582,9 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
GPU_pbvh_mesh_buffers_update(node->draw_buffers,
pbvh->verts,
pbvh->mloop,
pbvh->mpoly,
pbvh->looptri,
vdata,
ldata,
CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK),
@ -3568,6 +3589,8 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
pbvh_bmesh_check_other_verts(node);
}
vi->mverts = NULL;
vi->bi = 0;
vi->bm_cur_set = node->bm_unique_verts;
vi->bm_unique_verts = node->bm_unique_verts;
@ -4765,3 +4788,312 @@ void BKE_pbvh_ignore_uvs_set(PBVH *pbvh, bool value)
pbvh_boundaries_flag_update(pbvh);
}
bool BKE_pbvh_cache(const struct Mesh *me, PBVH *pbvh)
{
memset(&pbvh->cached_data, 0, sizeof(pbvh->cached_data));
switch (pbvh->type) {
case PBVH_BMESH:
if (!pbvh->bm) {
return false;
}
pbvh->cached_data.bm = pbvh->bm;
pbvh->cached_data.vdata = pbvh->bm->vdata;
pbvh->cached_data.edata = pbvh->bm->edata;
pbvh->cached_data.ldata = pbvh->bm->ldata;
pbvh->cached_data.pdata = pbvh->bm->pdata;
pbvh->cached_data.totvert = pbvh->bm->totvert;
pbvh->cached_data.totedge = pbvh->bm->totedge;
pbvh->cached_data.totloop = pbvh->bm->totloop;
pbvh->cached_data.totpoly = pbvh->bm->totface;
break;
case PBVH_GRIDS:
pbvh->cached_data.vdata = me->vdata;
pbvh->cached_data.edata = me->edata;
pbvh->cached_data.ldata = me->ldata;
pbvh->cached_data.pdata = me->pdata;
int grid_side = pbvh->gridkey.grid_size;
pbvh->cached_data.totvert = pbvh->totgrid * grid_side * grid_side;
pbvh->cached_data.totedge = me->totedge;
pbvh->cached_data.totloop = me->totloop;
pbvh->cached_data.totpoly = pbvh->totgrid * (grid_side - 1) * (grid_side - 1);
break;
case PBVH_FACES:
pbvh->cached_data.vdata = me->vdata;
pbvh->cached_data.edata = me->edata;
pbvh->cached_data.ldata = me->ldata;
pbvh->cached_data.pdata = me->pdata;
pbvh->cached_data.totvert = me->totvert;
pbvh->cached_data.totedge = me->totedge;
pbvh->cached_data.totloop = me->totloop;
pbvh->cached_data.totpoly = me->totpoly;
break;
}
return true;
}
static bool customdata_is_same(const CustomData *a, const CustomData *b)
{
return memcmp(a, b, sizeof(CustomData)) == 0;
}
ATTR_NO_OPT bool BKE_pbvh_cache_is_valid(const Object *ob,
const Mesh *me,
const PBVH *pbvh,
PBVHType pbvh_type)
{
if (pbvh->type != pbvh_type) {
return false;
}
bool ok = true;
int totvert, totedge, totloop, totpoly;
const CustomData *vdata, *edata, *ldata, *pdata;
switch (pbvh_type) {
case PBVH_BMESH:
if (!pbvh->bm || pbvh->bm != pbvh->cached_data.bm) {
return false;
}
totvert = pbvh->bm->totvert;
totedge = pbvh->bm->totedge;
totloop = pbvh->bm->totloop;
totpoly = pbvh->bm->totface;
vdata = &pbvh->bm->vdata;
edata = &pbvh->bm->edata;
ldata = &pbvh->bm->ldata;
pdata = &pbvh->bm->pdata;
break;
case PBVH_FACES:
totvert = me->totvert;
totedge = me->totedge;
totloop = me->totloop;
totpoly = me->totpoly;
vdata = &me->vdata;
edata = &me->edata;
ldata = &me->ldata;
pdata = &me->pdata;
break;
case PBVH_GRIDS: {
MultiresModifierData *mmd = NULL;
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Multires) {
mmd = (MultiresModifierData *)md;
break;
}
}
if (!mmd) {
return false;
}
int grid_side = 1 + (1 << (mmd->sculptlvl - 1));
totvert = me->totloop * grid_side * grid_side;
totedge = me->totedge;
totloop = me->totloop;
totpoly = me->totloop * (grid_side - 1) * (grid_side - 1);
vdata = &me->vdata;
edata = &me->edata;
ldata = &me->ldata;
pdata = &me->pdata;
break;
}
}
ok = ok && totvert == pbvh->cached_data.totvert;
ok = ok && totedge == pbvh->cached_data.totedge;
ok = ok && totloop == pbvh->cached_data.totloop;
ok = ok && totpoly == pbvh->cached_data.totpoly;
ok = ok && customdata_is_same(vdata, &pbvh->cached_data.vdata);
ok = ok && customdata_is_same(edata, &pbvh->cached_data.edata);
ok = ok && customdata_is_same(ldata, &pbvh->cached_data.ldata);
ok = ok && customdata_is_same(pdata, &pbvh->cached_data.pdata);
return ok;
}
GHash *cached_pbvhs = NULL;
static void pbvh_clear_cached_pbvhs(PBVH *exclude)
{
GHashIterator iter;
GHASH_ITER (iter, cached_pbvhs) {
PBVH *pbvh = BLI_ghashIterator_getValue(&iter);
if (pbvh != exclude) {
if (pbvh->bm) {
BM_mesh_free(pbvh->bm);
}
BKE_pbvh_free(pbvh);
}
}
BLI_ghash_clear(cached_pbvhs, MEM_freeN, NULL);
}
void BKE_pbvh_clear_cache(PBVH *preserve)
{
pbvh_clear_cached_pbvhs(NULL);
}
ATTR_NO_OPT PBVH *BKE_pbvh_get_or_free_cached(Object *ob, Mesh *me, PBVHType pbvh_type)
{
Object *ob_orig = DEG_get_original_object(ob);
PBVH *pbvh = BLI_ghash_lookup(cached_pbvhs, ob_orig->id.name);
if (!pbvh) {
return NULL;
}
if (BKE_pbvh_cache_is_valid(ob, me, pbvh, pbvh_type)) {
switch (pbvh_type) {
case PBVH_BMESH:
break;
case PBVH_FACES:
pbvh->vert_normals = BKE_mesh_vertex_normals_for_write(me);
case PBVH_GRIDS:
pbvh->verts = me->mvert;
pbvh->mloop = me->mloop;
pbvh->mpoly = me->mpoly;
pbvh->vdata = &me->vdata;
pbvh->ldata = &me->ldata;
pbvh->pdata = &me->pdata;
pbvh->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
break;
}
return pbvh;
}
pbvh_clear_cached_pbvhs(NULL);
return NULL;
}
ATTR_NO_OPT void BKE_pbvh_set_cached(Object *ob, PBVH *pbvh)
{
Object *ob_orig = DEG_get_original_object(ob);
PBVH *exist = BLI_ghash_lookup(cached_pbvhs, ob_orig->id.name);
if (!exist || exist != pbvh) {
pbvh_clear_cached_pbvhs(pbvh);
BLI_ghash_insert(cached_pbvhs, BLI_strdup(ob_orig->id.name), pbvh);
}
BKE_pbvh_cache(BKE_object_get_original_mesh(ob_orig), pbvh);
}
struct MeshElemMap *BKE_pbvh_get_pmap(PBVH *pbvh)
{
return pbvh->pmap;
}
struct MeshElemMap *BKE_pbvh_get_pmap_ex(PBVH *pbvh, int **r_mem)
{
if (r_mem) {
*r_mem = (int *)pbvh->pmap_mem;
}
return pbvh->pmap;
}
void BKE_pbvh_set_pmap(PBVH *pbvh, struct MeshElemMap *pmap, void *pmap_mem)
{
pbvh->pmap = pmap;
pbvh->pmap_mem = pmap_mem;
}
/** Does not free pbvh itself. */
void BKE_pbvh_cache_remove(PBVH *pbvh)
{
char **keys = NULL;
BLI_array_staticdeclare(keys, 32);
GHashIterator iter;
GHASH_ITER (iter, cached_pbvhs) {
PBVH *pbvh2 = BLI_ghashIterator_getValue(&iter);
if (pbvh2 == pbvh) {
BLI_array_append(keys, (char *)BLI_ghashIterator_getKey(&iter));
break;
}
}
for (int i = 0; i < BLI_array_len(keys); i++) {
BLI_ghash_remove(cached_pbvhs, keys[i], MEM_freeN, NULL);
}
BLI_array_free(keys);
}
void BKE_pbvh_set_bmesh(PBVH *pbvh, BMesh *bm)
{
pbvh->bm = bm;
}
void BKE_pbvh_free_bmesh(PBVH *pbvh, BMesh *bm)
{
if (pbvh) {
pbvh->bm = NULL;
}
BM_mesh_free(bm);
GHashIterator iter;
char **keys = NULL;
BLI_array_staticdeclare(keys, 32);
GHASH_ITER (iter, cached_pbvhs) {
PBVH *pbvh2 = BLI_ghashIterator_getValue(&iter);
if (pbvh2->bm == bm) {
pbvh2->bm = NULL;
if (pbvh2 != pbvh) {
BKE_pbvh_free(pbvh2);
}
BLI_array_append(keys, BLI_ghashIterator_getKey(&iter));
}
}
for (int i = 0; i < BLI_array_len(keys); i++) {
BLI_ghash_remove(cached_pbvhs, keys[i], MEM_freeN, NULL);
}
BLI_array_free(keys);
}
struct BMLog *BKE_pbvh_get_bm_log(PBVH *pbvh)
{
return pbvh->bm_log;
}
void BKE_pbvh_system_init()
{
cached_pbvhs = BLI_ghash_str_new("pbvh cache ghash");
}
void BKE_pbvh_system_exit()
{
pbvh_clear_cached_pbvhs(NULL);
BLI_ghash_free(cached_pbvhs, NULL, NULL);
}

View File

@ -2390,8 +2390,15 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
pbvh->depth_limit = 28;
int tottri = poly_to_tri_count(bm->totface, bm->totloop);
/* TODO: choose leaf limit better */
pbvh->leaf_limit = 1000;
if (tottri > 4 * 1000 * 1000) {
pbvh->leaf_limit = 10000;
}
else {
pbvh->leaf_limit = 1000;
}
BMIter iter;
BMVert *v;
@ -2603,7 +2610,7 @@ ATTR_NO_OPT bool BKE_pbvh_bmesh_update_topology_nodes(PBVH *pbvh,
updatePBVH,
mask_cb,
mask_cb_data,
0, //is_snake_hook ? 40960 : 0,
0, // is_snake_hook ? 40960 : 0,
disable_surface_relax,
is_snake_hook);

View File

@ -146,6 +146,7 @@ struct PBVH {
/* Mesh data */
struct MeshElemMap *pmap, *vemap;
void *pmap_mem;
const struct Mesh *mesh;
/* Note: Normals are not const because they can be updated for drawing by sculpt code. */
@ -220,6 +221,16 @@ struct PBVH {
int balance_counter;
int stroke_id; // used to keep origdata up to date in PBVH_BMESH
bool is_cached;
/* This data is for validating cached PBVHs;
* it is not guaranteed to be valid in any way! */
struct {
CustomData vdata, edata, ldata, pdata;
int totvert, totedge, totloop, totpoly;
struct BMesh *bm;
} cached_data;
};
/* pbvh.c */

View File

@ -3550,7 +3550,7 @@ typedef struct AreaNormalCenterTLSData {
int count_co[2];
} AreaNormalCenterTLSData;
static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
ATTR_NO_OPT static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
@ -3816,7 +3816,7 @@ void SCULPT_calc_area_normal(
SCULPT_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, r_area_no);
}
bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
ATTR_NO_OPT bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
Object *ob,
PBVHNode **nodes,
int totnode,
@ -5604,7 +5604,7 @@ static void SCULPT_run_command(
BKE_ptcache_object_reset(CTX_data_scene(C), ob, PTCACHE_RESET_OUTDATED);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
BKE_scene_graph_update_tagged(CTX_data_ensure_evaluated_depsgraph(C), CTX_data_main(C));
SCULPT_pbvh_clear(ob);
SCULPT_pbvh_clear(ob, false);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
if (cmd->tool == SCULPT_TOOL_ARRAY) {
@ -7468,7 +7468,7 @@ float SCULPT_raycast_init(ViewContext *vc,
* also updates the active vertex and cursor related data of the SculptSession using the mouse
* position
*/
bool SCULPT_cursor_geometry_info_update(bContext *C,
ATTR_NO_OPT bool SCULPT_cursor_geometry_info_update(bContext *C,
SculptCursorGeometryInfo *out,
const float mouse[2],
bool use_sampled_normal,
@ -8236,7 +8236,7 @@ static void sculpt_stroke_update_step(bContext *C,
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
BKE_scene_graph_update_tagged(CTX_data_ensure_evaluated_depsgraph(C), CTX_data_main(C));
SCULPT_pbvh_clear(ob);
SCULPT_pbvh_clear(ob, false);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
@ -8678,6 +8678,11 @@ void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scen
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
/* Leave sculpt mode. We do this here to prevent
* the depsgraph spawning a PBVH_FACES after disabling
* dynamic topology below. */
ob->mode &= ~mode_flag;
if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
/* Dynamic topology must be disabled before exiting sculpt
* mode to ensure the undo stack stays in a consistent
@ -8688,9 +8693,6 @@ void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scen
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
}
/* Leave sculpt mode. */
ob->mode &= ~mode_flag;
BKE_sculptsession_free(ob);
paint_cursor_delete_textures();

View File

@ -206,7 +206,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
SCULPT_undo_push_end(ob);
/* Force rebuild of PBVH for better BB placement. */
SCULPT_pbvh_clear(ob);
SCULPT_pbvh_clear(ob, false);
/* Redraw. */
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);

View File

@ -467,19 +467,28 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm)
// NULL);
}
void SCULPT_pbvh_clear(Object *ob)
void SCULPT_pbvh_clear(Object *ob, bool cache_pbvh)
{
SculptSession *ss = ob->sculpt;
/* Clear out any existing DM and PBVH. */
if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
if (cache_pbvh) {
BKE_pbvh_set_cached(ob, ss->pbvh);
}
else {
BKE_pbvh_cache_remove(ss->pbvh);
BKE_pbvh_free(ss->pbvh);
}
ss->pbvh = NULL;
ss->pmap = NULL;
ss->pmap_mem = NULL;
}
else {
MEM_SAFE_FREE(ss->pmap);
MEM_SAFE_FREE(ss->pmap_mem);
}
MEM_SAFE_FREE(ss->pmap);
MEM_SAFE_FREE(ss->pmap_mem);
BKE_object_free_derived_caches(ob);
@ -578,17 +587,55 @@ BMesh *BM_mesh_bm_from_me_threaded(BMesh *bm,
const Mesh *me,
const struct BMeshFromMeshParams *params);
static void customdata_strip_templayers(CustomData *cdata, int totelem)
{
for (int i = 0; i < cdata->totlayer; i++) {
CustomDataLayer *layer = cdata->layers + i;
if (layer->flag & CD_FLAG_TEMPORARY) {
CustomData_free_layer(cdata, layer->type, totelem, i);
i--;
}
}
}
void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
SculptSession *ss = ob->sculpt;
Mesh *me = ob->data;
void BKE_pbvh_clear_cache(PBVH * preserve);
customdata_strip_templayers(&me->vdata, me->totvert);
customdata_strip_templayers(&me->pdata, me->totpoly);
/* clear any non-dyntopo PBVH cache */
if (ss->pbvh) {
// pmap is freed by pbvh
ss->pmap = NULL;
ss->pmap_mem = NULL;
/* Remove existing pbvh so we can free it ourselves. */
BKE_pbvh_cache_remove(ss->pbvh);
/* Free any other pbvhs */
BKE_pbvh_clear_cache(NULL);
}
if (ss->bm) {
bool ok = ss->bm->totvert == me->totvert && ss->bm->totedge == me->totedge &&
ss->bm->totloop == me->totloop && ss->bm->totface == me->totpoly;
if (!ok) {
BM_mesh_free(ss->bm);
/* Ensure ss->pbvh is in the cache so it can be destroyed in BKE_pbvh_free_bmesh. */
if (ss->pbvh) {
BKE_pbvh_set_cached(ob, ss->pbvh);
}
/* Destroy all cached PBVHs with this bmesh. */
BKE_pbvh_free_bmesh(NULL, ss->bm);
ss->pbvh = NULL;
ss->bm = NULL;
}
}
@ -600,7 +647,7 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
SCULPT_clear_scl_pointers(ss);
if (!ss->bm || !ss->pbvh || BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
SCULPT_pbvh_clear(ob);
SCULPT_pbvh_clear(ob, false);
}
else {
/*sculpt session was set up by paint.c. just call SCULPT_update_customdata_refs to be safe*/
@ -614,6 +661,19 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
return;
}
PBVH *pbvh = BKE_pbvh_get_or_free_cached(ob, BKE_object_get_original_mesh(ob), PBVH_BMESH);
if (pbvh) {
BMesh *bm = BKE_pbvh_get_bmesh(pbvh);
if (!ss->bm) {
ss->bm = bm;
}
else if (ss->bm != bm) {
printf("%s: bmesh differed!\n");
SCULPT_pbvh_clear(ob, false);
}
}
const BMAllocTemplate allocsize = {
.totvert = 2048 * 16, .totface = 2048 * 16, .totloop = 4196 * 16, .totedge = 2048 * 16};
@ -624,6 +684,11 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
ss->mdyntopo_verts = NULL;
}
if (ss->face_areas) {
MEM_freeN(ss->face_areas);
ss->face_areas = NULL;
}
/* Dynamic topology doesn't ensure selection state is valid, so remove T36280. */
BKE_mesh_mselect_clear(me);
@ -722,7 +787,7 @@ static void SCULPT_dynamic_topology_disable_ex(
SculptSession *ss = ob->sculpt;
Mesh *me = ob->data;
SCULPT_pbvh_clear(ob);
SCULPT_pbvh_clear(ob, true);
/* destroy non-customdata temporary layers (which are rarely (never?) used for PBVH_BMESH) */
SCULPT_release_attributes(ss, ob, true);
@ -747,7 +812,8 @@ static void SCULPT_dynamic_topology_disable_ex(
/* Typically valid but with global-undo they can be NULL, see: T36234. */
if (ss->bm) {
BM_mesh_free(ss->bm);
// PBVH now frees this
// BM_mesh_free(ss->bm);
ss->bm = NULL;
}

View File

@ -1044,7 +1044,12 @@ bool SCULPT_vertex_colors_poll(struct bContext *C);
void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags);
void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags);
void SCULPT_pbvh_clear(Object *ob);
typedef enum PBVHClearFlags {
PBVH_CLEAR_CACHE_PBVH = 1<<1,
PBVH_CLEAR_FREE_BMESH = 1 << 2,
} PBVHClearFlags;
void SCULPT_pbvh_clear(Object *ob, bool cache_pbvh);
/**
* Flush displacement from deformed PBVH to original layer.

View File

@ -166,7 +166,7 @@ static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
SCULPT_pbvh_clear(ob);
SCULPT_pbvh_clear(ob, false);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
@ -334,7 +334,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
}
/* Redraw. */
SCULPT_pbvh_clear(ob);
SCULPT_pbvh_clear(ob, false);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;

View File

@ -743,7 +743,7 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob,
}
else {
printf("undo triggered pbvh rebuild");
SCULPT_pbvh_clear(ob);
SCULPT_pbvh_clear(ob, false);
}
}
@ -753,7 +753,7 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode, bool is_
SculptSession *ss = ob->sculpt;
Mesh *me = ob->data;
SCULPT_pbvh_clear(ob);
SCULPT_pbvh_clear(ob, false);
SCULPT_clear_scl_pointers(ss);
ss->active_face_index.i = ss->active_vertex_index.i = 0;
@ -977,7 +977,7 @@ static void sculpt_undo_geometry_free_data(SculptUndoNodeGeometry *geometry)
static void sculpt_undo_geometry_restore(SculptUndoNode *unode, Object *object)
{
if (unode->geometry_clear_pbvh) {
SCULPT_pbvh_clear(object);
SCULPT_pbvh_clear(object, false);
}
if (unode->applied) {
@ -1165,7 +1165,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
// PBVH is corrupted at this point, destroy it
SCULPT_pbvh_clear(ob);
SCULPT_pbvh_clear(ob, false);
}
#endif
@ -2278,6 +2278,10 @@ void sculpt_undo_push_begin_ex(Object *ob, const char *name, bool no_first_entry
BKE_pbvh_set_bm_log(ss->pbvh, ss->bm_log);
}
}
if (ss->pbvh) {
BKE_pbvh_set_cached(ob, ss->pbvh);
}
}
void SCULPT_undo_push_begin(Object *ob, const char *name)

View File

@ -106,6 +106,9 @@ enum {
*/
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
const struct MLoop *mloop,
const struct MPoly *mpoly,
const struct MLoopTri *looptri,
const CustomData *vdata,
const CustomData *ldata,
const float *vmask,

View File

@ -240,6 +240,9 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
const MLoop *mloop,
const MPoly *mpoly,
const MLoopTri *looptri,
const CustomData *vdata,
const CustomData *ldata,
const float *vmask,
@ -255,6 +258,11 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
GPUAttrRef vcol_refs[MAX_GPU_ATTR];
GPUAttrRef cd_uvs[MAX_GPU_ATTR];
buffers->mvert = mvert;
buffers->mloop = mloop;
buffers->mpoly = mpoly;
buffers->looptri = looptri;
int totcol = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER,
CD_MASK_PROP_COLOR | CD_MASK_MLOOPCOL,
vdata,

View File

@ -34,6 +34,7 @@ struct Ipo;
struct Material;
struct Mesh;
struct Object;
struct PBVH;
struct PartDeflect;
struct Path;
struct RigidBodyOb;
@ -206,6 +207,9 @@ typedef struct Object_Runtime {
int crazyspace_num_verts;
int _pad3[3];
struct PBVH *cached_pbvh;
void *_pad4;
} Object_Runtime;
typedef struct ObjectLineArt {
@ -433,7 +437,8 @@ typedef struct Object {
ObjectLineArt lineart;
/** Runtime evaluation data (keep last). */
void *_pad9;
//void *_pad9;
struct PBVH *cached_pbvh2;
Object_Runtime runtime;
} Object;

View File

@ -47,6 +47,7 @@
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_particle.h"
#include "BKE_pbvh.h"
#include "BKE_shader_fx.h"
#include "BKE_sound.h"
#include "BKE_vfont.h"
@ -407,6 +408,7 @@ int main(int argc,
DEG_register_node_types();
BKE_brush_system_init();
BKE_pbvh_system_init();
RE_texture_rng_init();
BKE_callback_global_init();