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,262 @@ } +/* 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); + + fprintf(stderr, "render: idle\n"); + + pthread_mutex_lock(&wakeup_lock); + if (!seq_thread_shutdown) { + pthread_cond_wait(&wakeup_cond, &wakeup_lock); + } + pthread_mutex_unlock(&wakeup_lock); + continue; + } + + This->running = TRUE; + + fprintf(stderr, "rendering %d\n", e->cfra); + + 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) { + fprintf(stderr, "wait cleanup: %d\n", e->cfra); + BLI_remlink(&prefetch_wait, e); + MEM_freeN(e); + } + } + + for (e = prefetch_done.first; e; e = e->next) { + if (s_last > e->cfra) { + fprintf(stderr, + "done cleanup: %d\n", 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 = 0; + + /* 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...) + */ + + fprintf(stderr, "seq_start_threads\n"); + + for (i = 0; i < 1; i++) { + PrefetchThread *t = MEM_callocN(sizeof(PrefetchThread), + "prefetch_thread"); + t->running = TRUE; + BLI_addtail(&running_threads, t); + + pthread_create(&t->pthread, NULL, seq_prefetch_thread, t); + } +} + +void seq_stop_threads() +{ + PrefetchThread *tslot; + PrefetchQueueElem * e; + + fprintf(stderr, "seq_stop_threads()\n"); + + + pthread_mutex_lock(&wakeup_lock); + + seq_thread_shutdown = TRUE; + + pthread_cond_broadcast(&wakeup_cond); + pthread_mutex_unlock(&wakeup_lock); + + for(tslot = running_threads.first; tslot; tslot= tslot->next) { + pthread_join(tslot->pthread, NULL); + } + + + for (e = prefetch_wait.first; e; e = e->next) { + BLI_remlink(&prefetch_wait, e); + MEM_freeN(e); + } + + for (e = prefetch_done.first; e; e = e->next) { + if (e->ibuf) { + IMB_cache_limiter_unref(e->ibuf); + } + BLI_remlink(&prefetch_done, e); + MEM_freeN(e); + } + + 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; + + fprintf(stderr, "prefetch request: %d %d %d %d\n", + rectx, recty, cfra, 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; + + fprintf(stderr, "In prefetch wait...\n"); + + pthread_mutex_lock(&prefetch_ready_lock); + + for(;;) { + for(tslot = running_threads.first; tslot; tslot= tslot->next) { + fprintf(stderr, "prefetch wait: testing %p\n", tslot); + if (tslot->running) { + fprintf(stderr, + "prefetch wait: still running\n"); + break; + } + } + if (!tslot) { + break; + } + pthread_cond_wait(&prefetch_ready_cond, &prefetch_ready_lock); + } + + pthread_mutex_unlock(&prefetch_ready_lock); + + fprintf(stderr, "out of prefetch wait.\n"); +} + +ImBuf * give_ibuf_threaded(int rectx, int recty, int cfra, int chanshown) +{ + PrefetchQueueElem * e = 0; + + fprintf(stderr, "give threaded: %d %d %d %d\n", + rectx, recty, cfra, chanshown); + + 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) { + fprintf(stderr, "found\n"); + 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 +1628,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) @@ -136,6 +136,7 @@ #include "BSE_filesel.h" #include "BSE_headerbuttons.h" #include "BSE_seqaudio.h" +#include "BSE_sequence.h" #include "BSE_trans_types.h" #include "BSE_time.h" #include "BSE_view.h" @@ -3168,6 +3169,9 @@ double tottime = 0.0; +static ScrArea *oldsa; +static double swaptime; +static int curmode; int update_time(void) { @@ -3183,60 +3187,172 @@ return (tottime < 0.0); } -void inner_play_anim_loop(int init, int mode) +static void inner_play_prefetch_frame(int mode, int cfra) { ScrArea *sa; - static ScrArea *oldsa; - static double swaptime; - static int curmode; + int oldcfra = CFRA; + ScrArea *oldcurarea = curarea; - /* init */ - if(init) { - oldsa= curarea; - swaptime= 1.0/(float)G.scene->r.frs_sec; - tottime= 0.0; - curmode= mode; - + if (!U.prefetchframes) { return; } - set_timecursor(CFRA); - - update_for_newframe_nodraw(1); /* adds no events in UI */ + CFRA = cfra; + fprintf(stderr, "prefetch_frame: %d (oldcfra=%d)\n", cfra, oldcfra); + sa= G.curscreen->areabase.first; while(sa) { if(sa==oldsa) { - scrarea_do_windraw(sa); + scrarea_do_winprefetchdraw(sa); } - else if(curmode & 1) { /* all view3d and seq spaces */ + else if(mode & 1) { /* all view3d and seq spaces */ if ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ) { - scrarea_do_windraw(sa); + scrarea_do_winprefetchdraw(sa); } } - else if(curmode & 4) { /* all seq spaces */ + else if(mode & 4) { /* all seq spaces */ if (sa->spacetype == SPACE_SEQ) { - scrarea_do_windraw(sa); + scrarea_do_winprefetchdraw(sa); } } sa= sa->next; } + + CFRA = oldcfra; + curarea = oldcurarea; +} + +static void inner_play_prefetch_startup(int mode) +{ + int i; + + fprintf(stderr, "inner_play_prefetch_startup: %d\n", + U.prefetchframes); + + if (!U.prefetchframes) { + return; + } + + seq_start_threads(); + + for (i = 0; i <= U.prefetchframes; i++) { + int cfra = CFRA + i; + inner_play_prefetch_frame(mode, cfra); + } + + 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 int last_cfra = -1; + int lost_sync = FALSE; + + /* init */ + if(init) { + oldsa= curarea; + swaptime= 1.0/(float)G.scene->r.frs_sec; + tottime= 0.0; + curmode= mode; + last_cfra = -1; + + return; + } + + if (CFRA != last_cfra) { + int pf; + set_timecursor(CFRA); - /* make sure that swaptime passed by */ - tottime -= swaptime; - while (update_time()) PIL_sleep_ms(1); + update_for_newframe_nodraw(1); /* adds no events in UI */ - if(CFRA>=PEFRA) { - if (tottime > 0.0) tottime = 0.0; - CFRA= PSFRA; - audiostream_stop(); - audiostream_start( CFRA ); + sa= G.curscreen->areabase.first; + while(sa) { + if(sa==oldsa) { + scrarea_do_windraw(sa); + } + else if(curmode & 1) { /* all view3d and seq spaces */ + if ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ) { + scrarea_do_windraw(sa); + } + } + else if(curmode & 4) { /* all seq spaces */ + if (sa->spacetype == SPACE_SEQ) { + scrarea_do_windraw(sa); + } + } + + sa= sa->next; + } + + if (last_cfra == -1) { + last_cfra = CFRA - 1; + } + + if (U.prefetchframes) { + pf = last_cfra; + + if (CFRA - last_cfra > U.prefetchframes || + CFRA - last_cfra < 0) { + pf = CFRA - U.prefetchframes; + fprintf(stderr, + "Lost sync, rerendering " + "prefetch queue, please wait...\n"); + /* audiostream_stop(); */ + lost_sync = TRUE; + } + + while (pf < CFRA) { + pf++; + inner_play_prefetch_frame( + curmode, pf + U.prefetchframes); + } + + if (lost_sync) { + seq_wait_for_prefetch_ready(); + + /* audiostream_start( CFRA ); + tottime -= swaptime; + while (update_time()) PIL_sleep_ms(1); + tottime = 0.0; */ + } + } } - else { - if (U.mixbufsize && (G.scene->audio.flag & AUDIO_SYNC)) CFRA = audiostream_pos(); - else CFRA++; + + last_cfra = CFRA; + + if (!lost_sync) { + /* make sure that swaptime passed by */ + tottime -= swaptime; + while (update_time()) PIL_sleep_ms(1); + + if(CFRA>=PEFRA) { + if (tottime > 0.0) tottime = 0.0; + CFRA= PSFRA; + audiostream_stop(); + audiostream_start( CFRA ); + } + else { + if (U.mixbufsize && (G.scene->audio.flag & AUDIO_SYNC)) CFRA = audiostream_pos(); + else CFRA++; + } } + + if (CFRA < last_cfra) { + fprintf(stderr, "ARGGGGGGHH CFRA running backwards: %d\n", + CFRA); + } + } /* play_anim: 'mode' defines where to play and if repeat is on (now bitfield): @@ -3251,28 +3367,32 @@ unsigned short event=0; short val; + fprintf(stderr, "Play anim\n"); + /* patch for very very old scenes */ if(SFRA==0) SFRA= 1; if(EFRA==0) EFRA= 250; if(PSFRA>PEFRA) return 0; - update_time(); - /* waitcursor(1); */ G.f |= G_PLAYANIM; /* in sequence.c and view.c this is handled */ cfraont= CFRA; oldsa= curarea; - audiostream_start( CFRA ); - if (curarea && curarea->spacetype == SPACE_SEQ) { SpaceSeq *sseq = curarea->spacedata.first; if (sseq->mainb == 0) mode |= 4; } + + inner_play_prefetch_startup(mode); + + update_time(); inner_play_anim_loop(1, mode); /* 1==init */ + + audiostream_start( CFRA ); /* forces all buffers to be OK for current frame (otherwise other windows get redrawn with CFRA+1) */ curarea->win_swap= WIN_BACK_OK; @@ -3313,6 +3433,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/editscreen.c =================================================================== --- src/editscreen.c (revision 11922) +++ src/editscreen.c (working copy) @@ -1119,7 +1119,9 @@ } if(val & TIME_ALL_ANIM_WIN) allqueue(REDRAWANIM, 0); if(val & TIME_ALL_BUTS_WIN) allqueue(REDRAWBUTSALL, 0); - if(val & TIME_SEQ) allqueue(REDRAWSEQ, 0); + if(val & TIME_SEQ) { + allqueue(REDRAWSEQ, 0); + } allqueue(REDRAWTIME, 0); } 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/header_seq.c =================================================================== --- src/header_seq.c (revision 11922) +++ src/header_seq.c (working copy) @@ -115,10 +115,22 @@ block= uiNewBlock(&curarea->uiblocks, "seq_viewmenu", UI_EMBOSSP, UI_HELV, curarea->headwin); uiBlockSetButmFunc(block, do_seq_viewmenu, NULL); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Animation|Alt A", 0, yco-=20, - menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Animation in 3D View|Alt Shift A", 0, yco-=20, - menuwidth, 19, NULL, 0.0, 0.0, 1, 2, ""); + if (sseq->mainb == 0) { + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, + "Play Back Animation " + "in all Sequence Areas|Alt A", 0, yco-=20, + menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); + } else { + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, + "Play Back Animation " + "in this window|Alt A", 0, yco-=20, + menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); + } + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, + "Play Back Animation in all " + "3D Views and Sequence Areas|Alt Shift A", + 0, yco-=20, + menuwidth, 19, NULL, 0.0, 0.0, 1, 2, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); 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;