commit before merge

This commit is contained in:
Joseph Eagar 2020-10-24 16:01:08 -07:00
parent f61d4b2e3a
commit 3ae8229843
8 changed files with 565 additions and 2 deletions

View File

@ -53,6 +53,77 @@ struct TaskParallelTLS;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
//#define PROXY_ADVANCED
// experimental performance test of "data-based programming" approach
#ifdef PROXY_ADVANCED
typedef struct ProxyKey {
int node;
int pindex;
} ProxyKey;
# define MAX_PROXY_NEIGHBORS 12
typedef struct ProxyVertArray {
float **ownerco;
short **ownerno;
float (*co)[3];
float (*fno)[3];
short (*no)[3];
float *mask, **ownermask;
int *index;
float **ownercolor, (*color)[4];
ProxyKey (*neighbors)[MAX_PROXY_NEIGHBORS];
int size;
int datamask;
GHash *indexmap;
} ProxyVertArray;
typedef enum {
PV_OWNERCO = 1,
PV_OWNERNO = 2,
PV_CO = 4,
PV_NO = 8,
PV_MASK = 16,
PV_OWNERMASK = 32,
PV_INDEX = 64,
PV_OWNERCOLOR = 128,
PV_COLOR = 256,
PV_NEIGHBORS = 512
} ProxyVertField;
typedef struct ProxyVertUpdateRec {
float *co, *no, *mask, *color;
int index, newindex;
} ProxyVertUpdateRec;
# define PBVH_PROXY_DEFAULT CO | INDEX | MASK
struct SculptSession;
void BKE_pbvh_ensure_proxyarrays(struct SculptSession *ss, PBVH *pbvh, int mask);
void BKE_pbvh_load_proxyarrays(PBVH *pbvh, PBVHNode **nodes, int totnode, int mask);
void BKE_pbvh_ensure_proxyarray(
struct SculptSession *ss,
struct PBVH *pbvh,
struct PBVHNode *node,
int mask,
struct GHash
*vert_node_map, // vert_node_map maps vertex SculptIdxs to PBVHNode indices; optional
bool check_indexmap,
bool force_update);
void BKE_pbvh_gather_proxyarray(PBVH *pbvh, PBVHNode **nodes, int totnode);
void BKE_pbvh_free_proxyarray(struct PBVH *pbvh, struct PBVHNode *node);
void BKE_pbvh_update_proxyvert(struct PBVH *pbvh, struct PBVHNode *node, ProxyVertUpdateRec *rec);
ProxyVertArray *BKE_pbvh_get_proxyarrays(struct PBVH *pbvh, struct PBVHNode *node);
#endif
typedef struct {
float (*co)[3];
} PBVHProxyNode;

View File

