Index: include/BIF_drawseq.h =================================================================== --- include/BIF_drawseq.h (revision 11922) +++ include/BIF_drawseq.h (working copy) @@ -36,6 +36,7 @@ struct ScrArea; struct Sequence; +void drawprefetchseqspace(struct ScrArea *sa, void *spacedata); void drawseqspace(struct ScrArea *sa, void *spacedata); void set_special_seq_update(int val); Index: include/BSE_sequence.h =================================================================== --- include/BSE_sequence.h (revision 11922) +++ include/BSE_sequence.h (working copy) @@ -60,6 +60,15 @@ struct ImBuf *give_ibuf_seq(int rectx, int recty, int cfra, int chansel); /* chansel: render this channel. Default=0 (renders end result)*/ +/* sequence prefetch API */ +void seq_start_threads(); +void seq_stop_threads(); +void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown); +void seq_wait_for_prefetch_ready(); +struct ImBuf * give_ibuf_threaded(int rectx, int recty, int cfra, + int chanshown); + + void free_imbuf_seq_except(int cfra); void free_imbuf_seq_with_ipo(struct Ipo * ipo); void free_imbuf_seq(void); Index: include/BIF_spacetypes.h =================================================================== --- include/BIF_spacetypes.h (revision 11922) +++ include/BIF_spacetypes.h (working copy) @@ -35,6 +35,7 @@ typedef struct _SpaceType SpaceType; +typedef void (*SpacePrefetchDrawFP) (struct ScrArea *sa, void *spacedata); typedef void (*SpaceDrawFP) (struct ScrArea *sa, void *spacedata); typedef void (*SpaceChangeFP) (struct ScrArea *sa, void *spacedata); typedef void (*SpaceHandleFP) (struct ScrArea *sa, void *spacedata, struct BWinEvent *evt); @@ -43,7 +44,7 @@ SpaceType* spacetype_new (char *name); -void spacetype_set_winfuncs (SpaceType *st, SpaceDrawFP draw, SpaceChangeFP change, SpaceHandleFP handle); +void spacetype_set_winfuncs (SpaceType *st, SpacePrefetchDrawFP prefetch, SpaceDrawFP draw, SpaceChangeFP change, SpaceHandleFP handle); /***/ Index: include/BIF_space.h =================================================================== --- include/BIF_space.h (revision 11922) +++ include/BIF_space.h (working copy) @@ -92,6 +92,7 @@ #define B_RECALCLIGHT 3310 +void scrarea_do_winprefetchdraw (struct ScrArea *sa); void scrarea_do_windraw (struct ScrArea *sa); void scrarea_do_winchange (struct ScrArea *sa); void scrarea_do_winhandle (struct ScrArea *sa, struct BWinEvent *evt); Index: makesdna/DNA_userdef_types.h =================================================================== --- makesdna/DNA_userdef_types.h (revision 11922) +++ makesdna/DNA_userdef_types.h (working copy) @@ -171,6 +171,7 @@ short tw_hotspot, tw_flag, tw_handlesize, tw_size; int textimeout, texcollectrate; int memcachelimit; + int prefetchframes; short frameserverport; short pad_rot_angle; /*control the rotation step of the view when PAD2,PAD4,PAD6&PAD8 is use*/ short obcenter_dia; @@ -181,7 +182,6 @@ short recent_files; /* maximum number of recently used files to remember */ short smooth_viewtx; /* miliseconds to spend spinning the view */ short glreslimit; - char pad[4]; } UserDef; extern UserDef U; /* from usiblender.c !!!! */ Index: src/sequence.c =================================================================== --- src/sequence.c (revision 11922) +++ src/sequence.c (working copy) @@ -70,6 +70,7 @@ #include "RE_pipeline.h" // talks to entire render API #include "blendef.h" +#include int seqrectx, seqrecty; @@ -1179,6 +1180,217 @@ } +/* threading api */ + +static ListBase running_threads; +static ListBase prefetch_wait; +static ListBase prefetch_done; + +static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t wakeup_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t wakeup_cond = PTHREAD_COND_INITIALIZER; + +static pthread_mutex_t prefetch_ready_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t prefetch_ready_cond = PTHREAD_COND_INITIALIZER; + +static volatile int seq_thread_shutdown = FALSE; +static volatile int seq_last_given_cfra = 0; + +typedef struct PrefetchThread { + struct PrefetchThread *next, *prev; + pthread_t pthread; + int running; +} PrefetchThread; + +typedef struct PrefetchQueueElem { + struct PrefetchQueueElem *next, *prev; + + int rectx; + int recty; + int cfra; + int chanshown; + + struct ImBuf * ibuf; +} PrefetchQueueElem; + + +static void * seq_prefetch_thread(void * This_) +{ + PrefetchThread * This = This_; + + while (!seq_thread_shutdown) { + PrefetchQueueElem * e; + int s_last; + + pthread_mutex_lock(&queue_lock); + e = prefetch_wait.first; + if (e) { + BLI_remlink(&prefetch_wait, e); + } + s_last = seq_last_given_cfra; + + pthread_mutex_unlock(&queue_lock); + + if (!e) { + pthread_mutex_lock(&prefetch_ready_lock); + + This->running = FALSE; + + pthread_cond_signal(&prefetch_ready_cond); + pthread_mutex_unlock(&prefetch_ready_lock); + + pthread_mutex_lock(&wakeup_lock); + pthread_cond_wait(&wakeup_cond, &wakeup_lock); + pthread_mutex_unlock(&wakeup_lock); + continue; + } + + This->running = TRUE; + + if (e->cfra >= s_last) { + e->ibuf = give_ibuf_seq(e->rectx, e->recty, e->cfra, + e->chanshown); + } + + if (e->ibuf) { + IMB_cache_limiter_ref(e->ibuf); + } + + pthread_mutex_lock(&queue_lock); + + BLI_addtail(&prefetch_done, e); + + for (e = prefetch_wait.first; e; e = e->next) { + if (s_last > e->cfra) { + BLI_remlink(&prefetch_done, e); + MEM_freeN(e); + } + } + + for (e = prefetch_done.first; e; e = e->next) { + if (s_last > e->cfra) { + if (e->ibuf) { + IMB_cache_limiter_unref(e->ibuf); + } + BLI_remlink(&prefetch_done, e); + MEM_freeN(e); + } + } + + pthread_mutex_unlock(&queue_lock); + + } + return 0; +} + +void seq_start_threads() +{ + int i; + + running_threads.first = running_threads.last = NULL; + prefetch_wait.first = prefetch_wait.last = NULL; + prefetch_done.first = prefetch_done.last = NULL; + + seq_thread_shutdown = FALSE; + seq_last_given_cfra = MAXFRAME; + + /* since global structures are modified during the processing + of one frame, only one render thread is currently possible... + + (but we code, in the hope, that we can remove this restriction + soon...) + */ + + for (i = 0; i < 1; i++) { + PrefetchThread *t = MEM_callocN(sizeof(PrefetchThread), + "prefetch_thread"); + BLI_addtail(&running_threads, t); + + pthread_create(&t->pthread, NULL, seq_prefetch_thread, t); + } +} + +void seq_stop_threads() +{ + PrefetchThread *tslot; + + seq_thread_shutdown = TRUE; + + pthread_mutex_lock(&wakeup_lock); + pthread_cond_broadcast(&wakeup_cond); + pthread_mutex_unlock(&wakeup_lock); + + for(tslot = running_threads.first; tslot; tslot= tslot->next) { + pthread_join(tslot->pthread, NULL); + } + + BLI_freelistN(&running_threads); +} + +void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown) +{ + PrefetchQueueElem * e = MEM_callocN(sizeof(PrefetchQueueElem), + "prefetch_queue_elem"); + e->rectx = rectx; + e->recty = recty; + e->cfra = cfra; + e->chanshown = chanshown; + + pthread_mutex_lock(&queue_lock); + BLI_addtail(&prefetch_wait, e); + pthread_mutex_unlock(&queue_lock); + + pthread_mutex_lock(&wakeup_lock); + pthread_cond_signal(&wakeup_cond); + pthread_mutex_unlock(&wakeup_lock); +} + +void seq_wait_for_prefetch_ready() +{ + PrefetchThread *tslot; + + pthread_mutex_lock(&prefetch_ready_lock); + + for(;;) { + for(tslot = running_threads.first; tslot; tslot= tslot->next) { + if (tslot->running) { + break; + } + } + if (!tslot) { + break; + } + pthread_cond_wait(&prefetch_ready_cond, &prefetch_ready_lock); + } + + pthread_mutex_unlock(&prefetch_ready_lock); +} + +ImBuf * give_ibuf_threaded(int rectx, int recty, int cfra, int chanshown) +{ + PrefetchQueueElem * e = 0; + + pthread_mutex_lock(&queue_lock); + + for (e = prefetch_done.first; e; e = e->next) { + if (cfra == e->cfra && + chanshown == e->chanshown && + rectx == e->rectx && + recty == e->recty) { + break; + } + } + + /* e->ibuf is unrefed by render thread on next round. */ + seq_last_given_cfra = cfra; + + pthread_mutex_unlock(&queue_lock); + + return e ? e->ibuf : 0; +} + + + /* Functions to free imbuf and anim data on changes */ static void free_imbuf_strip_elem(StripElem *se) @@ -1371,11 +1583,12 @@ */ { extern int mem_in_use; + extern int mmap_in_use; int max = MEM_CacheLimiter_get_maximum(); - if (max != 0 && mem_in_use > max) { + if (max != 0 && mem_in_use + mmap_in_use > max) { fprintf(stderr, "mem_in_use = %d, max = %d\n", - mem_in_use, max); + mem_in_use + mmap_in_use, max); fprintf(stderr, "Cleaning up, please wait...\n" "If this happens very often,\n" "consider " Index: src/drawview.c =================================================================== --- src/drawview.c (revision 11922) +++ src/drawview.c (working copy) @@ -3168,6 +3168,9 @@ double tottime = 0.0; +static ScrArea *oldsa; +static double swaptime; +static int curmode; int update_time(void) { @@ -3183,12 +3186,67 @@ return (tottime < 0.0); } +static void inner_play_prefetch_frame(int mode, int cfra) +{ + ScrArea *sa; + int oldcfra = CFRA; + + if (!U.prefetchframes) { + return; + } + + CFRA = cfra; + + sa= G.curscreen->areabase.first; + while(sa) { + if(sa==oldsa) { + scrarea_do_winprefetchdraw(sa); + } + else if(curmode & 1) { /* all view3d and seq spaces */ + if ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ) { + scrarea_do_winprefetchdraw(sa); + } + } + else if(curmode & 4) { /* all seq spaces */ + if (sa->spacetype == SPACE_SEQ) { + scrarea_do_winprefetchdraw(sa); + } + } + + sa= sa->next; + } + + CFRA = oldcfra; +} + +static void inner_play_prefetch_startup(int mode) +{ + int i; + + if (!U.prefetchframes) { + return; + } + + seq_start_threads(); + + for (i = 0; i <= U.prefetchframes; i++) { + inner_play_prefetch_frame(mode, CFRA + i); + } + + seq_wait_for_prefetch_ready(); +} + +static void inner_play_prefetch_shutdown(int mode) +{ + if (!U.prefetchframes) { + return; + } + seq_stop_threads(); +} + void inner_play_anim_loop(int init, int mode) { ScrArea *sa; - static ScrArea *oldsa; - static double swaptime; - static int curmode; /* init */ if(init) { @@ -3223,6 +3281,8 @@ sa= sa->next; } + inner_play_prefetch_frame(mode, CFRA + U.prefetchframes); + /* make sure that swaptime passed by */ tottime -= swaptime; while (update_time()) PIL_sleep_ms(1); @@ -3265,6 +3325,8 @@ cfraont= CFRA; oldsa= curarea; + inner_play_prefetch_startup(mode); + audiostream_start( CFRA ); if (curarea && curarea->spacetype == SPACE_SEQ) { @@ -3313,6 +3375,7 @@ if(event==SPACEKEY); else CFRA= cfraont; + inner_play_prefetch_shutdown(mode); audiostream_stop(); if(oldsa!=curarea) areawinset(oldsa->win); Index: src/spacetypes.c =================================================================== --- src/spacetypes.c (revision 11922) +++ src/spacetypes.c (working copy) @@ -52,6 +52,7 @@ struct _SpaceType { char name[32]; + SpacePrefetchDrawFP winprefetchdraw; SpaceDrawFP windraw; SpaceChangeFP winchange; SpaceHandleFP winhandle; @@ -70,8 +71,9 @@ return st; } -void spacetype_set_winfuncs(SpaceType *st, SpaceDrawFP draw, SpaceChangeFP change, SpaceHandleFP handle) +void spacetype_set_winfuncs(SpaceType *st, SpacePrefetchDrawFP prefetchdraw, SpaceDrawFP draw, SpaceChangeFP change, SpaceHandleFP handle) { + st->winprefetchdraw = prefetchdraw; st->windraw= draw; st->winchange= change; st->winhandle= handle; @@ -105,6 +107,17 @@ } } +void scrarea_do_winprefetchdraw(ScrArea *area) +{ + SpaceType *st= spacetype_from_area(area); + + areawinset(area->win); + + if(area->win && st->winprefetchdraw) { + st->winprefetchdraw(area, area->spacedata.first); + } +} + void scrarea_do_windraw(ScrArea *area) { SpaceType *st= spacetype_from_area(area); Index: src/space.c =================================================================== --- src/space.c (revision 11922) +++ src/space.c (working copy) @@ -3126,8 +3126,8 @@ uiBlock *block; static short cur_light=0; float fac, col[3]; - short xpos, ypos, ypostab, buth, rspace, dx, y1, y2, y3, y4, y5, y6; - short y2label, y3label, y4label, y5label, y6label; + short xpos, ypos, ypostab, buth, rspace, dx, y1, y2, y3, y4, y5, y6, y7; + short y2label, y3label, y4label, y5label, y6label, y7label; short spref, mpref, lpref, smfileselbut; short edgsp, midsp; char naam[32]; @@ -3178,6 +3178,7 @@ y4 = ypos+3*(buth+rspace); y5 = ypos+4*(buth+rspace); y6 = ypos+5*(buth+rspace); + y7 = ypos+6*(buth+rspace); y2label = y2-2; /* adjustments to offset the labels down to align better */ @@ -3185,6 +3186,7 @@ y4label = y4-2; y5label = y5-2; y6label = y6-2; + y7label = y7-2; /* set the color to blue and draw the main 'tab' controls */ @@ -3768,8 +3770,13 @@ uiDefBut(block, LABEL,0,"System:", - (xpos+edgsp+(4*midsp)+(4*mpref)),y6label,mpref,buth, + (xpos+edgsp+(4*midsp)+(4*mpref)),y7label,mpref,buth, 0, 0, 0, 0, 0, ""); + uiDefButI(block, NUM, B_REDR, "Prefetch frames ", + (xpos+edgsp+(4*mpref)+(4*midsp)), y6, mpref, buth, + &U.prefetchframes, 0.0, 50.0, 20, 2, + "Number of frames to render ahead during playback."); + uiDefButI(block, NUM, B_MEMCACHELIMIT, "MEM Cache Limit ", (xpos+edgsp+(4*mpref)+(4*midsp)), y5, mpref, buth, &U.memcachelimit, 0.0, 1024.0, 30, 2, @@ -6171,7 +6178,7 @@ if (!st) { st= spacetype_new("Action"); - spacetype_set_winfuncs(st, drawactionspace, changeactionspace, winqreadactionspace); + spacetype_set_winfuncs(st, NULL, drawactionspace, changeactionspace, winqreadactionspace); } return st; @@ -6182,7 +6189,7 @@ if (!st) { st= spacetype_new("Buts"); - spacetype_set_winfuncs(st, drawbutspace, changebutspace, winqreadbutspace); + spacetype_set_winfuncs(st, NULL, drawbutspace, changebutspace, winqreadbutspace); } return st; @@ -6193,7 +6200,7 @@ if (!st) { st= spacetype_new("File"); - spacetype_set_winfuncs(st, drawfilespace, NULL, winqreadfilespace); + spacetype_set_winfuncs(st, NULL, drawfilespace, NULL, winqreadfilespace); } return st; @@ -6204,7 +6211,7 @@ if (!st) { st= spacetype_new("Image"); - spacetype_set_winfuncs(st, drawimagespace, changeimagepace, winqreadimagespace); + spacetype_set_winfuncs(st, NULL, drawimagespace, changeimagepace, winqreadimagespace); } return st; @@ -6215,7 +6222,7 @@ if (!st) { st= spacetype_new("Imasel"); - spacetype_set_winfuncs(st, drawimaselspace, changeimaselspace, winqreadimaselspace); + spacetype_set_winfuncs(st, NULL, drawimaselspace, changeimaselspace, winqreadimaselspace); } return st; @@ -6226,7 +6233,7 @@ if (!st) { st= spacetype_new("Info"); - spacetype_set_winfuncs(st, drawinfospace, NULL, winqreadinfospace); + spacetype_set_winfuncs(st, NULL, drawinfospace, NULL, winqreadinfospace); } return st; @@ -6237,7 +6244,7 @@ if (!st) { st= spacetype_new("Ipo"); - spacetype_set_winfuncs(st, drawipospace, changeview2dspace, winqreadipospace); + spacetype_set_winfuncs(st, NULL, drawipospace, changeview2dspace, winqreadipospace); } return st; @@ -6248,7 +6255,7 @@ if (!st) { st= spacetype_new("Nla"); - spacetype_set_winfuncs(st, drawnlaspace, changeview2dspace, winqreadnlaspace); + spacetype_set_winfuncs(st, NULL, drawnlaspace, changeview2dspace, winqreadnlaspace); } return st; @@ -6259,7 +6266,7 @@ if (!st) { st= spacetype_new("Oops"); - spacetype_set_winfuncs(st, drawoopsspace, changeview2dspace, winqreadoopsspace); + spacetype_set_winfuncs(st, NULL, drawoopsspace, changeview2dspace, winqreadoopsspace); } return st; @@ -6270,7 +6277,7 @@ if (!st) { st= spacetype_new("Sequence"); - spacetype_set_winfuncs(st, drawseqspace, changeview2dspace, winqreadseqspace); + spacetype_set_winfuncs(st, drawprefetchseqspace, drawseqspace, changeview2dspace, winqreadseqspace); } return st; @@ -6281,7 +6288,7 @@ if (!st) { st= spacetype_new("Sound"); - spacetype_set_winfuncs(st, drawsoundspace, changeview2dspace, winqreadsoundspace); + spacetype_set_winfuncs(st, NULL, drawsoundspace, changeview2dspace, winqreadsoundspace); } return st; @@ -6292,7 +6299,7 @@ if (!st) { st= spacetype_new("Text"); - spacetype_set_winfuncs(st, drawtextspace, NULL, winqreadtextspace); + spacetype_set_winfuncs(st, NULL, drawtextspace, NULL, winqreadtextspace); } return st; @@ -6316,7 +6323,7 @@ if (!st) { st = spacetype_new("Script"); - spacetype_set_winfuncs(st, drawscriptspace, spacescript_change, winqreadscriptspace); + spacetype_set_winfuncs(st, NULL, drawscriptspace, spacescript_change, winqreadscriptspace); } return st; @@ -6327,7 +6334,7 @@ if (!st) { st= spacetype_new("View3D"); - spacetype_set_winfuncs(st, drawview3dspace, changeview3dspace, winqreadview3dspace); + spacetype_set_winfuncs(st, NULL, drawview3dspace, changeview3dspace, winqreadview3dspace); } return st; @@ -6338,7 +6345,7 @@ if (!st) { st= spacetype_new("Time"); - spacetype_set_winfuncs(st, drawtimespace, NULL, winqreadtimespace); + spacetype_set_winfuncs(st, NULL, drawtimespace, NULL, winqreadtimespace); } return st; @@ -6350,7 +6357,7 @@ if (!st) { st= spacetype_new("Node"); - spacetype_set_winfuncs(st, drawnodespace, changeview2dspace, winqreadnodespace); + spacetype_set_winfuncs(st, NULL, drawnodespace, changeview2dspace, winqreadnodespace); } return st; Index: src/drawseq.c =================================================================== --- src/drawseq.c (revision 11922) +++ src/drawseq.c (working copy) @@ -51,6 +51,7 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_view2d_types.h" +#include "DNA_userdef_types.h" #include "BKE_global.h" #include "BKE_plugin_types.h" @@ -788,7 +789,11 @@ return; else { recursive= 1; - ibuf= (ImBuf *)give_ibuf_seq(rectx, recty, (G.scene->r.cfra), sseq->chanshown); + if (!U.prefetchframes || (G.f & G_PLAYANIM) == 0) { + ibuf= (ImBuf *)give_ibuf_seq(rectx, recty, (G.scene->r.cfra), sseq->chanshown); + } else { + ibuf= (ImBuf *)give_ibuf_threaded(rectx, recty, (G.scene->r.cfra), sseq->chanshown); + } recursive= 0; /* HURMF! the give_ibuf_seq can call image display in this window */ @@ -1276,6 +1281,20 @@ } +void drawprefetchseqspace(ScrArea *sa, void *spacedata) +{ + SpaceSeq *sseq= sa->spacedata.first; + int rectx, recty; + + rectx= (G.scene->r.size*G.scene->r.xsch)/100; + recty= (G.scene->r.size*G.scene->r.ysch)/100; + + if(sseq->mainb) { + give_ibuf_prefetch_request( + rectx, recty, (G.scene->r.cfra), sseq->chanshown); + } +} + void drawseqspace(ScrArea *sa, void *spacedata) { SpaceSeq *sseq= sa->spacedata.first;