diff options
author | Janne Karhu <jhkarh@gmail.com> | 2010-03-09 06:01:18 +0300 |
---|---|---|
committer | Janne Karhu <jhkarh@gmail.com> | 2010-03-09 06:01:18 +0300 |
commit | 979aa4e9904017144b049f90ff14a6cc928b437d (patch) | |
tree | 10d0387a6e9a6d1252061bb7dcf055d63f3871c2 /source/blender/blenkernel/intern/pointcache.c | |
parent | 417c328874746d4c77f75eaf146da5414ee87958 (diff) |
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.
Diffstat (limited to 'source/blender/blenkernel/intern/pointcache.c')
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 223 |
1 files changed, 130 insertions, 93 deletions
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; p<psys->totpart; p++,pa++) - // totwrite += (pa->time - step > pa->state.time || pa->dietime + step > pa->state.time); - //} - //else - totwrite= psys->totpart; + for(p=0; p<psys->totpart; 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<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY); - - /* TODO for later */ - //if((psys->part->flag & (PART_UNBORN|PART_DIED))==0) - // pid->data_types|= (1<<BPHYS_DATA_INDEX); + pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY) | (1<<BPHYS_DATA_INDEX); if(psys->part->phystype == PART_PHYS_BOIDS) pid->data_types|= (1<<BPHYS_DATA_AVELOCITY) | (1<<BPHYS_DATA_ROTATION) | (1<<BPHYS_DATA_BOIDS); @@ -635,7 +638,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p } /* Smoke functions */ -static int ptcache_totpoint_smoke(void *smoke_v) +static int ptcache_totpoint_smoke(void *smoke_v, int cfra) { SmokeModifierData *smd= (SmokeModifierData *)smoke_v; SmokeDomainSettings *sds = smd->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; i<BPHYS_TOT_DATA; i++) - size += pf->data_types & (1<<i) ? ptcache_data_size[i] : 0; + if(data_types & (1<<BPHYS_DATA_INDEX)) { + int totpoint; + /* The simplest solution is to just write to the very end. This may cause + * some data duplication, but since it's on disk it's not so bad. The correct + * thing would be to search through the file for the correct index and only + * write to the end if it's not found, but this could be quite slow. + */ + fseek(pf->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; i<BPHYS_TOT_DATA; i++) + size += pf->data_types & (1<<i) ? ptcache_data_size[i] : 0; + + /* size of default header + data up to index */ + fseek(pf->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; i<BPHYS_TOT_DATA; i++) pm->cur[i] = data_types & (1<<i) ? (char*)pm->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; i<BPHYS_TOT_DATA; i++) { if(data[i]) MEM_freeN(data[i]); } + + if(pm->index_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<<BPHYS_DATA_INDEX) ? &pf->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<<BPHYS_DATA_INDEX) ? &pf2->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<<BPHYS_DATA_INDEX)) == 0) + totpoint = MIN2(totpoint, pid->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<<BPHYS_DATA_INDEX)) == 0) + totpoint2 = MIN2(totpoint2, pid->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; i<pm->totpoint; 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; i<pm->totpoint; 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; i<totpoint; i++) { if(pid->write_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; i<totpoint; i++) { if(pid->write_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; i<BPHYS_TOT_DATA; i++) + bytes += pm->data[i] ? MEM_allocN_len(pm->data[i]) : 0.0f; totframes++; - - bytes = totframes * framesize; + } mb = (bytes > 1024.0f * 1024.0f); |