Sculpt-dev: fix crash related to curve

cache

* Fixed a few bugs in the curvemapping
  cache code.
* Fixed bug in how BKE_channelset_compat_load
  was copying brush.curve to/from the falloff_curve
  brush channel.
This commit is contained in:
Joseph Eagar 2022-01-11 23:26:56 -08:00
parent bfd1dc3a75
commit 15cb3130c3
6 changed files with 68 additions and 23 deletions

View File

@ -129,7 +129,11 @@ void BKE_brush_channel_system_exit()
bool BKE_brush_mapping_ensure_write(BrushMapping *mp)
{
if (IS_CACHE_CURVE(mp->curve)) {
mp->curve = BKE_curvemapping_copy(mp->curve);
CurveMapping *newcurve = BKE_curvemapping_copy(mp->curve);
RELEASE_CACHE_CURVE(mp->curve);
mp->curve = newcurve;
return true;
}
@ -391,6 +395,7 @@ void BKE_brush_channel_copy_data(BrushChannel *dst,
}
else if (dst->curve.curve) {
BKE_curvemapping_free(dst->curve.curve);
dst->curve.curve = NULL;
}
}
@ -1090,6 +1095,9 @@ double BKE_brush_channel_eval_mappings(BrushChannel *ch,
inputf = 1.0f - inputf;
}
/* ensure curve tables exist */
BKE_curvemapping_init(mp->curve);
double f2 = (float)BKE_curvemapping_evaluateF(mp->curve, 0, inputf);
f2 = mp->min + (mp->max - mp->min) * f2;
@ -1182,7 +1190,9 @@ bool BKE_brush_mapping_is_enabled(BrushChannel *child, BrushChannel *parent, int
}
}
void BKE_brush_channel_apply_mapping_flags(BrushChannel *dst, BrushChannel *child, BrushChannel *parent)
void BKE_brush_channel_apply_mapping_flags(BrushChannel *dst,
BrushChannel *child,
BrushChannel *parent)
{
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
BrushMapping *mp = dst->mappings + i;
@ -2034,7 +2044,7 @@ void BKE_brush_channelset_read(BlendDataReader *reader, BrushChannelSet *chset)
BKE_curvemapping_init(curve);
}
ch->mappings[i].curve = GET_CACHE_CURVE(curve); // frees curve, returns new one
mp->curve = GET_CACHE_CURVE(curve); // frees curve, returns new one
// paranoia check to make sure BrushMapping.type is correct
mp->type = i;
@ -2065,7 +2075,10 @@ void BKE_brush_channelset_write(BlendWriter *writer, BrushChannelSet *chset)
}
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
/* instantiate cached curves to ensure they get written
(and susequently read) seperately. */
BKE_brush_mapping_ensure_write(ch->mappings + i);
BKE_curvemapping_blend_write(writer, ch->mappings[i].curve);
}
}

View File