@ -3067,3 +3067,379 @@ void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide)
{
pbvh->respect_hide = respect_hide;
}
#ifdef PROXY_ADVANCED
// TODO: if this really works, make sure to pull the neighbor iterator out of sculpt.c and put it
// here
/* clang-format off */
# include "BKE_context.h"
# include "DNA_object_types.h"
# include "DNA_scene_types.h"
# include "../../editors/sculpt_paint/sculpt_intern.h"
/* clang-format on */
int checkalloc(void **data, int esize, int oldsize, int newsize, int emask, int umask)
{
if (!*data && (emask & umask)) {
*data = MEM_callocN(newsize * esize, "pbvh proxy vert arrays");
return emask;
}
// update channel if it already was allocated once, or is requested by umask
else if (newsize != oldsize && (*data || (emask & umask))) {
*data = MEM_reallocN(data, newsize * esize);
return emask;
}
return 0;
}
void BKE_pbvh_ensure_proxyarray_indexmap(PBVH *pbvh, PBVHNode *node, GHash *vert_node_map)
{
ProxyVertArray *p = &node->proxyverts;
int totvert = 0;
BKE_pbvh_node_num_verts(pbvh, node, &totvert, NULL);
bool update = !p->indexmap || p->size != totvert;
if (!update) {
return;
}
if (p->indexmap) {
BLI_ghash_free(p->indexmap, NULL, NULL);
}
GHash *gs = p->indexmap = BLI_ghash_ptr_new("BKE_pbvh_ensure_proxyarray_indexmap");
PBVHVertexIter vd;
int i = 0;
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
{
BLI_ghash_insert(gs, (void *)vd.index, (void *)i);
i++;
}
BKE_pbvh_vertex_iter_end;
}
bool pbvh_proxyarray_needs_update(PBVH *pbvh, PBVHNode *node, int mask)
{
ProxyVertArray *p = &node->proxyverts;
int totvert = 0;
BKE_pbvh_node_num_verts(pbvh, node, &totvert, NULL);
bool bad = p->size != totvert || !p->neighbors;
bad = bad || (p->datamask & mask) != mask;
bad = bad && totvert > 0;
return bad;
}
GHash *pbvh_build_vert_node_map(PBVH *pbvh, int mask)
{
GHash *vert_node_map = BLI_ghash_ptr_new("BKE_pbvh_ensure_proxyarrays");
for (int i = 0; i < pbvh->totnode; i++) {
PBVHVertexIter vd;
PBVHNode *node = pbvh->nodes + i;
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
{
BLI_ghash_insert(vert_node_map, (void *)vd.index, (void *)i);
}
BKE_pbvh_vertex_iter_end;
}
return vert_node_map;
}
void BKE_pbvh_ensure_proxyarrays(SculptSession *ss, PBVH *pbvh, int mask)
{
bool update = false;
for (int i = 0; i < pbvh->totnode; i++) {
if (pbvh_proxyarray_needs_update(pbvh, pbvh->nodes + i, mask)) {
update = true;
break;
}
}
if (!update) {
return;
}
GHash *vert_node_map = pbvh_build_vert_node_map(pbvh, mask);
for (int i = 0; i < pbvh->totnode; i++) {
BKE_pbvh_ensure_proxyarray_indexmap(pbvh, pbvh->nodes + i, vert_node_map);
}
for (int i = 0; i < pbvh->totnode; i++) {
BKE_pbvh_ensure_proxyarray(ss, pbvh, pbvh->nodes + i, mask, vert_node_map, false, false);
}
if (vert_node_map) {
BLI_ghash_free(vert_node_map, NULL, NULL);
}
}
void BKE_pbvh_ensure_proxyarray(SculptSession *ss,
PBVH *pbvh,
PBVHNode *node,
int mask,
GHash *vert_node_map,
bool check_indexmap,
bool force_update)
{
ProxyVertArray *p = &node->proxyverts;
if (check_indexmap) {
BKE_pbvh_ensure_proxyarray_indexmap(pbvh, node, vert_node_map);
}
GHash *gs = p->indexmap;
int totvert = 0;
BKE_pbvh_node_num_verts(pbvh, node, &totvert, NULL);
if (!totvert) {
return;
}
int updatemask = 0;
# define UPDATETEST(name, emask, esize) \
if (mask & emask) { \
updatemask |= checkalloc((void **)&p->name, esize, p->size, totvert, emask, mask); \
}
UPDATETEST(ownerco, PV_OWNERCO, sizeof(void *))
UPDATETEST(ownerno, PV_OWNERNO, sizeof(void *))
UPDATETEST(ownermask, PV_OWNERMASK, sizeof(void *))
UPDATETEST(ownercolor, PV_OWNERCOLOR, sizeof(void *))
UPDATETEST(co, PV_CO, sizeof(float) * 3)
UPDATETEST(no, PV_NO, sizeof(short) * 3)
UPDATETEST(fno, PV_NO, sizeof(float) * 3)
UPDATETEST(mask, PV_MASK, sizeof(float))
UPDATETEST(color, PV_COLOR, sizeof(float) * 4)
UPDATETEST(index, PV_INDEX, sizeof(int))
UPDATETEST(neighbors, PV_NEIGHBORS, sizeof(ProxyKey) * MAX_PROXY_NEIGHBORS)
p->size = totvert;
if (force_update) {
updatemask |= mask;
}
if (!updatemask) {
return;
}
p->datamask |= mask;
PBVHVertexIter vd;
int i = 0;
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
{
BLI_ghash_insert(gs, (void *)vd.index, (void *)i);
i++;
}
BKE_pbvh_vertex_iter_end;
i = 0;
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
{
if (updatemask & PV_OWNERCO) {
p->ownerco[i] = vd.co;
}
if (updatemask & PV_INDEX) {
p->index[i] = vd.index;
}
if (updatemask & PV_OWNERNO) {
p->ownerno[i] = vd.no;
}
if (updatemask & PV_NO) {
copy_v3_v3_short(p->no[i], vd.no);
normal_short_to_float_v3(p->fno[i], vd.no);
}
if (updatemask & PV_CO) {
copy_v3_v3(p->co[i], vd.co);
}
if (updatemask & PV_OWNERMASK) {
p->ownermask[i] = vd.mask;
}
if (updatemask & PV_MASK) {
p->mask[i] = vd.mask ? *vd.mask : 0.0f;
}
if (updatemask & PV_COLOR) {
if (vd.vcol) {
copy_v4_v4(p->color[i], vd.vcol->color);
}
}
if (updatemask & PV_NEIGHBORS) {
int j = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
if (j >= MAX_PROXY_NEIGHBORS - 1) {
break;
}
ProxyKey key;
int *pindex = (int *)BLI_ghash_lookup_p(gs, (void *)ni.index);
if (!pindex) {
if (vert_node_map) {
int *nindex = BLI_ghash_lookup_p(vert_node_map, (void *)ni.index);
if (!nindex) {
continue;
}
PBVHNode *node2 = pbvh->nodes + *nindex;
if (node2->proxyverts.indexmap) {
pindex = (int *)BLI_ghash_lookup_p(node2->proxyverts.indexmap, (void *)ni.index);
}
if (!pindex) {
continue;
}
key.node = (int)(node2 - pbvh->nodes);
key.pindex = *pindex;
}
else {
continue;
}
}
else {
key.node = (int)(node - pbvh->nodes);
key.pindex = *pindex;
}
p->neighbors[i][j++] = key;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
p->neighbors[i][j].node = -1;
}
i++;
}
BKE_pbvh_vertex_iter_end;
}
typedef struct GatherProxyThread {
PBVHNode **nodes;
PBVH *pbvh;
int mask;
} GatherProxyThread;
static void pbvh_load_proxyarray_exec(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
GatherProxyThread *data = (GatherProxyThread *)userdata;
PBVHNode *node = data->nodes[n];
PBVHVertexIter vd;
ProxyVertArray *p = &node->proxyverts;
int i = 0;
int mask = p->datamask;
BKE_pbvh_ensure_proxyarray(NULL, data->pbvh, node, data->mask, NULL, false, true);
}
void BKE_pbvh_load_proxyarrays(PBVH *pbvh, PBVHNode **nodes, int totnode, int mask)
{
GatherProxyThread data = {.nodes = nodes, .pbvh = pbvh, .mask = mask};
mask = mask & ~PV_NEIGHBORS; //don't update neighbors in threaded code?
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, pbvh_load_proxyarray_exec, &settings);
}
static void pbvh_gather_proxyarray_exec(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
GatherProxyThread *data = (GatherProxyThread *)userdata;
PBVHNode *node = data->nodes[n];
PBVHVertexIter vd;
ProxyVertArray *p = &node->proxyverts;
int i = 0;
int mask = p->datamask;
BKE_pbvh_vertex_iter_begin(data->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
if (mask & PV_CO) {
copy_v3_v3(vd.co, p->co[i]);
}
if (vd.mask && (mask & PV_MASK)) {
*vd.mask = p->mask[i];
}
i++;
}
BKE_pbvh_vertex_iter_end;
}
void BKE_pbvh_gather_proxyarray(PBVH *pbvh, PBVHNode **nodes, int totnode)
{
GatherProxyThread data = {.nodes = nodes, .pbvh = pbvh};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, pbvh_gather_proxyarray_exec, &settings);
}
void BKE_pbvh_free_proxyarray(PBVH *pbvh, PBVHNode *node)
{
ProxyVertArray *p = &node->proxyverts;
if (p->co)
MEM_freeN(p->co);
if (p->no)
MEM_freeN(p->no);
if (p->index)
MEM_freeN(p->index);
if (p->mask)
MEM_freeN(p->mask);
if (p->ownerco)
MEM_freeN(p->ownerco);
if (p->ownerno)
MEM_freeN(p->ownerno);
if (p->ownermask)
MEM_freeN(p->ownermask);
if (p->ownercolor)
MEM_freeN(p->ownercolor);
if (p->color)
MEM_freeN(p->color);
if (p->neighbors)
MEM_freeN(p->neighbors);
memset(p, 0, sizeof(*p));
}
void BKE_pbvh_update_proxyvert(PBVH *pbvh, PBVHNode *node, ProxyVertUpdateRec *rec)
{
}
ProxyVertArray *BKE_pbvh_get_proxyarrays(PBVH *pbvh, PBVHNode *node)
{
return &node->proxyverts;
}
#endif

