Fixed: Showing pointcached frames in the timeline was terribly slow when using disk cache.

* The existence of cached frames was checked each frame causing hundreds of disk operations per frame update.
* Pointcache now keeps an updated array of the cached frames for fast "frame exists in cache" queries.
* This fix also speeds up some other pointcache operations nicely.
This commit is contained in:
Janne Karhu 2010-09-27 09:58:37 +00:00
parent 03c65a0c01
commit afa4b855ca
4 changed files with 106 additions and 4 deletions

@ -1876,6 +1876,9 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra)
else else
cache->flag |= PTCACHE_FRAMES_SKIPPED; cache->flag |= PTCACHE_FRAMES_SKIPPED;
} }
if(cache->cached_frames)
cache->cached_frames[cfra] = 1;
if(pf) ptcache_file_close(pf); if(pf) ptcache_file_close(pf);
@ -1893,6 +1896,9 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra)
void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra) void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra)
{ {
int len; /* store the length of the string */ int len; /* store the length of the string */
int i;
int sta = pid->cache->startframe;
int end = pid->cache->endframe;
/* mode is same as fopen's modes */ /* mode is same as fopen's modes */
DIR *dir; DIR *dir;
@ -1936,6 +1942,8 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra)
pid->cache->last_exact = MIN2(pid->cache->startframe, 0); pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
BLI_join_dirfile(path_full, path, de->d_name); BLI_join_dirfile(path_full, path, de->d_name);
BLI_delete(path_full, 0, 0); BLI_delete(path_full, 0, 0);
if(pid->cache->cached_frames) for(i=0; i<end-sta+1; i++)
pid->cache->cached_frames[i] = 0;
} else { } else {
/* read the number of the file */ /* read the number of the file */
int frame, len2 = (int)strlen(de->d_name); int frame, len2 = (int)strlen(de->d_name);
@ -1950,6 +1958,8 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra)
BLI_join_dirfile(path_full, path, de->d_name); BLI_join_dirfile(path_full, path, de->d_name);
BLI_delete(path_full, 0, 0); BLI_delete(path_full, 0, 0);
if(frame >=sta && frame <= end)
pid->cache->cached_frames[frame-sta] = 0;
} }
} }
} }
@ -1970,11 +1980,16 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra)
for(; pm; pm=pm->next) for(; pm; pm=pm->next)
ptcache_free_data(pm); ptcache_free_data(pm);
BLI_freelistN(&pid->cache->mem_cache); BLI_freelistN(&pid->cache->mem_cache);
if(pid->cache->cached_frames) for(i=0; i<end-sta+1; i++)
pid->cache->cached_frames[i] = 0;
} else { } else {
while(pm) { while(pm) {
if((mode==PTCACHE_CLEAR_BEFORE && pm->frame < cfra) || if((mode==PTCACHE_CLEAR_BEFORE && pm->frame < cfra) ||
(mode==PTCACHE_CLEAR_AFTER && pm->frame > cfra) ) { (mode==PTCACHE_CLEAR_AFTER && pm->frame > cfra) ) {
link = pm; link = pm;
if(pm->frame >=sta && pm->frame <= end)
pid->cache->cached_frames[pm->frame-sta] = 0;
ptcache_free_data(pm); ptcache_free_data(pm);
pm = pm->next; pm = pm->next;
BLI_freelinkN(&pid->cache->mem_cache, link); BLI_freelinkN(&pid->cache->mem_cache, link);
@ -2004,6 +2019,8 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra)
} }
} }
} }
if(pid->cache->cached_frames && cfra>=sta && cfra<=end)
pid->cache->cached_frames[cfra-sta] = 0;
break; break;
} }
@ -2014,6 +2031,12 @@ int BKE_ptcache_id_exist(PTCacheID *pid, int cfra)
{ {
if(!pid->cache) if(!pid->cache)
return 0; return 0;
if(cfra<pid->cache->startframe || cfra > pid->cache->endframe)
return 0;
if(pid->cache->cached_frames && pid->cache->cached_frames[cfra-pid->cache->startframe]==0)
return 0;
if(pid->cache->flag & PTCACHE_DISK_CACHE) { if(pid->cache->flag & PTCACHE_DISK_CACHE) {
char filename[MAX_PTCACHE_FILE]; char filename[MAX_PTCACHE_FILE];
@ -2073,6 +2096,73 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra
*endframe += (int)(offset+0.5f); *endframe += (int)(offset+0.5f);
} }
} }
/* verify cached_frames array is up to date */
if(cache->cached_frames) {
if(MEM_allocN_len(cache->cached_frames) != sizeof(char) * (cache->endframe-cache->startframe+1)) {
MEM_freeN(cache->cached_frames);
cache->cached_frames = NULL;
}
}
if(cache->cached_frames==NULL) {
int sta=cache->startframe;
int end=cache->endframe;
int i=0;
cache->cached_frames = MEM_callocN(sizeof(char) * (cache->endframe-cache->startframe+1), "cached frames array");
if(pid->cache->flag & PTCACHE_DISK_CACHE) {
/* mode is same as fopen's modes */
DIR *dir;
struct dirent *de;
char path[MAX_PTCACHE_PATH];
char filename[MAX_PTCACHE_FILE];
char ext[MAX_PTCACHE_PATH];
int len; /* store the length of the string */
ptcache_path(pid, path);
len = BKE_ptcache_id_filename(pid, filename, (int)cfra, 0, 0); /* no path */
dir = opendir(path);
if (dir==NULL)
return;
snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, pid->stack_index);
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
/* read the number of the file */
int frame, len2 = (int)strlen(de->d_name);
char num[7];
if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
frame = atoi(num);
if(frame >= sta && frame <= end)
cache->cached_frames[frame-sta] = 1;
}
}
}
}
closedir(dir);
}
else {
PTCacheMem *pm= pid->cache->mem_cache.first;
PTCacheMem *link= NULL;
pm= pid->cache->mem_cache.first;
while(pm) {
if(pm->frame >= sta && pm->frame <= end)
cache->cached_frames[pm->frame-sta] = 1;
pm = pm->next;
}
}
}
} }
int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode) int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
@ -2293,6 +2383,8 @@ void BKE_ptcache_free(PointCache *cache)
BKE_ptcache_free_mem(&cache->mem_cache); BKE_ptcache_free_mem(&cache->mem_cache);
if(cache->edit && cache->free_edit) if(cache->edit && cache->free_edit)
cache->free_edit(cache->edit); cache->free_edit(cache->edit);
if(cache->cached_frames)
MEM_freeN(cache->cached_frames);
MEM_freeN(cache); MEM_freeN(cache);
} }
void BKE_ptcache_free_list(ListBase *ptcaches) void BKE_ptcache_free_list(ListBase *ptcaches)

