Sculpt-dev: Performance improvements
* PBVH_BMESH construction is now partially threaded. * Fixed n**2 behavior in freelist-based bmesh id implementation. I'd really rather get range-tree faster, but this works as a stopgap. * Removed a bunch of debug ATTR_NO_OPTs.
This commit is contained in:
parent
35133f9a06
commit
a72721a2ae
|
@ -309,7 +309,8 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
|
|||
const int cd_face_node_offset,
|
||||
const int cd_sculpt_vert,
|
||||
const int cd_face_areas,
|
||||
bool fast_draw);
|
||||
bool fast_draw,
|
||||
bool update_sculptverts);
|
||||
void BKE_pbvh_update_offsets(PBVH *pbvh,
|
||||
const int cd_vert_node_offset,
|
||||
const int cd_face_node_offset,
|
||||
|
@ -319,6 +320,18 @@ void BKE_pbvh_free(PBVH *pbvh);
|
|||
|
||||
void BKE_pbvh_set_bm_log(PBVH *pbvh, struct BMLog *log);
|
||||
|
||||
/* update MSculptVerts, doesn't take pbvh argument to allow usage if pbvh doesn't currently exist
|
||||
*/
|
||||
void BKE_pbvh_update_sculpt_verts(struct BMesh *bm,
|
||||
const int cd_sculpt_vert,
|
||||
const int cd_faceset_offset,
|
||||
const int cd_vert_node_offset,
|
||||
const int cd_face_node_offset,
|
||||
const int boundary_symmetry,
|
||||
const int vcol_type,
|
||||
const AttributeDomain vcol_domain,
|
||||
const int cd_vcol_offset);
|
||||
|
||||
/** update original data, only data whose r_** parameters are passed in will be updated*/
|
||||
void BKE_pbvh_bmesh_update_origvert(
|
||||
PBVH *pbvh, struct BMVert *v, float **r_co, float **r_no, float **r_color, bool log_undo);
|
||||
|
|
|
@ -194,7 +194,7 @@ bool BKE_id_attribute_find_unique_name(ID *id,
|
|||
return BLI_uniquename_cb(unique_name_cb, &data, NULL, '.', outname, MAX_CUSTOMDATA_LAYER_NAME);
|
||||
}
|
||||
|
||||
ATTR_NO_OPT CustomDataLayer *BKE_id_attribute_new(
|
||||
CustomDataLayer *BKE_id_attribute_new(
|
||||
ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
|
@ -300,7 +300,7 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ATTR_NO_OPT CustomDataLayer *BKE_id_attribute_from_index(const ID *id, int lookup_index)
|
||||
CustomDataLayer *BKE_id_attribute_from_index(const ID *id, int lookup_index)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
|
@ -501,7 +501,7 @@ CustomDataLayer *BKE_id_attributes_active_color_get(ID *id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ATTR_NO_OPT void BKE_id_attributes_active_color_set(ID *id, CustomDataLayer *active_layer)
|
||||
void BKE_id_attributes_active_color_set(ID *id, CustomDataLayer *active_layer)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
|
@ -585,7 +585,7 @@ CustomDataLayer *BKE_id_attributes_render_color_get(ID *id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ATTR_NO_OPT void BKE_id_attributes_render_color_set(ID *id, CustomDataLayer *active_layer)
|
||||
void BKE_id_attributes_render_color_set(ID *id, CustomDataLayer *active_layer)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
|
|
|
@ -5077,10 +5077,10 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
|
|||
customdata_unique_check, &data_arg, NULL, '.', nlayer->name, sizeof(nlayer->name));
|
||||
}
|
||||
|
||||
ATTR_NO_OPT void CustomData_validate_layer_name(const CustomData *data,
|
||||
int type,
|
||||
const char *name,
|
||||
char *outname)
|
||||
void CustomData_validate_layer_name(const CustomData *data,
|
||||
int type,
|
||||
const char *name,
|
||||
char *outname)
|
||||
{
|
||||
int index = -1;
|
||||
|
||||
|
|
|
@ -2382,7 +2382,7 @@ 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)
|
||||
static PBVH *build_pbvh_for_dynamic_topology(Object *ob, bool update_sculptverts)
|
||||
{
|
||||
PBVH *pbvh = BKE_pbvh_new();
|
||||
|
||||
|
@ -2397,7 +2397,8 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
|
|||
ob->sculpt->cd_face_node_offset,
|
||||
ob->sculpt->cd_sculpt_vert,
|
||||
ob->sculpt->cd_face_areas,
|
||||
ob->sculpt->fast_draw);
|
||||
ob->sculpt->fast_draw,
|
||||
update_sculptverts);
|
||||
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
|
||||
pbvh_show_face_sets_set(pbvh, false);
|
||||
|
||||
|
@ -2609,7 +2610,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
|
|||
|
||||
if (ob->sculpt->bm != NULL) {
|
||||
/* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
|
||||
pbvh = build_pbvh_for_dynamic_topology(ob);
|
||||
pbvh = build_pbvh_for_dynamic_topology(ob, false);
|
||||
|
||||
ob->sculpt->pbvh = pbvh;
|
||||
}
|
||||
|
@ -2638,7 +2639,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
|
|||
SCULPT_dyntopo_node_layers_add(ob->sculpt, ob);
|
||||
SCULPT_undo_ensure_bmlog(ob);
|
||||
|
||||
pbvh = build_pbvh_for_dynamic_topology(ob);
|
||||
pbvh = build_pbvh_for_dynamic_topology(ob, true);
|
||||
|
||||
SCULPT_update_customdata_refs(ob->sculpt, ob);
|
||||
}
|
||||
|
|
|
@ -1372,10 +1372,10 @@ static int pbvh_get_buffers_update_flags(PBVH *UNUSED(pbvh))
|
|||
}
|
||||
|
||||
/* updates pbvh->vcol_domain, vcol_type too */
|
||||
ATTR_NO_OPT bool BKE_pbvh_get_color_layer(PBVH *pbvh,
|
||||
const Mesh *me,
|
||||
CustomDataLayer **r_cl,
|
||||
AttributeDomain *r_attr)
|
||||
bool BKE_pbvh_get_color_layer(PBVH *pbvh,
|
||||
const Mesh *me,
|
||||
CustomDataLayer **r_cl,
|
||||
AttributeDomain *r_attr)
|
||||
{
|
||||
CustomDataLayer *cl = BKE_id_attributes_active_color_get((ID *)me);
|
||||
AttributeDomain domain;
|
||||
|
@ -1669,6 +1669,14 @@ static void pbvh_update_draw_buffers(
|
|||
ldata = pbvh->ldata;
|
||||
}
|
||||
|
||||
if (!vdata && me) {
|
||||
vdata = &me->vdata;
|
||||
}
|
||||
|
||||
if (!ldata && me) {
|
||||
ldata = &me->ldata;
|
||||
}
|
||||
|
||||
CustomDataLayer *vcol_layer = NULL;
|
||||
AttributeDomain domain;
|
||||
BKE_pbvh_get_color_layer(pbvh, me, &vcol_layer, &domain);
|
||||
|
|
|
@ -300,12 +300,47 @@ static void pbvh_bmesh_node_finalize(PBVH *pbvh,
|
|||
|
||||
BKE_pbvh_node_fully_hidden_set(n, !has_visible);
|
||||
n->flag |= PBVH_UpdateNormals | PBVH_UpdateCurvatureDir | PBVH_UpdateTris;
|
||||
n->flag |= PBVH_UpdateBB | PBVH_UpdateOriginalBB;
|
||||
|
||||
if (add_orco) {
|
||||
BKE_pbvh_bmesh_check_tris(pbvh, n);
|
||||
}
|
||||
}
|
||||
|
||||
static void pbvh_print_mem_size(PBVH *pbvh)
|
||||
{
|
||||
BMesh *bm = pbvh->bm;
|
||||
CustomData *cdatas[4] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata};
|
||||
|
||||
int tots[4] = {bm->totvert, bm->totedge, bm->totloop, bm->totface};
|
||||
int sizes[4] = {
|
||||
(int)sizeof(BMVert), (int)sizeof(BMEdge), (int)sizeof(BMLoop), (int)sizeof(BMFace)};
|
||||
|
||||
float memsize1[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
float memsize2[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
CustomData *cdata = cdatas[i];
|
||||
|
||||
memsize1[i] = (float)(sizes[i] * tots[i]) / 1024.0f / 1024.0f;
|
||||
memsize2[i] = (float)(cdata->totsize * tots[i]) / 1024.0f / 1024.0f;
|
||||
}
|
||||
|
||||
printf("base sizes:\n");
|
||||
printf(" v: %.2fmb e: %.2fmb l: %.2fmb f: %.2fmb\n",
|
||||
memsize1[0],
|
||||
memsize1[1],
|
||||
memsize1[2],
|
||||
memsize1[3]);
|
||||
|
||||
printf("custom attribute sizes:\n");
|
||||
printf(" v: %.2fmb e: %.2fmb l: %.2fmb f: %.2fmb\n",
|
||||
memsize2[0],
|
||||
memsize2[1],
|
||||
memsize2[2],
|
||||
memsize2[3]);
|
||||
}
|
||||
|
||||
/* Recursively split the node if it exceeds the leaf_limit */
|
||||
static void pbvh_bmesh_node_split(
|
||||
PBVH *pbvh, const BBC *bbc_array, int node_index, bool add_orco, int depth)
|
||||
|
@ -318,7 +353,7 @@ static void pbvh_bmesh_node_split(
|
|||
BKE_pbvh_free_proxyarray(pbvh, n);
|
||||
#endif
|
||||
|
||||
if (depth > 6 || BLI_table_gset_len(n->bm_faces) <= pbvh->leaf_limit) {
|
||||
if (n->depth >= pbvh->depth_limit || BLI_table_gset_len(n->bm_faces) <= pbvh->leaf_limit) {
|
||||
/* Node limit not exceeded */
|
||||
pbvh_bmesh_node_finalize(pbvh, node_index, cd_vert_node_offset, cd_face_node_offset, add_orco);
|
||||
return;
|
||||
|
@ -355,6 +390,8 @@ static void pbvh_bmesh_node_split(
|
|||
/* Initialize children */
|
||||
PBVHNode *c1 = &pbvh->nodes[children], *c2 = &pbvh->nodes[children + 1];
|
||||
|
||||
c1->depth = c2->depth = n->depth + 1;
|
||||
|
||||
c1->flag |= PBVH_Leaf;
|
||||
c2->flag |= PBVH_Leaf;
|
||||
c1->bm_faces = BLI_table_gset_new_ex("bm_faces", BLI_table_gset_len(n->bm_faces) / 2);
|
||||
|
@ -476,7 +513,7 @@ bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
|
|||
|
||||
// pbvh_bmesh_check_nodes(pbvh);
|
||||
|
||||
if (bm_faces_size <= pbvh->leaf_limit) {
|
||||
if (bm_faces_size <= pbvh->leaf_limit || pbvh->nodes[node_index].depth >= pbvh->depth_limit) {
|
||||
/* Node limit not exceeded */
|
||||
return false;
|
||||
}
|
||||
|
@ -809,7 +846,7 @@ void BKE_pbvh_bmesh_regen_node_verts(PBVH *pbvh)
|
|||
}
|
||||
}
|
||||
|
||||
ATTR_NO_OPT void BKE_pbvh_bmesh_get_vcol(
|
||||
void BKE_pbvh_bmesh_get_vcol(
|
||||
BMVert *v, float color[4], int vcol_type, AttributeDomain vcol_domain, int vcol_offset)
|
||||
{
|
||||
if (vcol_domain == ATTR_DOMAIN_POINT) {
|
||||
|
@ -1241,6 +1278,16 @@ void pbvh_bmesh_normals_update(PBVH *pbvh, PBVHNode **nodes, int totnode)
|
|||
for (int j = 0; j < data->tot_border_verts; j++) {
|
||||
BMVert *v = data->border_verts[j];
|
||||
|
||||
if (BM_elem_is_free((BMElem *)v, BM_VERT)) {
|
||||
printf("%s: error, v was freed!\n", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (v->head.index < 0 || v->head.index >= bm->totvert) {
|
||||
printf("%s: error, v->head.index was out of bounds!\n", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BLI_BITMAP_TEST(visit, v->head.index)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1304,23 +1351,31 @@ static void pbvh_bmesh_normals_update_old(PBVHNode **nodes, int totnode)
|
|||
}
|
||||
}
|
||||
|
||||
struct FastNodeBuildInfo {
|
||||
typedef struct FastNodeBuildInfo {
|
||||
int totface; /* number of faces */
|
||||
int start; /* start of faces in array */
|
||||
int depth;
|
||||
int node_index;
|
||||
struct FastNodeBuildInfo *child1;
|
||||
struct FastNodeBuildInfo *child2;
|
||||
};
|
||||
float cent[3], no[3];
|
||||
int tag;
|
||||
} FastNodeBuildInfo;
|
||||
|
||||
/**
|
||||
* Recursively split the node if it exceeds the leaf_limit.
|
||||
* This function is multi-thread-able since each invocation applies
|
||||
* to a sub part of the arrays.
|
||||
*/
|
||||
static void pbvh_bmesh_node_limit_ensure_fast(
|
||||
PBVH *pbvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, MemArena *arena)
|
||||
static void pbvh_bmesh_node_limit_ensure_fast(PBVH *pbvh,
|
||||
BMFace **nodeinfo,
|
||||
BBC *bbc_array,
|
||||
FastNodeBuildInfo *node,
|
||||
FastNodeBuildInfo ***r_leaves,
|
||||
int *r_totleaf,
|
||||
MemArena *arena)
|
||||
{
|
||||
struct FastNodeBuildInfo *child1, *child2;
|
||||
FastNodeBuildInfo *child1, *child2;
|
||||
|
||||
if (node->totface <= pbvh->leaf_limit || node->depth >= pbvh->depth_limit) {
|
||||
return;
|
||||
|
@ -1399,8 +1454,8 @@ static void pbvh_bmesh_node_limit_ensure_fast(
|
|||
* each sequential part belonging to one node only */
|
||||
BLI_assert((num_child1 + num_child2) == node->totface);
|
||||
|
||||
node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
|
||||
node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
|
||||
node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
|
||||
node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
|
||||
|
||||
child1->totface = num_child1;
|
||||
child1->start = node->start;
|
||||
|
@ -1412,96 +1467,149 @@ static void pbvh_bmesh_node_limit_ensure_fast(
|
|||
|
||||
child1->child1 = child1->child2 = child2->child1 = child2->child2 = NULL;
|
||||
|
||||
pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, child1, arena);
|
||||
pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, child2, arena);
|
||||
pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, child1, r_leaves, r_totleaf, arena);
|
||||
pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, child2, r_leaves, r_totleaf, arena);
|
||||
|
||||
FastNodeBuildInfo **leaves = *r_leaves;
|
||||
BLI_array_declare(leaves);
|
||||
BLI_array_len_set(leaves, *r_totleaf);
|
||||
|
||||
if (!child1->child1 && !child1->child2) {
|
||||
BLI_array_append(leaves, child1);
|
||||
}
|
||||
|
||||
if (!child2->child1 && !child2->child2) {
|
||||
BLI_array_append(leaves, child2);
|
||||
}
|
||||
|
||||
*r_leaves = leaves;
|
||||
*r_totleaf = BLI_array_len(leaves);
|
||||
}
|
||||
|
||||
static void pbvh_bmesh_create_nodes_fast_recursive(
|
||||
PBVH *pbvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, int node_index)
|
||||
{
|
||||
PBVHNode *n = pbvh->nodes + node_index;
|
||||
typedef struct LeafBuilderThreadData {
|
||||
PBVH *pbvh;
|
||||
BMFace **nodeinfo;
|
||||
BBC *bbc_array;
|
||||
FastNodeBuildInfo **leaves;
|
||||
} LeafBuilderThreadData;
|
||||
|
||||
static void pbvh_bmesh_create_leaf_fast_task_cb(void *__restrict userdata,
|
||||
const int i,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
LeafBuilderThreadData *data = (LeafBuilderThreadData *)userdata;
|
||||
PBVH *pbvh = data->pbvh;
|
||||
BMFace **nodeinfo = data->nodeinfo;
|
||||
BBC *bbc_array = data->bbc_array;
|
||||
struct FastNodeBuildInfo *node = data->leaves[i];
|
||||
|
||||
/* node does not have children so it's a leaf node, populate with faces and tag accordingly
|
||||
* this is an expensive part but it's not so easily thread-able due to vertex node indices */
|
||||
// const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
|
||||
const int cd_face_node_offset = pbvh->cd_face_node_offset;
|
||||
|
||||
PBVHNode *n = pbvh->nodes + node->node_index;
|
||||
const int node_index = node->node_index;
|
||||
|
||||
bool has_visible = false;
|
||||
|
||||
n->flag = PBVH_Leaf | PBVH_UpdateTris;
|
||||
n->bm_faces = BLI_table_gset_new_ex("bm_faces", node->totface);
|
||||
|
||||
/* Create vert hash sets */
|
||||
n->bm_unique_verts = BLI_table_gset_new_ex("bm_unique_verts", node->totface * 3);
|
||||
n->bm_other_verts = BLI_table_gset_new_ex("bm_other_verts", node->totface * 3);
|
||||
|
||||
BB_reset(&n->vb);
|
||||
|
||||
const int end = node->start + node->totface;
|
||||
|
||||
for (int i = node->start; i < end; i++) {
|
||||
BMFace *f = nodeinfo[i];
|
||||
BBC *bbc = &bbc_array[BM_elem_index_get(f)];
|
||||
|
||||
/* Update ownership of faces */
|
||||
BLI_table_gset_insert(n->bm_faces, f);
|
||||
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
|
||||
|
||||
/* Update vertices */
|
||||
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
|
||||
BMLoop *l_iter = l_first;
|
||||
do {
|
||||
BMVert *v = l_iter->v;
|
||||
|
||||
if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
|
||||
BLI_table_gset_insert(n->bm_unique_verts, v);
|
||||
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, node_index);
|
||||
}
|
||||
else {
|
||||
BLI_table_gset_add(n->bm_other_verts, v);
|
||||
}
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
|
||||
/* Update node bounding box */
|
||||
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
has_visible = true;
|
||||
}
|
||||
|
||||
BB_expand_with_bb(&n->vb, (BB *)bbc);
|
||||
}
|
||||
|
||||
BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && n->vb.bmin[1] <= n->vb.bmax[1] &&
|
||||
n->vb.bmin[2] <= n->vb.bmax[2]);
|
||||
|
||||
n->orig_vb = n->vb;
|
||||
|
||||
/* Build GPU buffers for new node and update vertex normals */
|
||||
BKE_pbvh_node_mark_rebuild_draw(n);
|
||||
|
||||
BKE_pbvh_node_fully_hidden_set(n, !has_visible);
|
||||
n->flag |= PBVH_UpdateNormals | PBVH_UpdateCurvatureDir;
|
||||
}
|
||||
|
||||
static void pbvh_bmesh_create_nodes_fast_recursive_create(PBVH *pbvh,
|
||||
BMFace **nodeinfo,
|
||||
BBC *bbc_array,
|
||||
struct FastNodeBuildInfo *node)
|
||||
{
|
||||
/* two cases, node does not have children or does have children */
|
||||
if (node->child1) {
|
||||
int children_offset = pbvh->totnode;
|
||||
|
||||
n->children_offset = children_offset;
|
||||
pbvh_grow_nodes(pbvh, pbvh->totnode + 2);
|
||||
pbvh_bmesh_create_nodes_fast_recursive(
|
||||
pbvh, nodeinfo, bbc_array, node->child1, children_offset);
|
||||
pbvh_bmesh_create_nodes_fast_recursive(
|
||||
pbvh, nodeinfo, bbc_array, node->child2, children_offset + 1);
|
||||
|
||||
n = &pbvh->nodes[node_index];
|
||||
PBVHNode *n = pbvh->nodes + node->node_index;
|
||||
n->children_offset = children_offset;
|
||||
|
||||
n->depth = node->depth;
|
||||
(n + 1)->depth = node->depth + 1;
|
||||
(n + 2)->depth = node->depth + 1;
|
||||
|
||||
node->child1->node_index = children_offset;
|
||||
node->child2->node_index = children_offset + 1;
|
||||
|
||||
pbvh_bmesh_create_nodes_fast_recursive_create(pbvh, nodeinfo, bbc_array, node->child1);
|
||||
pbvh_bmesh_create_nodes_fast_recursive_create(pbvh, nodeinfo, bbc_array, node->child2);
|
||||
}
|
||||
}
|
||||
|
||||
static void pbvh_bmesh_create_nodes_fast_recursive_final(PBVH *pbvh,
|
||||
BMFace **nodeinfo,
|
||||
BBC *bbc_array,
|
||||
struct FastNodeBuildInfo *node)
|
||||
{
|
||||
/* two cases, node does not have children or does have children */
|
||||
if (node->child1) {
|
||||
pbvh_bmesh_create_nodes_fast_recursive_final(pbvh, nodeinfo, bbc_array, node->child1);
|
||||
pbvh_bmesh_create_nodes_fast_recursive_final(pbvh, nodeinfo, bbc_array, node->child2);
|
||||
|
||||
PBVHNode *n = pbvh->nodes + node->node_index;
|
||||
|
||||
/* Update bounding box */
|
||||
BB_reset(&n->vb);
|
||||
BB_expand_with_bb(&n->vb, &pbvh->nodes[n->children_offset].vb);
|
||||
BB_expand_with_bb(&n->vb, &pbvh->nodes[n->children_offset + 1].vb);
|
||||
BB_expand_with_bb(&n->vb, &pbvh->nodes[node->child1->node_index].vb);
|
||||
BB_expand_with_bb(&n->vb, &pbvh->nodes[node->child2->node_index].vb);
|
||||
n->orig_vb = n->vb;
|
||||
}
|
||||
else {
|
||||
/* node does not have children so it's a leaf node, populate with faces and tag accordingly
|
||||
* this is an expensive part but it's not so easily thread-able due to vertex node indices */
|
||||
const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
|
||||
const int cd_face_node_offset = pbvh->cd_face_node_offset;
|
||||
|
||||
bool has_visible = false;
|
||||
|
||||
n->flag = PBVH_Leaf | PBVH_UpdateTris;
|
||||
n->bm_faces = BLI_table_gset_new_ex("bm_faces", node->totface);
|
||||
|
||||
/* Create vert hash sets */
|
||||
n->bm_unique_verts = BLI_table_gset_new("bm_unique_verts");
|
||||
n->bm_other_verts = BLI_table_gset_new("bm_other_verts");
|
||||
|
||||
BB_reset(&n->vb);
|
||||
|
||||
const int end = node->start + node->totface;
|
||||
|
||||
for (int i = node->start; i < end; i++) {
|
||||
BMFace *f = nodeinfo[i];
|
||||
BBC *bbc = &bbc_array[BM_elem_index_get(f)];
|
||||
|
||||
/* Update ownership of faces */
|
||||
BLI_table_gset_insert(n->bm_faces, f);
|
||||
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
|
||||
|
||||
/* Update vertices */
|
||||
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
|
||||
BMLoop *l_iter = l_first;
|
||||
do {
|
||||
BMVert *v = l_iter->v;
|
||||
if (!BLI_table_gset_haskey(n->bm_unique_verts, v)) {
|
||||
if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
|
||||
BLI_table_gset_add(n->bm_other_verts, v);
|
||||
}
|
||||
else {
|
||||
BLI_table_gset_insert(n->bm_unique_verts, v);
|
||||
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
|
||||
}
|
||||
}
|
||||
/* Update node bounding box */
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
|
||||
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
has_visible = true;
|
||||
}
|
||||
|
||||
BB_expand_with_bb(&n->vb, (BB *)bbc);
|
||||
}
|
||||
|
||||
BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && n->vb.bmin[1] <= n->vb.bmax[1] &&
|
||||
n->vb.bmin[2] <= n->vb.bmax[2]);
|
||||
|
||||
n->orig_vb = n->vb;
|
||||
|
||||
/* Build GPU buffers for new node and update vertex normals */
|
||||
BKE_pbvh_node_mark_rebuild_draw(n);
|
||||
|
||||
BKE_pbvh_node_fully_hidden_set(n, !has_visible);
|
||||
n->flag |= PBVH_UpdateNormals | PBVH_UpdateCurvatureDir;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************** Public API *****************************/
|
||||
|
@ -1909,6 +2017,180 @@ void BKE_pbvh_update_all_boundary_bmesh(PBVH *pbvh)
|
|||
} while (l != e->l);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct FaceBinThread {
|
||||
MemArena *arena;
|
||||
FastNodeBuildInfo *nodes, **leaves;
|
||||
int totnode, totleaf;
|
||||
} FaceBinThread;
|
||||
|
||||
static void coalese_pbvh(PBVH *pbvh, BMesh *bm)
|
||||
{
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
|
||||
const char tag = BM_ELEM_TAG_ALT;
|
||||
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
f->head.hflag &= ~tag;
|
||||
}
|
||||
|
||||
int leafsize = 1000;
|
||||
double f1 = pow(2.0, ceil(log2(bm->totface / (double)leafsize)));
|
||||
leafsize = (int)ceil(bm->totface / f1);
|
||||
|
||||
printf("leafsize: %d\n", leafsize);
|
||||
|
||||
int *fmap = MEM_calloc_arrayN(bm->totface, sizeof(int), "pbvh face map");
|
||||
int totleaf = 0;
|
||||
|
||||
FastNodeBuildInfo *nodes = NULL;
|
||||
BLI_array_declare(nodes);
|
||||
|
||||
const int qsize = leafsize;
|
||||
BMFace **queue = MEM_calloc_arrayN(qsize, sizeof(*queue), "pbvh queue");
|
||||
|
||||
BM_mesh_elem_table_ensure(bm, BM_FACE | BM_VERT);
|
||||
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
int qhead = 0;
|
||||
int qtail = 0;
|
||||
|
||||
if (f->head.hflag & tag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int ni = totleaf++;
|
||||
BLI_array_grow_one(nodes);
|
||||
|
||||
FastNodeBuildInfo *node = nodes + BLI_array_len(nodes) - 1;
|
||||
copy_v3_v3(node->cent, f->l_first->v->co);
|
||||
copy_v3_v3(node->no, f->no);
|
||||
|
||||
queue[0] = f;
|
||||
qhead = 1;
|
||||
|
||||
while (qhead != qtail) {
|
||||
BMFace *f2 = queue[qtail];
|
||||
qtail = (qtail + 1) % qsize;
|
||||
|
||||
fmap[f2->head.index] = ni;
|
||||
node->totface++;
|
||||
|
||||
BMLoop *l = f2->l_first;
|
||||
do {
|
||||
BMLoop *l2 = l;
|
||||
do {
|
||||
if (!(l2->f->head.hflag & tag)) {
|
||||
l2->f->head.hflag |= tag;
|
||||
|
||||
queue[qhead] = l2->f;
|
||||
qhead = (qhead + 1) % qsize;
|
||||
}
|
||||
} while ((l2 = l2->radial_next) != l);
|
||||
} while ((l = l->next) != f2->l_first);
|
||||
}
|
||||
}
|
||||
|
||||
printf("totleafs: %d\n", totleaf);
|
||||
BLI_array_grow_items(nodes, BLI_array_len(nodes) << 1);
|
||||
|
||||
const int tag2 = 1;
|
||||
int pi = totleaf;
|
||||
int starti = 0;
|
||||
int endi = totleaf;
|
||||
|
||||
for (int step = 0; step < 55; step++) {
|
||||
if (endi - starti <= 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = starti; i < endi; i++) {
|
||||
FastNodeBuildInfo *n1 = nodes + i, *n2 = NULL;
|
||||
|
||||
if (n1->tag & tag2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float mindis = 1e17;
|
||||
|
||||
for (int j = starti; j < endi; j++) {
|
||||
FastNodeBuildInfo *n3 = nodes + j;
|
||||
|
||||
if (j == i || n3->tag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float dis = len_squared_v3v3(n1->cent, n3->cent);
|
||||
if (dis < mindis) {
|
||||
mindis = dis;
|
||||
n2 = n3;
|
||||
}
|
||||
}
|
||||
|
||||
if (!n2) {
|
||||
break;
|
||||
}
|
||||
|
||||
FastNodeBuildInfo *parent = nodes + pi;
|
||||
pi++;
|
||||
|
||||
n1->tag |= tag2;
|
||||
n2->tag |= tag2;
|
||||
parent->tag = 0;
|
||||
parent->child1 = n1;
|
||||
parent->child2 = n2;
|
||||
}
|
||||
|
||||
starti = endi;
|
||||
endi = pi;
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(queue);
|
||||
MEM_SAFE_FREE(fmap);
|
||||
BLI_array_free(nodes);
|
||||
}
|
||||
|
||||
void BKE_pbvh_update_sculpt_verts(BMesh *bm,
|
||||
const int cd_sculpt_vert,
|
||||
const int cd_faceset_offset,
|
||||
const int cd_vert_node_offset,
|
||||
const int cd_face_node_offset,
|
||||
const int boundary_symmetry,
|
||||
const int vcol_type,
|
||||
const AttributeDomain vcol_domain,
|
||||
const int cd_vcol_offset)
|
||||
{
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
|
||||
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
MSculptVert *mv = BKE_PBVH_SCULPTVERT(cd_sculpt_vert, v);
|
||||
|
||||
mv->flag = SCULPTVERT_NEED_DISK_SORT | SCULPTVERT_NEED_VALENCE;
|
||||
|
||||
bke_pbvh_update_vert_boundary(cd_sculpt_vert,
|
||||
cd_faceset_offset,
|
||||
cd_vert_node_offset,
|
||||
cd_face_node_offset,
|
||||
-1,
|
||||
v,
|
||||
boundary_symmetry);
|
||||
|
||||
BKE_pbvh_bmesh_update_valence(cd_sculpt_vert, (SculptVertRef){(intptr_t)v});
|
||||
|
||||
copy_v3_v3(mv->origco, v->co);
|
||||
copy_v3_v3(mv->origno, v->no);
|
||||
|
||||
if (vcol_type != -1) {
|
||||
BKE_pbvh_bmesh_get_vcol(v, mv->origcolor, vcol_type, vcol_domain, cd_vcol_offset);
|
||||
}
|
||||
else {
|
||||
zero_v4(mv->origcolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Build a PBVH from a BMesh */
|
||||
void BKE_pbvh_build_bmesh(PBVH *pbvh,
|
||||
struct Mesh *me,
|
||||
|
@ -1919,8 +2201,11 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
|
|||
const int cd_face_node_offset,
|
||||
const int cd_sculpt_vert,
|
||||
const int cd_face_areas,
|
||||
bool fast_draw)
|
||||
bool fast_draw,
|
||||
bool update_sculptverts)
|
||||
{
|
||||
// coalese_pbvh(pbvh, bm);
|
||||
|
||||
pbvh->cd_face_area = cd_face_areas;
|
||||
pbvh->cd_vert_node_offset = cd_vert_node_offset;
|
||||
pbvh->cd_face_node_offset = cd_face_node_offset;
|
||||
|
@ -1945,8 +2230,6 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
|
|||
BMIter iter;
|
||||
BMVert *v;
|
||||
|
||||
// BKE_pbvh_update_all_boundary_bmesh(pbvh);
|
||||
|
||||
if (smooth_shading) {
|
||||
pbvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
|
||||
}
|
||||
|
@ -1991,58 +2274,78 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
|
|||
}
|
||||
|
||||
/* setup root node */
|
||||
struct FastNodeBuildInfo rootnode = {0};
|
||||
struct FastNodeBuildInfo rootnode = {0}, **leaves = NULL;
|
||||
|
||||
rootnode.totface = bm->totface;
|
||||
int totleaf = 0;
|
||||
|
||||
/* start recursion, assign faces to nodes accordingly */
|
||||
pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, &rootnode, arena);
|
||||
pbvh_bmesh_node_limit_ensure_fast(
|
||||
pbvh, nodeinfo, bbc_array, &rootnode, &leaves, &totleaf, arena);
|
||||
|
||||
/* We now have all faces assigned to a node,
|
||||
* next we need to assign those to the gsets of the nodes. */
|
||||
pbvh_grow_nodes(pbvh, 1);
|
||||
rootnode.node_index = 0;
|
||||
|
||||
/* Start with all faces in the root node */
|
||||
pbvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
|
||||
pbvh->totnode = 1;
|
||||
pbvh_bmesh_create_nodes_fast_recursive_create(pbvh, nodeinfo, bbc_array, &rootnode);
|
||||
|
||||
/* build leaf nodes */
|
||||
LeafBuilderThreadData tdata = {
|
||||
.pbvh = pbvh, .nodeinfo = nodeinfo, .bbc_array = bbc_array, .leaves = leaves};
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totleaf);
|
||||
BLI_task_parallel_range(0, totleaf, &tdata, pbvh_bmesh_create_leaf_fast_task_cb, &settings);
|
||||
|
||||
// pbvh_bmesh_create_leaf_fast(pbvh, nodeinfo, bbc_array, leaves[i]);
|
||||
|
||||
MEM_SAFE_FREE(leaves);
|
||||
|
||||
/* take root node and visit and populate children recursively */
|
||||
pbvh_bmesh_create_nodes_fast_recursive(pbvh, nodeinfo, bbc_array, &rootnode, 0);
|
||||
pbvh_bmesh_create_nodes_fast_recursive_final(pbvh, nodeinfo, bbc_array, &rootnode);
|
||||
|
||||
BLI_memarena_free(arena);
|
||||
MEM_freeN(bbc_array);
|
||||
MEM_freeN(nodeinfo);
|
||||
|
||||
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
MSculptVert *mv = BKE_PBVH_SCULPTVERT(cd_sculpt_vert, v);
|
||||
|
||||
mv->flag = SCULPTVERT_NEED_DISK_SORT;
|
||||
|
||||
bke_pbvh_update_vert_boundary(pbvh->cd_sculpt_vert,
|
||||
pbvh->cd_faceset_offset,
|
||||
pbvh->cd_vert_node_offset,
|
||||
pbvh->cd_face_node_offset,
|
||||
-1,
|
||||
v,
|
||||
pbvh->boundary_symmetry);
|
||||
BKE_pbvh_bmesh_update_valence(pbvh->cd_sculpt_vert, (SculptVertRef){(intptr_t)v});
|
||||
|
||||
copy_v3_v3(mv->origco, v->co);
|
||||
copy_v3_v3(mv->origno, v->no);
|
||||
|
||||
if (pbvh->vcol_type != -1) {
|
||||
BKE_pbvh_bmesh_get_vcol(
|
||||
v, mv->origcolor, pbvh->vcol_type, pbvh->vcol_domain, pbvh->cd_vcol_offset);
|
||||
}
|
||||
else {
|
||||
zero_v4(mv->origcolor);
|
||||
}
|
||||
}
|
||||
|
||||
if (me) { // ensure pbvh->vcol_type, vcol_domain and cd_vcol_offset are up to date
|
||||
CustomDataLayer *cl;
|
||||
AttributeDomain domain;
|
||||
|
||||
BKE_pbvh_get_color_layer(pbvh, me, &cl, &domain);
|
||||
}
|
||||
|
||||
/*final check that nodes are sufficiently subdivided*/
|
||||
int totnode = pbvh->totnode;
|
||||
|
||||
for (int i = 0; i < totnode; i++) {
|
||||
PBVHNode *n = pbvh->nodes + i;
|
||||
|
||||
if (totnode != pbvh->totnode) {
|
||||
#ifdef PROXY_ADVANCED
|
||||
BKE_pbvh_free_proxyarray(pbvh, n);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (n->flag & PBVH_Leaf) {
|
||||
/* Recursively split nodes that have gotten too many
|
||||
* elements */
|
||||
pbvh_bmesh_node_limit_ensure(pbvh, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (update_sculptverts) {
|
||||
BKE_pbvh_update_sculpt_verts(pbvh->bm,
|
||||
pbvh->cd_sculpt_vert,
|
||||
pbvh->cd_faceset_offset,
|
||||
pbvh->cd_vert_node_offset,
|
||||
pbvh->cd_face_node_offset,
|
||||
pbvh->boundary_symmetry,
|
||||
pbvh->vcol_type,
|
||||
pbvh->vcol_domain,
|
||||
pbvh->cd_vcol_offset);
|
||||
}
|
||||
|
||||
pbvh_print_mem_size(pbvh);
|
||||
}
|
||||
|
||||
void BKE_pbvh_set_bm_log(PBVH *pbvh, struct BMLog *log)
|
||||
|
@ -3223,7 +3526,7 @@ static void pbvh_bmesh_balance_tree(PBVH *pbvh)
|
|||
|
||||
if (bad) {
|
||||
modified = true;
|
||||
printf(" DELETE! %.4f %.4f %d\n", overlap, volume, BLI_array_len(stack));
|
||||
// printf(" DELETE! %.4f %.4f %d\n", overlap, volume, BLI_array_len(stack));
|
||||
|
||||
BLI_array_clear(substack);
|
||||
|
||||
|
@ -3524,23 +3827,23 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh, bool force_balance)
|
|||
pbvh_bmesh_balance_tree(pbvh);
|
||||
pbvh_bmesh_check_nodes(pbvh);
|
||||
pbvh->balance_counter = 0;
|
||||
}
|
||||
|
||||
totnode = pbvh->totnode;
|
||||
totnode = pbvh->totnode;
|
||||
|
||||
for (int i = 0; i < totnode; i++) {
|
||||
PBVHNode *n = pbvh->nodes + i;
|
||||
for (int i = 0; i < totnode; i++) {
|
||||
PBVHNode *n = pbvh->nodes + i;
|
||||
|
||||
if (totnode != pbvh->totnode) {
|
||||
if (totnode != pbvh->totnode) {
|
||||
#ifdef PROXY_ADVANCED
|
||||
BKE_pbvh_free_proxyarray(pbvh, n);
|
||||
BKE_pbvh_free_proxyarray(pbvh, n);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (n->flag & PBVH_Leaf) {
|
||||
/* Recursively split nodes that have gotten too many
|
||||
* elements */
|
||||
pbvh_bmesh_node_limit_ensure(pbvh, i);
|
||||
if (n->flag & PBVH_Leaf) {
|
||||
/* Recursively split nodes that have gotten too many
|
||||
* elements */
|
||||
pbvh_bmesh_node_limit_ensure(pbvh, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5218,7 +5521,8 @@ void pbvh_bmesh_cache_test(CacheParams *params, BMesh **r_bm, PBVH **r_pbvh_out)
|
|||
cd_face_node,
|
||||
cd_sculpt_vert,
|
||||
cd_face_area,
|
||||
false);
|
||||
false,
|
||||
true);
|
||||
|
||||
int loop_size = sizeof(BMLoop) - sizeof(void *) * 4;
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@ struct PBVHNode {
|
|||
int children_offset;
|
||||
int subtree_tottri;
|
||||
|
||||
int depth;
|
||||
|
||||
/* Pointer into the PBVH prim_indices array and the number of
|
||||
* primitives used by this leaf node.
|
||||
*
|
||||
|
|
|
@ -843,7 +843,6 @@ void BLI_mempool_as_array(BLI_mempool *pool,void *data)
|
|||
memcpy(p,elem,(size_t)esize);
|
||||
p = NODE_STEP_NEXT(p);
|
||||
}
|
||||
BLI_assert((int)(p - (char *)data) == pool->totused * esize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,7 +26,7 @@ TableGSet *BLI_table_gset_new_ex(const char *info, int size)
|
|||
TableGSet *ts = MEM_callocN(sizeof(TableGSet), info);
|
||||
|
||||
// ts->ptr_to_idx.buckets = (void *)BLI_ghash_ptr_new_ex(info, (uint)size);
|
||||
BLI_smallhash_init(&ts->ptr_to_idx);
|
||||
BLI_smallhash_init_ex(&ts->ptr_to_idx, size);
|
||||
|
||||
if (size) {
|
||||
ts->elems = MEM_callocN(sizeof(void *) * (uint)size, info);
|
||||
|
|
|
@ -292,7 +292,7 @@ typedef struct BMFlagLayer {
|
|||
|
||||
struct RangeTreeUInt;
|
||||
|
||||
//#define WITH_BM_ID_FREELIST
|
||||
#define WITH_BM_ID_FREELIST
|
||||
|
||||
typedef struct BMesh {
|
||||
int totvert, totedge, totloop, totface;
|
||||
|
@ -387,6 +387,11 @@ typedef struct BMesh {
|
|||
uint *freelist;
|
||||
int freelist_len, freelist_size;
|
||||
uint *free_ids, free_ids_size;
|
||||
|
||||
/* maps ids to their position within the freelist
|
||||
only used if freelist is bigger then a certain size,
|
||||
see FREELIST_HASHMAP_THRESHOLD_HIGH in bmesh_construct.c.*/
|
||||
struct SmallHash *free_idx_map;
|
||||
#else
|
||||
struct RangeTreeUInt *idtree;
|
||||
#endif
|
||||
|
|
|
@ -44,10 +44,46 @@
|
|||
#define SELECT 1
|
||||
|
||||
#ifdef WITH_BM_ID_FREELIST
|
||||
|
||||
/* if freelist is bigger then this, allocate free_idx_map */
|
||||
# define FREELIST_HASHMAP_THRESHOLD_HIGH 1024
|
||||
|
||||
/* if freelist is smaller then this, free free_idx_map*/
|
||||
# define FREELIST_HASHMAP_THRESHOLD_LOW 700
|
||||
|
||||
static void bm_id_freelist_check_hashmap(BMesh *bm)
|
||||
{
|
||||
if (!bm->idmap.free_idx_map && bm->idmap.freelist_len >= FREELIST_HASHMAP_THRESHOLD_HIGH) {
|
||||
printf("switching on freelist idx map");
|
||||
bm->idmap.free_idx_map = MEM_callocN(sizeof(SmallHash), "free_idx_map");
|
||||
BLI_smallhash_init_ex(bm->idmap.free_idx_map, bm->idmap.freelist_len);
|
||||
|
||||
for (int i = 0; i < bm->idmap.freelist_len; i++) {
|
||||
BLI_smallhash_insert(
|
||||
bm->idmap.free_idx_map, (uintptr_t)bm->idmap.freelist[i], POINTER_FROM_INT(i));
|
||||
}
|
||||
}
|
||||
else if (bm->idmap.free_idx_map && bm->idmap.freelist_len <= FREELIST_HASHMAP_THRESHOLD_LOW) {
|
||||
BLI_smallhash_release(bm->idmap.free_idx_map);
|
||||
MEM_freeN(bm->idmap.free_idx_map);
|
||||
|
||||
printf("switching off freelist idx map");
|
||||
}
|
||||
}
|
||||
|
||||
static uint bm_id_freelist_pop(BMesh *bm)
|
||||
{
|
||||
bm_id_freelist_check_hashmap(bm);
|
||||
|
||||
if (bm->idmap.freelist_len > 0) {
|
||||
return bm->idmap.freelist[--bm->idmap.freelist_len];
|
||||
int i = --bm->idmap.freelist_len;
|
||||
uint id = bm->idmap.freelist[i];
|
||||
|
||||
if (bm->idmap.free_idx_map) {
|
||||
BLI_smallhash_remove(bm->idmap.free_idx_map, (uintptr_t) id);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -78,15 +114,28 @@ void bm_id_freelist_take(BMesh *bm, uint id)
|
|||
return;
|
||||
}
|
||||
|
||||
BLI_BITMAP_ENABLE(bm->idmap.free_ids, id);
|
||||
BLI_BITMAP_DISABLE(bm->idmap.free_ids, id);
|
||||
|
||||
if (bm->idmap.free_idx_map) {
|
||||
void **val = BLI_smallhash_lookup_p(bm->idmap.free_idx_map, (uintptr_t)id);
|
||||
|
||||
if (val) {
|
||||
int i = POINTER_AS_INT(*val);
|
||||
|
||||
for (int i = 0; i < bm->idmap.freelist_len; i++) {
|
||||
if (bm->idmap.freelist[i] == id) {
|
||||
// swap with end
|
||||
bm->idmap.freelist[i] = bm->idmap.freelist[bm->idmap.freelist_len - 1];
|
||||
bm->idmap.freelist_len--;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < bm->idmap.freelist_len; i++) {
|
||||
if (bm->idmap.freelist[i] == id) {
|
||||
// swap with end
|
||||
bm->idmap.freelist[i] = bm->idmap.freelist[bm->idmap.freelist_len - 1];
|
||||
bm->idmap.freelist_len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool bm_id_freelist_has(BMesh *bm, uint id)
|
||||
|
@ -100,6 +149,7 @@ static bool bm_id_freelist_has(BMesh *bm, uint id)
|
|||
|
||||
void bm_id_freelist_push(BMesh *bm, uint id)
|
||||
{
|
||||
bm_id_freelist_check_hashmap(bm);
|
||||
bm_free_ids_check(bm, id);
|
||||
|
||||
bm->idmap.freelist_len++;
|
||||
|
@ -111,7 +161,6 @@ void bm_id_freelist_push(BMesh *bm, uint id)
|
|||
|
||||
if (bm->idmap.freelist) {
|
||||
newlist = MEM_reallocN(bm->idmap.freelist, size * sizeof(uint));
|
||||
memcpy((void *)newlist, (void *)bm->idmap.freelist, bm->idmap.freelist_size);
|
||||
}
|
||||
else {
|
||||
newlist = MEM_malloc_arrayN(size, sizeof(uint), "bm->idmap.freelist");
|
||||
|
@ -121,6 +170,14 @@ void bm_id_freelist_push(BMesh *bm, uint id)
|
|||
bm->idmap.freelist = newlist;
|
||||
}
|
||||
|
||||
if (bm->idmap.free_idx_map) {
|
||||
void **val;
|
||||
|
||||
if (!BLI_smallhash_ensure_p(bm->idmap.free_idx_map, (uintptr_t)id, &val)) {
|
||||
*val = POINTER_FROM_INT(bm->idmap.freelist_len - 1);
|
||||
}
|
||||
}
|
||||
|
||||
bm->idmap.freelist[bm->idmap.freelist_len - 1] = id;
|
||||
BLI_BITMAP_ENABLE(bm->idmap.free_ids, id);
|
||||
}
|
||||
|
@ -128,7 +185,7 @@ void bm_id_freelist_push(BMesh *bm, uint id)
|
|||
|
||||
// static const int _typemap[] = {0, 0, 1, 0, 2, 0, 0, 0, 3};
|
||||
|
||||
void bm_assign_id_intern(BMesh *bm, BMElem *elem, uint id)
|
||||
ATTR_NO_OPT void bm_assign_id_intern(BMesh *bm, BMElem *elem, uint id)
|
||||
{
|
||||
// CustomData *cdata = &bm->vdata + _typemap[elem->head.htype];
|
||||
// int cd_id_off = cdata->layers[cdata->typemap[CD_MESH_ID]].offset;
|
||||
|
|
|
@ -284,6 +284,14 @@ void BM_mesh_data_free(BMesh *bm)
|
|||
BLI_ghash_free(bm->idmap.ghash, NULL, NULL);
|
||||
}
|
||||
|
||||
#ifdef WITH_BM_ID_FREELIST
|
||||
if (bm->idmap.free_idx_map) {
|
||||
BLI_smallhash_release(bm->idmap.free_idx_map);
|
||||
MEM_freeN(bm->idmap.free_idx_map);
|
||||
bm->idmap.free_idx_map = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
const bool is_ldata_free = CustomData_bmesh_has_free(&bm->ldata);
|
||||
const bool is_pdata_free = CustomData_bmesh_has_free(&bm->pdata);
|
||||
|
||||
|
|
|
@ -846,7 +846,7 @@ void BM_mesh_bm_from_me(Object *ob,
|
|||
#ifdef WITH_BM_ID_FREELIST
|
||||
/*ensure correct id freelist*/
|
||||
if (bm->idmap.flag & BM_HAS_IDS) {
|
||||
bm_free_ids_check(bm, bm->idmap.max_id);
|
||||
bm_free_ids_check(bm, bm->idmap.maxid);
|
||||
|
||||
MEM_SAFE_FREE(bm->idmap.freelist);
|
||||
bm->idmap.freelist_len = 0;
|
||||
|
@ -874,8 +874,8 @@ void BM_mesh_bm_from_me(Object *ob,
|
|||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < max_id; i++) {
|
||||
if (!BLI_BITMAP_TEST(bm->idmap.free_ids, id)) {
|
||||
for (uint i = 0; i < bm->idmap.maxid; i++) {
|
||||
if (!BLI_BITMAP_TEST(bm->idmap.free_ids, i)) {
|
||||
bm_id_freelist_push(bm, i);
|
||||
}
|
||||
}
|
||||
|
@ -1072,13 +1072,11 @@ void BM_mesh_bm_to_me(
|
|||
ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_CORNER, ATTR_DOMAIN_FACE};
|
||||
CustomDataMergeState attr_states[4];
|
||||
|
||||
//undo mesh?
|
||||
// undo mesh?
|
||||
bool non_id_mesh = GS(me->id.name) != ID_ME;
|
||||
|
||||
for (int i = 0; !non_id_mesh && i < 4; i++) {
|
||||
BKE_mesh_attributes_update_pre(me,
|
||||
active_domains[i],
|
||||
attr_states+i);
|
||||
BKE_mesh_attributes_update_pre(me, active_domains[i], attr_states + i);
|
||||
}
|
||||
|
||||
/* Free custom data. */
|
||||
|
@ -1140,9 +1138,7 @@ void BM_mesh_bm_to_me(
|
|||
|
||||
for (int i = 0; !non_id_mesh && i < 4; i++) {
|
||||
CustomData *dst;
|
||||
BKE_mesh_attributes_update_post(me,
|
||||
active_domains[i],
|
||||
attr_states+i);
|
||||
BKE_mesh_attributes_update_post(me, active_domains[i], attr_states + i);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
|
|
@ -101,3 +101,5 @@ void bm_alloc_id(BMesh *bm, BMElem *elem);
|
|||
void bm_free_id(BMesh *bm, BMElem *elem);
|
||||
void bm_init_idmap_cdlayers(BMesh *bm);
|
||||
void bm_update_idmap_cdlayers(BMesh *bm);
|
||||
void bm_free_ids_check(BMesh *bm, uint id);
|
||||
void bm_id_freelist_push(BMesh *bm, uint id);
|
||||
|
|
|
@ -81,7 +81,7 @@ static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C,
|
|||
return rna_enum_attribute_domain_itemf(ob->data, r_free);
|
||||
}
|
||||
|
||||
ATTR_NO_OPT static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
|
||||
static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = ED_object_context(C);
|
||||
ID *id = ob->data;
|
||||
|
|
|
@ -1412,7 +1412,8 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
|
|||
sgcontext->ss->cd_face_node_offset,
|
||||
sgcontext->ss->cd_sculpt_vert,
|
||||
sgcontext->ss->cd_face_areas,
|
||||
sgcontext->ss->fast_draw);
|
||||
sgcontext->ss->fast_draw,
|
||||
true);
|
||||
}
|
||||
else { // save result to mesh
|
||||
Mesh *result = BKE_mesh_from_bmesh_nomain(bm,
|
||||
|
|
|
@ -416,9 +416,7 @@ bool SCULPT_has_colors(const SculptSession *ss)
|
|||
return ss->vcol_type != -1;
|
||||
}
|
||||
|
||||
ATTR_NO_OPT bool SCULPT_vertex_color_get(const SculptSession *ss,
|
||||
SculptVertRef vertex,
|
||||
float out[4])
|
||||
bool SCULPT_vertex_color_get(const SculptSession *ss, SculptVertRef vertex, float out[4])
|
||||
{
|
||||
if (vertex.i == SCULPT_REF_NONE) {
|
||||
return false;
|
||||
|
@ -565,9 +563,7 @@ ATTR_NO_OPT bool SCULPT_vertex_color_get(const SculptSession *ss,
|
|||
return false;
|
||||
}
|
||||
|
||||
ATTR_NO_OPT void SCULPT_vertex_color_set(const SculptSession *ss,
|
||||
SculptVertRef vertex,
|
||||
float color[4])
|
||||
void SCULPT_vertex_color_set(const SculptSession *ss, SculptVertRef vertex, float color[4])
|
||||
{
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES:
|
||||
|
@ -6565,11 +6561,6 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
|
|||
PBVHVertexIter vd;
|
||||
PBVHProxyNode *proxies;
|
||||
int proxy_count;
|
||||
float(*orco)[3] = NULL;
|
||||
|
||||
if (use_orco && !ss->bm) {
|
||||
orco = SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS)->co;
|
||||
}
|
||||
|
||||
BKE_pbvh_node_get_proxies(data->nodes[n], &proxies, &proxy_count);
|
||||
|
||||
|
@ -6580,10 +6571,10 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
|
|||
if (ss->bm) {
|
||||
float *co = BKE_PBVH_SCULPTVERT(ss->cd_sculpt_vert, vd.bm_vert)->origco;
|
||||
copy_v3_v3(val, co);
|
||||
// copy_v3_v3(val, BM_log_original_vert_co(ss->bm_log, vd.bm_vert));
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(val, orco[vd.i]);
|
||||
float *co = ss->mdyntopo_verts[vd.index].origco;
|
||||
copy_v3_v3(val, co);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -672,12 +672,12 @@ static void cloth_brush_add_bend_constraint(SculptSession *ss,
|
|||
}
|
||||
#endif
|
||||
|
||||
ATTR_NO_OPT static void cloth_brush_add_length_constraint(SculptSession *ss,
|
||||
SculptClothSimulation *cloth_sim,
|
||||
const int node_index,
|
||||
const int v1i,
|
||||
const int v2i,
|
||||
const bool use_persistent)
|
||||
static void cloth_brush_add_length_constraint(SculptSession *ss,
|
||||
SculptClothSimulation *cloth_sim,
|
||||
const int node_index,
|
||||
const int v1i,
|
||||
const int v2i,
|
||||
const bool use_persistent)
|
||||
{
|
||||
SculptClothLengthConstraint *length_constraint = cloth_add_constraint(cloth_sim, CON_LENGTH);
|
||||
SculptVertRef v1, v2;
|
||||
|
@ -766,10 +766,10 @@ static void cloth_brush_add_pin_constraint(SculptClothSimulation *cloth_sim,
|
|||
cloth_brush_reallocate_constraints(cloth_sim);
|
||||
}
|
||||
|
||||
ATTR_NO_OPT static void cloth_brush_add_deformation_constraint(SculptClothSimulation *cloth_sim,
|
||||
const int node_index,
|
||||
const int v,
|
||||
const float strength)
|
||||
static void cloth_brush_add_deformation_constraint(SculptClothSimulation *cloth_sim,
|
||||
const int node_index,
|
||||
const int v,
|
||||
const float strength)
|
||||
{
|
||||
SculptClothLengthConstraint *length_constraint = cloth_add_constraint(cloth_sim, CON_LENGTH);
|
||||
|
||||
|
@ -1669,10 +1669,10 @@ static void cloth_free_tasks(SculptClothSimulation *cloth_sim)
|
|||
cloth_sim->tot_constraint_tasks = 0;
|
||||
}
|
||||
|
||||
ATTR_NO_OPT static void cloth_sort_constraints_for_tasks(SculptSession *ss,
|
||||
Brush *brush,
|
||||
SculptClothSimulation *cloth_sim,
|
||||
int totthread)
|
||||
static void cloth_sort_constraints_for_tasks(SculptSession *ss,
|
||||
Brush *brush,
|
||||
SculptClothSimulation *cloth_sim,
|
||||
int totthread)
|
||||
{
|
||||
SculptClothTaskData *tasks = MEM_calloc_arrayN(
|
||||
totthread + 1, sizeof(SculptClothTaskData), "SculptClothTaskData");
|
||||
|
|
|
@ -902,22 +902,15 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
|
|||
e->head.hflag |= BM_ELEM_DRAW;
|
||||
}
|
||||
|
||||
BM_ITER_MESH (v, &iter, ss->bm, BM_VERTS_OF_MESH) {
|
||||
MSculptVert *mv = BKE_PBVH_SCULPTVERT(ss->cd_sculpt_vert, v);
|
||||
|
||||
mv->flag |= SCULPTVERT_NEED_DISK_SORT | SCULPTVERT_NEED_VALENCE;
|
||||
|
||||
BKE_pbvh_update_vert_boundary(ss->cd_sculpt_vert,
|
||||
ss->cd_faceset_offset,
|
||||
ss->cd_vert_node_offset,
|
||||
ss->cd_face_node_offset,
|
||||
-1,
|
||||
v,
|
||||
ss->boundary_symmetry);
|
||||
BKE_pbvh_bmesh_update_valence(ss->cd_sculpt_vert, (SculptVertRef){.i = (intptr_t)v});
|
||||
|
||||
i++;
|
||||
}
|
||||
BKE_pbvh_update_sculpt_verts(ss->bm,
|
||||
ss->cd_sculpt_vert,
|
||||
ss->cd_faceset_offset,
|
||||
ss->cd_vert_node_offset,
|
||||
ss->cd_face_node_offset,
|
||||
ss->boundary_symmetry,
|
||||
ss->vcol_type,
|
||||
ss->vcol_domain,
|
||||
ss->cd_vcol_offset);
|
||||
|
||||
/* Make sure the data for existing faces are initialized. */
|
||||
if (me->totpoly != ss->bm->totface) {
|
||||
|
|
|
@ -459,9 +459,9 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
|
|||
}
|
||||
}
|
||||
|
||||
ATTR_NO_OPT static void do_smear_brush_task_cb_exec(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
static void do_smear_brush_task_cb_exec(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
SculptThreadedTaskData *data = userdata;
|
||||
SculptSession *ss = data->ob->sculpt;
|
||||
|
@ -546,8 +546,9 @@ ATTR_NO_OPT static void do_smear_brush_task_cb_exec(void *__restrict userdata,
|
|||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
ATTR_NO_OPT static void do_smear_store_prev_colors_task_cb_exec(
|
||||
void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
SculptThreadedTaskData *data = userdata;
|
||||
SculptSession *ss = data->ob->sculpt;
|
||||
|
|
|
@ -799,9 +799,15 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode, bool is_
|
|||
SCULPT_dyntopo_node_layers_add(ss, ob);
|
||||
SCULPT_update_customdata_refs(ss, ob);
|
||||
|
||||
if (ss->pbvh && ss->bm) {
|
||||
SCULT_dyntopo_flag_all_disk_sort(ss);
|
||||
}
|
||||
BKE_pbvh_update_sculpt_verts(ss->bm,
|
||||
ss->cd_sculpt_vert,
|
||||
ss->cd_faceset_offset,
|
||||
ss->cd_vert_node_offset,
|
||||
ss->cd_face_node_offset,
|
||||
ss->boundary_symmetry,
|
||||
ss->vcol_type,
|
||||
ss->vcol_domain,
|
||||
ss->cd_vcol_offset);
|
||||
|
||||
if (!ss->bm_log) {
|
||||
/* Restore the BMLog using saved entries. */
|
||||
|
|
|
@ -1088,10 +1088,7 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid
|
|||
static int debug_pass = 0;
|
||||
bool pbvh_show_orig_co = false;
|
||||
|
||||
ATTR_NO_OPT static void gpu_bmesh_get_vcol(BMVert *v,
|
||||
BMLoop *l,
|
||||
const ColorRef *ref,
|
||||
float color[4])
|
||||
static void gpu_bmesh_get_vcol(BMVert *v, BMLoop *l, const ColorRef *ref, float color[4])
|
||||
{
|
||||
if (ref->domain == ATTR_DOMAIN_POINT) {
|
||||
switch (ref->type) {
|
||||
|
@ -1171,20 +1168,20 @@ ATTR_NO_OPT static void gpu_bmesh_get_vcol(BMVert *v,
|
|||
}
|
||||
|
||||
/* Output a BMVert into a VertexBufferFormat array at v_index. */
|
||||
ATTR_NO_OPT static void gpu_bmesh_vert_to_buffer_copy(BMesh *bm,
|
||||
BMVert *v,
|
||||
BMLoop *l,
|
||||
GPUVertBuf *vert_buf,
|
||||
int v_index,
|
||||
const float fno[3],
|
||||
const float *fmask,
|
||||
const int cd_vert_mask_offset,
|
||||
const int cd_vert_node_offset,
|
||||
const bool show_mask,
|
||||
const bool show_vcol,
|
||||
bool *empty_mask,
|
||||
const ColorRef *vcol_layers,
|
||||
const int totvcol)
|
||||
static void gpu_bmesh_vert_to_buffer_copy(BMesh *bm,
|
||||
BMVert *v,
|
||||
BMLoop *l,
|
||||
GPUVertBuf *vert_buf,
|
||||
int v_index,
|
||||
const float fno[3],
|
||||
const float *fmask,
|
||||
const int cd_vert_mask_offset,
|
||||
const int cd_vert_node_offset,
|
||||
const bool show_mask,
|
||||
const bool show_vcol,
|
||||
bool *empty_mask,
|
||||
const ColorRef *vcol_layers,
|
||||
const int totvcol)
|
||||
{
|
||||
/* Vertex should always be visible if it's used by a visible face. */
|
||||
BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN));
|
||||
|
@ -1390,14 +1387,14 @@ bool GPU_pbvh_need_full_render_get()
|
|||
return g_vbo_id.need_full_render;
|
||||
}
|
||||
|
||||
ATTR_NO_OPT void GPU_pbvh_update_attribute_names(CustomData *vdata,
|
||||
CustomData *ldata,
|
||||
bool need_full_render,
|
||||
bool fast_mode,
|
||||
int active_vcol_type,
|
||||
int active_vcol_domain,
|
||||
CustomDataLayer *active_vcol_layer,
|
||||
CustomDataLayer *render_vcol_layer)
|
||||
void GPU_pbvh_update_attribute_names(CustomData *vdata,
|
||||
CustomData *ldata,
|
||||
bool need_full_render,
|
||||
bool fast_mode,
|
||||
int active_vcol_type,
|
||||
int active_vcol_domain,
|
||||
CustomDataLayer *active_vcol_layer,
|
||||
CustomDataLayer *render_vcol_layer)
|
||||
{
|
||||
const bool active_only = !need_full_render;
|
||||
|
||||
|
@ -1537,14 +1534,14 @@ ATTR_NO_OPT void GPU_pbvh_update_attribute_names(CustomData *vdata,
|
|||
}
|
||||
}
|
||||
|
||||
ATTR_NO_OPT static void gpu_flat_vcol_make_vert(float co[3],
|
||||
BMVert *v,
|
||||
BMLoop *l,
|
||||
GPUVertBuf *vert_buf,
|
||||
int v_index,
|
||||
ColorRef vcol_refs[MAX_GPU_MCOL],
|
||||
int totoffsets,
|
||||
const float fno[3])
|
||||
static void gpu_flat_vcol_make_vert(float co[3],
|
||||
BMVert *v,
|
||||
BMLoop *l,
|
||||
GPUVertBuf *vert_buf,
|
||||
int v_index,
|
||||
ColorRef vcol_refs[MAX_GPU_MCOL],
|
||||
int totoffsets,
|
||||
const float fno[3])
|
||||
{
|
||||
for (int i = 0; i < totoffsets; i++) {
|
||||
float color[4];
|
||||
|
@ -1937,7 +1934,7 @@ static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers,
|
|||
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
|
||||
* shading, an element index buffer.
|
||||
* Threaded - do not call any functions that use OpenGL calls! */
|
||||
ATTR_NO_OPT void GPU_pbvh_bmesh_buffers_update(PBVHGPUBuildArgs *args)
|
||||
void GPU_pbvh_bmesh_buffers_update(PBVHGPUBuildArgs *args)
|
||||
{
|
||||
BMesh *bm = args->bm;
|
||||
GPU_PBVH_Buffers *buffers = args->buffers;
|
||||
|
|
|
@ -567,7 +567,13 @@ static void rna_AttributeGroup_active_color_index_range(
|
|||
|
||||
static void rna_AttributeGroup_update_active_color(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
rna_Attribute_update_data(bmain, scene, ptr);
|
||||
ID *id = ptr->owner_id;
|
||||
|
||||
/* cheating way for importers to avoid slow updates */
|
||||
if (id->us > 0) {
|
||||
// DEG_id_tag_update(id, 0);
|
||||
// WM_main_add_notifier(NC_GEOM | ND_DATA, id);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
|
|
Loading…
Reference in New Issue