View File

@ -107,6 +107,9 @@ struct PBVHNode {
/* Used to store the brush color during a stroke and composite it over the original color */
PBVHColorBufferNode color_buffer;
#ifdef PROXY_ADVANCED
ProxyVertArray proxyverts;
#endif
};
typedef enum {

View File

@ -346,7 +346,7 @@ void MESH_OT_paint_mask_extract(wmOperatorType *ot)
ot->invoke = paint_mask_extract_invoke;
ot->exec = paint_mask_extract_exec;
ot->flag = OPTYPE_REGISTER;
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
RNA_def_float(
ot->srna,

View File

@ -58,7 +58,12 @@
#include "RNA_define.h"
#include "bmesh.h"
#ifdef PROXY_ADVANCED
/* clang-format off */
#include "BKE_DerivedMesh.h"
#include "../../blenkernel/intern/pbvh_intern.h"
/* clang-format on */
#endif
#include <math.h>
#include <stdlib.h>
@ -289,6 +294,79 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
BLI_task_parallel_range(0, totnode, &data, do_enhance_details_brush_task_cb_ex, &settings);
}
#ifdef PROXY_ADVANCED
static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
const Brush *brush = data->brush;
const bool smooth_mask = data->smooth_mask;
float bstrength = data->strength;
PBVHVertexIter vd;
CLAMP(bstrength, 0.0f, 1.0f);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
PBVHNode **nodes = data->nodes;
ProxyVertArray *p = &nodes[n]->proxyverts;
for (int i = 0; i < p->size; i++) {
float co[3] = {0.0f, 0.0f, 0.0f};
int ni = 0;
# if 1
if (sculpt_brush_test_sq_fn(&test, p->co[i])) {
const float fade = bstrength * SCULPT_brush_strength_factor(
ss,
brush,
p->co[i],
sqrtf(test.dist),
p->no[i],
p->fno[i],
smooth_mask ? 0.0f : (p->mask ? p->mask[i] : 0.0f),
p->index[i],
thread_id);
# else
if (1) {
const float fade = 1.0;
# endif
while (ni < MAX_PROXY_NEIGHBORS && p->neighbors[i][ni].node >= 0) {
ProxyKey *key = p->neighbors[i] + ni;
PBVHNode *n2 = ss->pbvh->nodes + key->node;
// printf("%d %d %d %p\n", key->node, key->pindex, ss->pbvh->totnode, n2);
add_v3_v3(co, n2->proxyverts.co[key->pindex]);
ni++;
}
// printf("ni %d\n", ni);
if (ni > 2) {
mul_v3_fl(co, 1.0f / (float)ni);
}
else {
copy_v3_v3(co, p->co[i]);
}
// printf("%f %f %f ", co[0], co[1], co[2]);
interp_v3_v3v3(p->co[i], p->co[i], co, fade);
}
}
}
#else
static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@ -343,6 +421,7 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
}
BKE_pbvh_vertex_iter_end;
}
#endif
void SCULPT_smooth(Sculpt *sd,
Object *ob,
@ -373,6 +452,12 @@ void SCULPT_smooth(Sculpt *sd,
SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_info_ensure(ob);
#ifdef PROXY_ADVANCED
int datamask = PV_CO | PV_NEIGHBORS | PV_NO | PV_INDEX | PV_MASK;
BKE_pbvh_ensure_proxyarrays(ss, ss->pbvh, datamask);
BKE_pbvh_load_proxyarrays(ss->pbvh, nodes, totnode, PV_CO | PV_NO | PV_MASK);
#endif
for (iteration = 0; iteration <= count; iteration++) {
const float strength = (iteration != count) ? 1.0f : last;
@ -388,6 +473,10 @@ void SCULPT_smooth(Sculpt *sd,
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_task_cb_ex, &settings);
#ifdef PROXY_ADVANCED
BKE_pbvh_gather_proxyarray(ss->pbvh, nodes, totnode);
#endif
}
}

View File

@ -1878,6 +1878,7 @@ typedef struct UVWarpModifierData {
/* UVWarp modifier flags */
enum {
MOD_UVWARP_INVERT_VGROUP = 1 << 0,
MOD_UVWARP_RESTRICT_ISLANDS = 1<<1
};
/* cache modifier */

View File

@ -4993,6 +4993,13 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "restrict_to_islands", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_UVWARP_RESTRICT_ISLANDS);
RNA_def_property_ui_text(prop,
"Island Restrict",
"Don't affect UVs in faces outside of the vertex group's influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
RNA_def_property_ui_text(prop, "UV Layer", "UV Layer name");

View File

@ -100,6 +100,7 @@ typedef struct UVWarpData {
MDeformVert *dvert;
int defgrp_index;
bool restrict_island;
float (*warp_mat)[4];
bool invert_vgroup;
@ -123,6 +124,19 @@ static void uv_warp_compute(void *__restrict userdata,
int l;
if (dvert) {
if (data->restrict_island) {
for (l = 0; l < mp->totloop; l++, ml++) {
const float weight = data->invert_vgroup ?
1.0f - BKE_defvert_find_weight(&dvert[ml->v], defgrp_index) :
BKE_defvert_find_weight(&dvert[ml->v], defgrp_index);
if (weight == 0.0f) {
return;
}
}
ml = &data->mloop[mp->loopstart];
}
for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
float uv[2];
const float weight = data->invert_vgroup ?
@ -221,6 +235,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
UVWarpData data = {
.mpoly = mpoly,
.restrict_island = umd->flag & MOD_UVWARP_RESTRICT_ISLANDS,
.mloop = mloop,
.mloopuv = mloopuv,
.dvert = dvert,
@ -299,6 +314,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
}
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
uiItemR(layout, ptr, "restrict_to_islands", 0, NULL, ICON_NONE);
modifier_panel_end(layout, ptr);
}