Modifier: warn if the ocean simulation fails to allocate memory

While most modifies don't handle out of memory cases, ocean simulation
could attempt huge allocations: 2048 gb at the maximum resolution.

Resolves T83952.
This commit is contained in:
Jeroen Bakker 2021-08-04 09:18:21 +02:00 committed by Campbell Barton
parent 3b0fab6dfa
commit 218df99410
Notes: blender-bot 2023-02-14 06:17:14 +01:00
Referenced by commit d9a530c55e, Fix compile error without `WITH_OCEANSIM` enabled
Referenced by issue #83952, Crash to desktop with too high number in the ocean modifier resolution viewport value
3 changed files with 80 additions and 40 deletions

View File

@ -74,11 +74,13 @@ struct Ocean *BKE_ocean_add(void);
void BKE_ocean_free_data(struct Ocean *oc);
void BKE_ocean_free(struct Ocean *oc);
bool BKE_ocean_ensure(struct OceanModifierData *omd, const int resolution);
void BKE_ocean_init_from_modifier(struct Ocean *ocean,
bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
struct OceanModifierData const *omd,
const int resolution);
void BKE_ocean_init(struct Ocean *o,
bool BKE_ocean_is_valid(const struct Ocean *o);
bool BKE_ocean_init(struct Ocean *o,
int M,
int N,
float Lx,

View File

@ -650,6 +650,14 @@ static void ocean_compute_normal_z(TaskPool *__restrict pool, void *UNUSED(taskd
fftw_execute(o->_N_z_plan);
}
/**
* Return true if the ocean is valid and can be used.
*/
bool BKE_ocean_is_valid(const struct Ocean *o)
{
return o->_k != NULL;
}
void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount)
{
TaskPool *pool;
@ -769,7 +777,10 @@ bool BKE_ocean_ensure(struct OceanModifierData *omd, const int resolution)
return true;
}
void BKE_ocean_init_from_modifier(struct Ocean *ocean,
/**
* Return true if the ocean data is valid and can be used.
*/
bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
struct OceanModifierData const *omd,
const int resolution)
{
@ -783,31 +794,34 @@ void BKE_ocean_init_from_modifier(struct Ocean *ocean,
BKE_ocean_free_data(ocean);
BKE_ocean_init(ocean,
resolution * resolution,
resolution * resolution,
omd->spatial_size,
omd->spatial_size,
omd->wind_velocity,
omd->smallest_wave,
1.0,
omd->wave_direction,
omd->damp,
omd->wave_alignment,
omd->depth,
omd->time,
omd->spectrum,
omd->fetch_jonswap,
omd->sharpen_peak_jonswap,
do_heightfield,
do_chop,
do_spray,
do_normals,
do_jacobian,
omd->seed);
return BKE_ocean_init(ocean,
resolution * resolution,
resolution * resolution,
omd->spatial_size,
omd->spatial_size,
omd->wind_velocity,
omd->smallest_wave,
1.0,
omd->wave_direction,
omd->damp,
omd->wave_alignment,
omd->depth,
omd->time,
omd->spectrum,
omd->fetch_jonswap,
omd->sharpen_peak_jonswap,
do_heightfield,
do_chop,
do_spray,
do_normals,
do_jacobian,
omd->seed);
}
void BKE_ocean_init(struct Ocean *o,
/**
* Return true if the ocean data is valid and can be used.
*/
bool BKE_ocean_init(struct Ocean *o,
int M,
int N,
float Lx,
@ -830,7 +844,6 @@ void BKE_ocean_init(struct Ocean *o,
short do_jacobian,
int seed)
{
RNG *rng;
int i, j, ii;
BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
@ -858,18 +871,34 @@ void BKE_ocean_init(struct Ocean *o,
o->_fetch_jonswap = fetch_jonswap;
o->_sharpen_peak_jonswap = sharpen_peak_jonswap * 10.0f;
/* NOTE: most modifiers don't account for failure to allocate.
* In this case however a large resolution can easily perform large allocations that fail,
* support early exiting in this case. */
if ((o->_k = (float *)MEM_mallocN(sizeof(float) * (size_t)M * (1 + N / 2), "ocean_k")) &&
(o->_h0 = (fftw_complex *)MEM_mallocN(sizeof(fftw_complex) * (size_t)M * N, "ocean_h0")) &&
(o->_h0_minus = (fftw_complex *)MEM_mallocN(sizeof(fftw_complex) * (size_t)M * N,
"ocean_h0_minus")) &&
(o->_kx = (float *)MEM_mallocN(sizeof(float) * o->_M, "ocean_kx")) &&
(o->_kz = (float *)MEM_mallocN(sizeof(float) * o->_N, "ocean_kz"))) {
/* Success. */
}
else {
MEM_SAFE_FREE(o->_k);
MEM_SAFE_FREE(o->_h0);
MEM_SAFE_FREE(o->_h0_minus);
MEM_SAFE_FREE(o->_kx);
MEM_SAFE_FREE(o->_kz);
BLI_rw_mutex_unlock(&o->oceanmutex);
return false;
}
o->_do_disp_y = do_height_field;
o->_do_normals = do_normals;
o->_do_spray = do_spray;
o->_do_chop = do_chop;
o->_do_jacobian = do_jacobian;
o->_k = (float *)MEM_mallocN(M * (1 + N / 2) * sizeof(float), "ocean_k");
o->_h0 = (fftw_complex *)MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0");
o->_h0_minus = (fftw_complex *)MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0_minus");
o->_kx = (float *)MEM_mallocN(o->_M * sizeof(float), "ocean_kx");
o->_kz = (float *)MEM_mallocN(o->_N * sizeof(float), "ocean_kz");
/* make this robust in the face of erroneous usage */
if (o->_Lx == 0.0f) {
o->_Lx = 0.001f;
@ -902,11 +931,11 @@ void BKE_ocean_init(struct Ocean *o,
/* pre-calculate the k matrix */
for (i = 0; i < o->_M; i++) {
for (j = 0; j <= o->_N / 2; j++) {
o->_k[i * (1 + o->_N / 2) + j] = sqrt(o->_kx[i] * o->_kx[i] + o->_kz[j] * o->_kz[j]);
o->_k[(size_t)i * (1 + o->_N / 2) + j] = sqrt(o->_kx[i] * o->_kx[i] + o->_kz[j] * o->_kz[j]);
}
}
rng = BLI_rng_new(seed);
RNG *rng = BLI_rng_new(seed);
for (i = 0; i < o->_M; i++) {
for (j = 0; j < o->_N; j++) {
@ -1029,6 +1058,8 @@ void BKE_ocean_init(struct Ocean *o,
set_height_normalize_factor(o);
BLI_rng_free(rng);
return true;
}
void BKE_ocean_free_data(struct Ocean *oc)
@ -1700,10 +1731,11 @@ void BKE_ocean_bake(struct Ocean *UNUSED(o),
(void)update_cb;
}
void BKE_ocean_init_from_modifier(struct Ocean *UNUSED(ocean),
bool BKE_ocean_init_from_modifier(struct Ocean *UNUSED(ocean),
struct OceanModifierData const *UNUSED(omd),
int UNUSED(resolution))
{
return true;
}
#endif /* WITH_OCEANSIM */

View File

@ -95,8 +95,9 @@ static void initData(ModifierData *md)
BKE_modifier_path_init(omd->cachepath, sizeof(omd->cachepath), "cache_ocean");
omd->ocean = BKE_ocean_add();
BKE_ocean_init_from_modifier(omd->ocean, omd, omd->viewport_resolution);
simulate_ocean_modifier(omd);
if (BKE_ocean_init_from_modifier(omd->ocean, omd, omd->viewport_resolution)) {
simulate_ocean_modifier(omd);
}
#else /* WITH_OCEANSIM */
UNUSED_VARS(md);
#endif /* WITH_OCEANSIM */
@ -132,8 +133,9 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
tomd->oceancache = NULL;
tomd->ocean = BKE_ocean_add();
BKE_ocean_init_from_modifier(tomd->ocean, tomd, tomd->viewport_resolution);
simulate_ocean_modifier(tomd);
if (BKE_ocean_init_from_modifier(tomd->ocean, tomd, tomd->viewport_resolution)) {
simulate_ocean_modifier(tomd);
}
#else /* WITH_OCEANSIM */
/* unused */
(void)md;
@ -323,6 +325,10 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig, co
static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
OceanModifierData *omd = (OceanModifierData *)md;
if (omd->ocean && !BKE_ocean_is_valid(omd->ocean)) {
BKE_modifier_set_error(ctx->object, md, "Failed to allocate memory");
return mesh;
}
int cfra_scene = (int)DEG_get_ctime(ctx->depsgraph);
Object *ob = ctx->object;
bool allocated_ocean = false;