From 979aa4e9904017144b049f90ff14a6cc928b437d Mon Sep 17 00:00:00 2001 From: Janne Karhu Date: Tue, 9 Mar 2010 03:01:18 +0000 Subject: [PATCH] Point cache optimization: only cache particles that are alive. This reduces point cache sizes dramatically especially if particle life time is small compared to total simulation length. For example with the settings: particle amount = 10000, start = 1, end = 200, life = 10, cache step = 1, the unoptimized blend file size (compressed) was a little over 22 Mb and with this optimization the file is a little under 2 Mb (again compressed). In addition to saving memory/disk space this also probably speeds up reading from cache, since there's less data to read. As an additional fix the memory cache size (displayed in cache panel) is now calculated correctly. --- source/blender/blenkernel/BKE_pointcache.h | 10 +- source/blender/blenkernel/intern/particle.c | 6 +- source/blender/blenkernel/intern/pointcache.c | 223 ++++++++++-------- 3 files changed, 138 insertions(+), 101 deletions(-) diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 10550ccdc05..0268f2faf31 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -118,7 +118,7 @@ typedef struct PTCacheID { unsigned int data_types, info_types; /* copies point data to cache data */ - int (*write_elem)(int index, void *calldata, void **data); + int (*write_elem)(int index, void *calldata, void **data, int cfra); /* copies point data to cache data */ int (*write_stream)(PTCacheFile *pf, void *calldata); /* copies cache cata to point data */ @@ -128,10 +128,10 @@ typedef struct PTCacheID { /* interpolated between previously read point data and cache data */ void (*interpolate_elem)(int index, void *calldata, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data); - /* total number of simulated points */ - int (*totpoint)(void *calldata); - /* number of points written for current cache frame (currently not used) */ - int (*totwrite)(void *calldata); + /* total number of simulated points (the cfra parameter is just for using same function pointer with totwrite) */ + int (*totpoint)(void *calldata, int cfra); + /* number of points written for current cache frame */ + int (*totwrite)(void *calldata, int cfra); int (*write_header)(PTCacheFile *pf); int (*read_header)(PTCacheFile *pf); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index b88df677c9b..97e8d6c7f7d 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -1067,12 +1067,12 @@ static void get_pointcache_keys_for_time(Object *ob, PointCache *cache, int inde while(pm && pm->next && (float)pm->frame < t) pm = pm->next; - BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] : index, pm->data, (float)pm->frame); - BKE_ptcache_make_particle_key(key1, pm->prev->index_array ? pm->prev->index_array[index] : index, pm->prev->data, (float)pm->prev->frame); + BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] - 1 : index, pm->data, (float)pm->frame); + BKE_ptcache_make_particle_key(key1, pm->prev->index_array ? pm->prev->index_array[index] - 1 : index, pm->prev->data, (float)pm->prev->frame); } else if(cache->mem_cache.first) { PTCacheMem *pm2 = cache->mem_cache.first; - BKE_ptcache_make_particle_key(key2, pm2->index_array ? pm2->index_array[index] : index, pm2->data, (float)pm2->frame); + BKE_ptcache_make_particle_key(key2, pm2->index_array ? pm2->index_array[index] - 1 : index, pm2->data, (float)pm2->frame); copy_particle_key(key1, key2, 1); } } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 7ae2898ab8d..9c393ad0ae1 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -135,7 +135,7 @@ static int ptcache_write_basic_header(PTCacheFile *pf) return 1; } /* Softbody functions */ -static int ptcache_write_softbody(int index, void *soft_v, void **data) +static int ptcache_write_softbody(int index, void *soft_v, void **data, int cfra) { SoftBody *soft= soft_v; BodyPoint *bp = soft->bpoint + index; @@ -191,13 +191,13 @@ static void ptcache_interpolate_softbody(int index, void *soft_v, void **data, f VECCOPY(bp->pos, keys->co); VECCOPY(bp->vec, keys->vel); } -static int ptcache_totpoint_softbody(void *soft_v) +static int ptcache_totpoint_softbody(void *soft_v, int cfra) { SoftBody *soft= soft_v; return soft->totpoint; } /* Particle functions */ -static int ptcache_write_particle(int index, void *psys_v, void **data) +static int ptcache_write_particle(int index, void *psys_v, void **data, int cfra) { ParticleSystem *psys= psys_v; ParticleData *pa = psys->particles + index; @@ -205,11 +205,9 @@ static int ptcache_write_particle(int index, void *psys_v, void **data) float times[3] = {pa->time, pa->dietime, pa->lifetime}; int step = psys->pointcache->step; - if(data[BPHYS_DATA_INDEX]) { - /* No need to store unborn or died particles */ - if(pa->time - step > pa->state.time || pa->dietime + step < pa->state.time) - return 0; - } + /* No need to store unborn or died particles outside cache step bounds */ + if(data[BPHYS_DATA_INDEX] && (cfra < pa->time - step || cfra > pa->dietime + step)) + return 0; PTCACHE_DATA_FROM(data, BPHYS_DATA_INDEX, &index); PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, pa->state.co); @@ -236,8 +234,14 @@ void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, flo static void ptcache_read_particle(int index, void *psys_v, void **data, float frs_sec, float cfra, float *old_data) { ParticleSystem *psys= psys_v; - ParticleData *pa = psys->particles + index; - BoidParticle *boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL; + ParticleData *pa; + BoidParticle *boid; + + if(index >= psys->totpart) + return; + + pa = psys->particles + index; + boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL; if(cfra > pa->state.time) memcpy(&pa->prev_state, &pa->state, sizeof(ParticleKey)); @@ -288,10 +292,19 @@ static void ptcache_read_particle(int index, void *psys_v, void **data, float fr static void ptcache_interpolate_particle(int index, void *psys_v, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data) { ParticleSystem *psys= psys_v; - ParticleData *pa = psys->particles + index; + ParticleData *pa; ParticleKey keys[4]; float dfra; + if(index >= psys->totpart) + return; + + pa = psys->particles + index; + + /* particle wasn't read from first cache so can't interpolate */ + if((int)cfra1 < pa->time - psys->pointcache->step || (int)cfra1 > pa->dietime + psys->pointcache->step) + return; + cfra = MIN2(cfra, pa->dietime); cfra1 = MIN2(cfra1, pa->dietime); cfra2 = MIN2(cfra2, pa->dietime); @@ -338,26 +351,20 @@ static void ptcache_interpolate_particle(int index, void *psys_v, void **data, f pa->state.time = cfra; } -static int ptcache_totpoint_particle(void *psys_v) +static int ptcache_totpoint_particle(void *psys_v, int cfra) { ParticleSystem *psys = psys_v; return psys->totpart; } -static int ptcache_totwrite_particle(void *psys_v) +static int ptcache_totwrite_particle(void *psys_v, int cfra) { ParticleSystem *psys = psys_v; + ParticleData *pa= psys->particles; + int p, step = psys->pointcache->step; int totwrite = 0; - /* TODO for later */ - //if((psys->part->flag & (PART_UNBORN|PART_DIED))==0) { - // ParticleData *pa= psys->particles; - // int p, step = psys->pointcache->step; - - // for(p=0; ptotpart; p++,pa++) - // totwrite += (pa->time - step > pa->state.time || pa->dietime + step > pa->state.time); - //} - //else - totwrite= psys->totpart; + for(p=0; ptotpart; p++,pa++) + totwrite += (cfra >= pa->time - step && cfra <= pa->dietime + step); return totwrite; } @@ -489,7 +496,7 @@ static int ptcache_totwrite_particle(void *psys_v) //} // /* Cloth functions */ -static int ptcache_write_cloth(int index, void *cloth_v, void **data) +static int ptcache_write_cloth(int index, void *cloth_v, void **data, int cfra) { ClothModifierData *clmd= cloth_v; Cloth *cloth= clmd->clothObject; @@ -554,7 +561,7 @@ static void ptcache_interpolate_cloth(int index, void *cloth_v, void **data, flo /* should vert->xconst be interpolated somehow too? - jahka */ } -static int ptcache_totpoint_cloth(void *cloth_v) +static int ptcache_totpoint_cloth(void *cloth_v, int cfra) { ClothModifierData *clmd= cloth_v; return clmd->clothObject->numverts; @@ -615,11 +622,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p pid->write_header= ptcache_write_basic_header; pid->read_header= ptcache_read_basic_header; - pid->data_types= (1<part->flag & (PART_UNBORN|PART_DIED))==0) - // pid->data_types|= (1<data_types= (1<part->phystype == PART_PHYS_BOIDS) pid->data_types|= (1<domain; @@ -648,7 +651,7 @@ static int ptcache_totpoint_smoke(void *smoke_v) } /* Smoke functions */ -static int ptcache_totpoint_smoke_turbulence(void *smoke_v) +static int ptcache_totpoint_smoke_turbulence(void *smoke_v, int cfra) { SmokeModifierData *smd= (SmokeModifierData *)smoke_v; SmokeDomainSettings *sds = smd->domain; @@ -1266,12 +1269,32 @@ static void ptcache_file_seek_pointers(int index, PTCacheFile *pf) int i, size=0; int data_types = pf->data_types; - for(i=0; idata_types & (1<fp, 8 + sizeof(int), SEEK_SET); + fread(&totpoint, sizeof(int), 1, pf->fp); + + totpoint++; + + fseek(pf->fp, 8 + sizeof(int), SEEK_SET); + fwrite(&totpoint, sizeof(int), 1, pf->fp); + + fseek(pf->fp, 0, SEEK_END); + } + else { + for(i=0; idata_types & (1<fp, 8 + 3*sizeof(int) + index * size, SEEK_SET); + } ptcache_file_init_pointers(pf); - /* size of default header + data up to index */ - fseek(pf->fp, 8 + 3*sizeof(int) + index * size, SEEK_SET); } void BKE_ptcache_mem_init_pointers(PTCacheMem *pm) { @@ -1291,13 +1314,24 @@ void BKE_ptcache_mem_incr_pointers(PTCacheMem *pm) pm->cur[i] = (char*)pm->cur[i] + ptcache_data_size[i]; } } -void BKE_ptcache_mem_seek_pointers(int index, PTCacheMem *pm) +static int BKE_ptcache_mem_seek_pointers(int point_index, PTCacheMem *pm) { int data_types = pm->data_types; - int i; + int i, index = pm->index_array ? pm->index_array[point_index] - 1 : point_index; + + if(index < 0) { + /* Can't give proper location without reallocation, so don't give any location. + * Some points will be cached improperly, but this only happens with simulation + * steps bigger than cache->step, so the cache has to be recalculated anyways + * at some point. + */ + return 0; + } for(i=0; icur[i] = data_types & (1<data[i] + index * ptcache_data_size[i] : NULL; + + return 1; } static void ptcache_alloc_data(PTCacheMem *pm) { @@ -1310,14 +1344,20 @@ static void ptcache_alloc_data(PTCacheMem *pm) pm->data[i] = MEM_callocN(totpoint * ptcache_data_size[i], "PTCache Data"); } } -static void ptcache_free_data(void *data[]) +static void ptcache_free_data(PTCacheMem *pm) { + void **data = pm->data; int i; for(i=0; iindex_array) { + MEM_freeN(pm->index_array); + pm->index_array = NULL; + } } static void ptcache_copy_data(void *from[], void *to[]) { @@ -1361,7 +1401,7 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) int ret = 0, error = 0; /* nothing to read to */ - if(pid->totpoint(pid->calldata) == 0) + if(pid->totpoint(pid->calldata, (int)cfra) == 0) return 0; if(pid->cache->flag & PTCACHE_READ_INFO) { @@ -1462,13 +1502,13 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) else if(pid->read_header(pf)) { ptcache_file_init_pointers(pf); totpoint = pf->totpoint; - index = pf->data_types & BPHYS_DATA_INDEX ? &pf->data.index : &i; + index = pf->data_types & (1<data.index : &i; } } else { /* fall back to old cache file format */ use_old = 1; - totpoint = pid->totpoint(pid->calldata); + totpoint = pid->totpoint(pid->calldata, (int) cfra); } } if(pf2) { @@ -1481,13 +1521,13 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) else if(pid->read_header(pf2)) { ptcache_file_init_pointers(pf2); totpoint2 = pf2->totpoint; - index2 = pf2->data_types & BPHYS_DATA_INDEX ? &pf2->data.index : &i; + index2 = pf2->data_types & (1<data.index : &i; } } else { /* fall back to old cache file format */ use_old = 1; - totpoint2 = pid->totpoint(pid->calldata); + totpoint2 = pid->totpoint(pid->calldata, (int) cfra); } } @@ -1500,7 +1540,7 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) if(!error) { if(pf && pid->read_stream) { - if(totpoint != pid->totpoint(pid->calldata)) + if(totpoint != pid->totpoint(pid->calldata, (int) cfra)) error = 1; else { @@ -1510,7 +1550,8 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) } } - totpoint = MIN2(totpoint, pid->totpoint(pid->calldata)); + if((pid->data_types & (1<totpoint(pid->calldata, (int) cfra)); if(!error) { @@ -1539,7 +1580,7 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) if(!error) { if(pf2 && pid->read_stream) { - if(totpoint2 != pid->totpoint(pid->calldata)) + if(totpoint2 != pid->totpoint(pid->calldata, (int) cfra)) error = 1; else { @@ -1549,7 +1590,8 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) } } - totpoint2 = MIN2(totpoint2, pid->totpoint(pid->calldata)); + if((pid->data_types & (1<totpoint(pid->calldata, (int) cfra)); if(!error) { @@ -1621,31 +1663,31 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) return (error ? 0 : ret); } /* TODO for later */ -//static void ptcache_make_index_array(PTCacheMem *pm, int totpoint) -//{ -// int i, *index; -// -// if(pm->index_array) { -// MEM_freeN(pm->index_array); -// pm->index_array = NULL; -// } -// -// if(!pm->data[BPHYS_DATA_INDEX]) -// return; -// -// pm->index_array = MEM_callocN(totpoint * sizeof(int), "PTCacheMem index_array"); -// index = pm->data[BPHYS_DATA_INDEX]; -// -// for(i=0; itotpoint; i++, index++) -// pm->index_array[*index] = i; -//} +static void ptcache_make_index_array(PTCacheMem *pm, int totpoint) +{ + int i, *index; + + if(pm->index_array) { + MEM_freeN(pm->index_array); + pm->index_array = NULL; + } + + if(!pm->data[BPHYS_DATA_INDEX]) + return; + + pm->index_array = MEM_callocN(totpoint * sizeof(int), "PTCacheMem index_array"); + index = pm->data[BPHYS_DATA_INDEX]; + + for(i=0; itotpoint; i++, index++) + pm->index_array[*index] = i + 1; +} /* writes cache to disk or memory */ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra) { PointCache *cache = pid->cache; PTCacheFile *pf= NULL, *pf2= NULL; int i; - int totpoint = pid->totpoint(pid->calldata); + int totpoint = pid->totpoint(pid->calldata, cfra); int add = 0, overwrite = 0; if(totpoint == 0 || cfra < 0 @@ -1690,7 +1732,7 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra) return 0; pf->type = pid->type; - pf->totpoint = cfra ? totpoint : pid->totwrite(pid->calldata); + pf->totpoint = cfra ? pid->totwrite(pid->calldata, cfra) : totpoint; pf->data_types = cfra ? pid->data_types : pid->info_types; if(!ptcache_file_write_header_begin(pf) || !pid->write_header(pf)) { @@ -1707,7 +1749,7 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra) else for(i=0; iwrite_elem) { - int write = pid->write_elem(i, pid->calldata, pf->cur); + int write = pid->write_elem(i, pid->calldata, pf->cur, cfra); if(write) { if(!ptcache_file_write_data(pf)) { ptcache_file_close(pf); @@ -1727,7 +1769,7 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra) pf2->data_types = pid->data_types; } ptcache_file_seek_pointers(i, pf2); - pid->write_elem(i, pid->calldata, pf2->cur); + pid->write_elem(i, pid->calldata, pf2->cur, cfra); if(!ptcache_file_write_data(pf2)) { ptcache_file_close(pf); ptcache_file_close(pf2); @@ -1773,7 +1815,7 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra) pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem"); - pm->totpoint = pid->totwrite(pid->calldata); + pm->totpoint = pid->totwrite(pid->calldata, cfra); pm->data_types = cfra ? pid->data_types : pid->info_types; ptcache_alloc_data(pm); @@ -1781,20 +1823,20 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra) for(i=0; iwrite_elem) { - int write = pid->write_elem(i, pid->calldata, pm->cur); + int write = pid->write_elem(i, pid->calldata, pm->cur, cfra); if(write) { BKE_ptcache_mem_incr_pointers(pm); /* newly born particles have to be copied to previous cached frame */ if(overwrite && write == 2) { pm2 = cache->mem_cache.last; - BKE_ptcache_mem_seek_pointers(i, pm2); - pid->write_elem(i, pid->calldata, pm2->cur); + if(BKE_ptcache_mem_seek_pointers(i, pm2)) + pid->write_elem(i, pid->calldata, pm2->cur, cfra); } } } } - //ptcache_make_index_array(pm, pid->totpoint(pid->calldata)); + ptcache_make_index_array(pm, pid->totpoint(pid->calldata, cfra)); pm->frame = cfra; BLI_addtail(&cache->mem_cache, pm); @@ -1899,15 +1941,15 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra) if(mode == PTCACHE_CLEAR_ALL) { pid->cache->last_exact = 0; for(; pm; pm=pm->next) - ptcache_free_data(pm->data); + ptcache_free_data(pm); BLI_freelistN(&pid->cache->mem_cache); } else { while(pm) { if((mode==PTCACHE_CLEAR_BEFORE && pm->frame < cfra) || (mode==PTCACHE_CLEAR_AFTER && pm->frame > cfra) ) { link = pm; + ptcache_free_data(pm); pm = pm->next; - ptcache_free_data(link->data); BLI_freelinkN(&pid->cache->mem_cache, link); } else @@ -1929,7 +1971,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra) for(; pm; pm=pm->next) { if(pm->frame == cfra) { - ptcache_free_data(pm->data); + ptcache_free_data(pm); BLI_freelinkN(&pid->cache->mem_cache, pm); break; } @@ -2214,11 +2256,8 @@ void BKE_ptcache_free_mem(ListBase *mem_cache) PTCacheMem *pm = mem_cache->first; if(pm) { - for(; pm; pm=pm->next) { - ptcache_free_data(pm->data); - if(pm->index_array) - MEM_freeN(pm->index_array); - } + for(; pm; pm=pm->next) + ptcache_free_data(pm); BLI_freelistN(mem_cache); } @@ -2587,7 +2626,7 @@ void BKE_ptcache_disk_to_mem(PTCacheID *pid) cache->flag |= PTCACHE_DISK_CACHE; - ptcache_free_data(pm->data); + ptcache_free_data(pm); MEM_freeN(pm); ptcache_file_close(pf); @@ -2597,7 +2636,7 @@ void BKE_ptcache_disk_to_mem(PTCacheID *pid) BKE_ptcache_mem_incr_pointers(pm); } - //ptcache_make_index_array(pm, pid->totpoint(pid->calldata)); + ptcache_make_index_array(pm, pid->totpoint(pid->calldata, cfra)); BLI_addtail(&pid->cache->mem_cache, pm); @@ -2813,16 +2852,14 @@ void BKE_ptcache_update_info(PTCacheID *pid) } else { PTCacheMem *pm = cache->mem_cache.first; - float framesize = 0.0f, bytes = 0.0f; - int mb; - - if(pm) - framesize = (float)ptcache_pid_old_elemsize(pid) * (float)pm->totpoint; + float bytes = 0.0f; + int i, mb; - for(; pm; pm=pm->next) + for(; pm; pm=pm->next) { + for(i=0; idata[i] ? MEM_allocN_len(pm->data[i]) : 0.0f; totframes++; - - bytes = totframes * framesize; + } mb = (bytes > 1024.0f * 1024.0f);