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:
Joseph Eagar 2021-11-13 01:13:47 -08:00
parent 35133f9a06
commit a72721a2ae
23 changed files with 652 additions and 262 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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.
*

View File

@ -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);
}
/**

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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 {

View File

@ -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");

View File

@ -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) {

View File

@ -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;

View File

@ -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. */

View File

@ -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;

View File

@ -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