@ -2937,6 +2937,7 @@ static void direct_link_pointcache(FileData *fd, PointCache *cache)
cache->simframe= 0; cache->simframe= 0;
cache->edit= NULL; cache->edit= NULL;
cache->free_edit= NULL; cache->free_edit= NULL;
cache->cached_frames= NULL;
} }
static void direct_link_pointcache_list(FileData *fd, ListBase *ptcaches, PointCache **ocache) static void direct_link_pointcache_list(FileData *fd, ListBase *ptcaches, PointCache **ocache)

@ -181,6 +181,7 @@ static void time_cache_refresh(const bContext *C, SpaceTime *stime, ARegion *ar)
SpaceTimeCache *stc; SpaceTimeCache *stc;
float *fp, *array; float *fp, *array;
int i, len; int i, len;
int sta, end;
switch(pid->type) { switch(pid->type) {
case PTCACHE_TYPE_SOFTBODY: case PTCACHE_TYPE_SOFTBODY:
@ -197,6 +198,11 @@ static void time_cache_refresh(const bContext *C, SpaceTime *stime, ARegion *ar)
if (!(stime->cache_display & TIME_CACHE_SMOKE)) continue; if (!(stime->cache_display & TIME_CACHE_SMOKE)) continue;
break; break;
} }
BKE_ptcache_id_time(pid, CTX_data_scene(C), 0, &sta, &end, NULL);
if(pid->cache->cached_frames==NULL)
continue;
stc= MEM_callocN(sizeof(SpaceTimeCache), "spacetimecache"); stc= MEM_callocN(sizeof(SpaceTimeCache), "spacetimecache");
@ -208,14 +214,15 @@ static void time_cache_refresh(const bContext *C, SpaceTime *stime, ARegion *ar)
stc->flag |= PTCACHE_DISK_CACHE; stc->flag |= PTCACHE_DISK_CACHE;
/* first allocate with maximum number of frames needed */ /* first allocate with maximum number of frames needed */
BKE_ptcache_id_time(pid, CTX_data_scene(C), 0, &stc->startframe, &stc->endframe, NULL); stc->startframe = sta;
len = (stc->endframe - stc->startframe + 1)*4; stc->endframe = end;
len = (end - sta + 1)*4;
fp = array = MEM_callocN(len*2*sizeof(float), "temporary timeline cache array"); fp = array = MEM_callocN(len*2*sizeof(float), "temporary timeline cache array");
/* fill the vertex array with a quad for each cached frame */ /* fill the vertex array with a quad for each cached frame */
for (i=stc->startframe; i<=stc->endframe; i++) { for (i=sta; i<=end; i++) {
if (BKE_ptcache_id_exist(pid, i)) { if (pid->cache->cached_frames[i-sta]) {
fp[0] = (float)i; fp[0] = (float)i;
fp[1] = 0.0; fp[1] = 0.0;
fp+=2; fp+=2;

@ -167,6 +167,8 @@ typedef struct PointCache {
char prev_name[64]; char prev_name[64];
char info[64]; char info[64];
char path[240]; /* file path */ char path[240]; /* file path */
char *cached_frames; /* array of length endframe-startframe+1 with flags to indicate cached frames */
/* can be later used for other per frame flags too if needed */
struct ListBase mem_cache; struct ListBase mem_cache;
struct PTCacheEdit *edit; struct PTCacheEdit *edit;