@ -33,6 +33,7 @@
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_curvemapping_cache.h"
#include "BKE_node.h"
#include "BKE_paint.h"
@ -266,7 +267,7 @@ static bool check_builtin_init()
SUBTYPE_SET(smooth_stroke_radius, BRUSH_CHANNEL_PIXEL);
SUBTYPE_SET(normal_mask_limit, BRUSH_CHANNEL_ANGLE);
SUBTYPE_SET(view_normal_mask_limit, BRUSH_CHANNEL_ANGLE);
SUBTYPE_SET(jitter_absolute, BRUSH_CHANNEL_PIXEL);
SUBTYPE_SET(radius, BRUSH_CHANNEL_PIXEL);
@ -304,7 +305,7 @@ static bool check_builtin_init()
mdef->blendmode = MA_RAMP_ADD;
}
//SETCAT(enhance_detail_presteps, "Enhancement");
// SETCAT(enhance_detail_presteps, "Enhancement");
SETCAT(concave_mask_factor, "Automasking");
SETCAT(automasking, "Automasking");
SETCAT(automasking_boundary_edges_propagation_steps, "Automasking");
@ -972,16 +973,32 @@ void BKE_brush_channelset_compat_load(BrushChannelSet *chset, Brush *brush, bool
}
}
#if 1
if (brush_to_channels) {
BrushChannel *ch = BRUSHSET_LOOKUP(chset, falloff_curve);
if (ch) {
ch->curve.preset = brush->curve_preset;
BKE_brush_channel_curve_ensure_write(&ch->curve);
if (brush->curve && brush->curve_preset == BRUSH_CURVE_CUSTOM) {
BKE_curvemapping_free_data(ch->curve.curve);
BKE_curvemapping_copy_data(ch->curve.curve, brush->curve);
if (brush->curve_preset == BRUSH_CURVE_CUSTOM) {
BKE_curvemapping_cache_release_or_free(brush_curve_cache, ch->curve.curve);
if (brush->curve) {
ch->curve.curve = BKE_curvemapping_copy(brush->curve);
}
else {
printf("%s: missing curve in brush\n", __func__);
ch->curve.curve = MEM_callocN(sizeof(CurveMapping), "CurveMapping");
BKE_curvemapping_set_defaults(ch->curve.curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemap_reset(ch->curve.curve->cm,
&(struct rctf){.xmin = 0, .ymin = 0.0, .xmax = 1.0, .ymax = 1.0},
CURVE_PRESET_LINE,
1);
}
BKE_curvemapping_init(ch->curve.curve);
}
}
}
@ -991,12 +1008,14 @@ void BKE_brush_channelset_compat_load(BrushChannelSet *chset, Brush *brush, bool
if (ch) {
brush->curve_preset = ch->curve.preset;
if (ch->curve.curve && ch->curve.preset == BRUSH_CURVE_CUSTOM) {
BKE_curvemapping_free_data(brush->curve);
BKE_curvemapping_copy_data(brush->curve, ch->curve.curve);
if (ch->curve.preset == BRUSH_CURVE_CUSTOM) {
BKE_curvemapping_cache_release_or_free(brush_curve_cache, brush->curve);
brush->curve = BKE_curvemapping_copy(ch->curve.curve);
BKE_curvemapping_init(brush->curve);
}
}
}
#endif
}
/* todo: move into BKE_brush_reset_mapping*/

View File

@ -120,6 +120,7 @@ void BKE_curvemapping_free(CurveMapping *cumap)
{
if (cumap) {
BKE_curvemapping_free_data(cumap);
cumap->flag |= CUMA_IS_FREED;
MEM_freeN(cumap);
}
}
@ -194,6 +195,7 @@ CurveMapping *BKE_curvemapping_copy(const CurveMapping *cumap)
CurveMapping *cumapn = MEM_dupallocN(cumap);
BKE_curvemapping_copy_data(cumapn, cumap);
cumapn->flag &= ~CUMA_PART_OF_CACHE;
cumapn->cache_users = 0;
return cumapn;
}
return NULL;

View File

@ -182,13 +182,17 @@ CurveMappingCache *BKE_curvemapping_cache_create()
void BKE_curvemapping_cache_aquire(CurveMappingCache *cache, CurveMapping *curve)
{
curve->cache_users++;
// printf("%s: %d flag: %d\n", __func__, curve->cache_users, curve->flag);
}
void BKE_curvemapping_cache_release(CurveMappingCache *cache, CurveMapping *curve)
{
curve->cache_users--;
if ((curve->flag & CUMA_PART_OF_CACHE) && curve->cache_users < 0) {
//printf("%s: %d flag: %d\n", __func__, curve->cache_users, curve->flag);
if ((curve->flag & CUMA_PART_OF_CACHE) && curve->cache_users <= 0) {
if (!BLI_ghash_remove(cache->gh, curve, NULL, NULL)) {
printf("error, curve was not in cache! %p\n", curve);
}
@ -272,6 +276,10 @@ void BKE_curvemapping_cache_exit()
// releases a curve if it's in the cache, otherwise frees it
void BKE_curvemapping_cache_release_or_free(CurveMappingCache *cache, CurveMapping *curve)
{
if (!curve) {
return;
}
if (curve->flag & CUMA_PART_OF_CACHE) {
BKE_curvemapping_cache_release(cache, curve);
}

View File

@ -5050,7 +5050,7 @@ static void sculpt_topology_update(Sculpt *sd,
BMVert *v = (BMVert *)BM_ELEM_FROM_ID_SAFE(ss->bm, actv);
if (v && v->head.htype == BM_VERT) {
ss->active_vertex_index.i == (intptr_t)v;
ss->active_vertex_index.i = (intptr_t)v;
}
else {
ss->active_vertex_index.i = SCULPT_REF_NONE;
@ -5061,7 +5061,7 @@ static void sculpt_topology_update(Sculpt *sd,
BMFace *f = (BMFace *)BM_ELEM_FROM_ID_SAFE(ss->bm, actf);
if (f && f->head.htype == BM_FACE) {
ss->active_face_index.i == (intptr_t)f;
ss->active_face_index.i = (intptr_t)f;
}
else {
ss->active_face_index.i = SCULPT_REF_NONE;
@ -5847,14 +5847,11 @@ static void SCULPT_run_command(
*brush2 = *brush;
BrushChannel *ch = BRUSHSET_LOOKUP(cmd->params_final, falloff_curve);
if (ch) {
brush2->curve_preset = ch->curve.preset;
brush2->curve = ch->curve.curve;
}
/* prevent auto freeing of brush2->curve in BKE_brush_channelset_compat_load */
brush2->curve = NULL;
// Load parameters into brush2 for compatibility with old code
// Make sure to remove all pen pressure/tilt old code
/* Load parameters into brush2 for compatibility with old code
Make sure to remove all old code for pen pressure/tilt */
BKE_brush_channelset_compat_load(cmd->params_mapped, brush2, false);
ss->cache->use_plane_trim = BRUSHSET_GET_INT(cmd->params_mapped, use_plane_trim, NULL);
@ -6154,6 +6151,9 @@ static void SCULPT_run_commandlist(
Brush brush2 = *brush;
brush2.sculpt_tool = cmd->tool;
/* prevent auto freeing of brush2->curve in BKE_brush_channelset_compat_load */
brush2.curve = NULL;
// Load parameters into brush2 for compatibility with old code
BKE_brush_channelset_compat_load(cmd->params_final, &brush2, false);
@ -6863,6 +6863,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Relax";
case SCULPT_TOOL_ENHANCE_DETAILS:
return "Enhance Details";
case SCULPT_TOOL_DISPLACEMENT_HEAL:
return "Multires Heal";
}
return "Sculpting";

View File

@ -105,7 +105,8 @@ typedef enum eCurveMappingFlags {
/** The curve is extended by extrapolation. When not set the curve is extended horizontally. */
CUMA_EXTEND_EXTRAPOLATE = (1 << 4),
CUMA_PART_OF_CACHE = (1 << 5)
CUMA_PART_OF_CACHE = (1 << 5),
CUMA_IS_FREED = (1 << 6)
} eCurveMappingFlags;
/** #CurveMapping.preset */