Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <jeroen@blender.org>2021-08-04 10:18:21 +0300
committerCampbell Barton <ideasman42@gmail.com>2021-08-04 11:29:43 +0300
commit218df9941097bf973485ac343c070bdc6641a539 (patch)
treef831265bc737b30a811385b46911eef01b40b4c4
parent3b0fab6dfaa00a6fd476d28c160fcd9219f9a973 (diff)
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.
-rw-r--r--source/blender/blenkernel/BKE_ocean.h6
-rw-r--r--source/blender/blenkernel/intern/ocean.c104
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c14
3 files changed, 82 insertions, 42 deletions
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index 2c0c6989acf..380f9045520 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -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,
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 3aee5cd639d..30e9213cdae 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -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);
-}
-
-void BKE_ocean_init(struct Ocean *o,
+ 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);
+}
+
+/**
+ * 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 */
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 8f3206da5be..1c502b94bdb 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -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;