== Sequencer ==
authorPeter Schlaile <peter@schlaile.de>
Mon, 1 Oct 2007 08:03:11 +0000 (08:03 +0000)
committerPeter Schlaile <peter@schlaile.de>
Mon, 1 Oct 2007 08:03:11 +0000 (08:03 +0000)
This patch adds prefetch buffering to the sequencer
(see the tracker for additional details:

https://projects.blender.org/tracker/?func=detail&aid=7307&group_id=9&atid=127
)

We create seperate render threads (currently one, because of the fact,
that sequence rendering modifies global structures...), that
render up to the defined userpref value "Prefetch frames" in advance.
(Pressing Alt-A will _first_ fill the buffer and then start playing.)

Bassam and I did some extensive testing, so it should work.

If you don't configure your number of prefetch frames, prefetching is disabled!
(Sane defaults... :)

Also: if the machine is definitely too slow and runs out of the prefetch
area, prefetching is disabled automatically and we are back to good old
frame skipping mode.

My Dual Athlon is able to handle 4 parallel DV streams at once (sometimes
a little bit choppy, but prefetching is never disabled!)

I fixed also a long standing bug in the audio code, that made playback run
backwards at the beginning...

13 files changed:
source/blender/include/BIF_drawseq.h
source/blender/include/BIF_space.h
source/blender/include/BIF_spacetypes.h
source/blender/include/BSE_sequence.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/src/drawseq.c
source/blender/src/drawview.c
source/blender/src/editscreen.c
source/blender/src/header_seq.c
source/blender/src/seqaudio.c
source/blender/src/sequence.c
source/blender/src/space.c
source/blender/src/spacetypes.c

index 986044d9c7eab8849fb0f9243feca01fae6b1128..4571267a09c6cb09937549ff851625f5d606440c 100644 (file)
@@ -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 7c88610cf3ac9411a26ef9e4d2a37b8f46b97e57..855773b34976e3915d685dbb14f70ce320e88dcd 100644 (file)
@@ -94,6 +94,7 @@ struct SpaceOops;
 #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 e825acf676f0acda8067916400a5eaba6229ed0e..6125cfd5926fce29cca81f6105a6a9eb3ce805cf 100644 (file)
@@ -35,6 +35,7 @@ struct BWinEvent;
 
 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 @@ typedef       void    (*SpaceHandleFP)        (struct ScrArea *sa, void *spacedata, struct BWinE
 
 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 c975e8de8ff13178676f826b1fd8bb3c296e8adf..47a09e154dfd7c9259c877effcc3857390ff1c1e 100644 (file)
@@ -60,6 +60,15 @@ void set_meta_stripdata(struct Sequence *seqm);
 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 5860ca13a5d653a16c498683def2669a523a0cb0..7aa4dbdcf788138feed1b045ad2bfe08364400e1 100644 (file)
@@ -171,6 +171,7 @@ typedef struct UserDef {
        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 @@ typedef struct UserDef {
        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 aaef04283b09ab10f730d3680cd00c06332f334a..86246759a3b6b71eeedb7e2efdb6beaec38075cc 100644 (file)
@@ -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 @@ static void draw_image_seq(ScrArea *sa)
                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 @@ static void seq_blockhandlers(ScrArea *sa)
 
 }
 
+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;
index de4a81abb959062125796bb869d9e8bcc19dd6d2..2bcc7ed76a7c204f14dec88fdcf7809468c2ad76 100644 (file)
 #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"
@@ -3172,13 +3173,20 @@ void drawview3d_render(struct View3D *v3d, int winx, int winy)
 
 
 double tottime = 0.0;
+static ScrArea *oldsa;
+static double swaptime;
+static int curmode;
 
 int update_time(void)
 {
        static double ltime;
        double time;
 
-       if ((U.mixbufsize)&&(audiostream_pos() != CFRA)&&(G.scene->audio.flag & AUDIO_SYNC)) return 0;
+       if ((U.mixbufsize)
+           && (audiostream_pos() != CFRA)
+           && (G.scene->audio.flag & AUDIO_SYNC)) {
+               return 0;
+       }
 
        time = PIL_check_seconds_timer();
        
@@ -3187,60 +3195,169 @@ int update_time(void)
        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;
-
-       /* init */
-       if(init) {
-               oldsa= curarea;
-               swaptime= 1.0/(float)G.scene->r.frs_sec;
-               tottime= 0.0;
-               curmode= mode;
+       int oldcfra = CFRA;
+       ScrArea *oldcurarea = curarea;
 
+       if (!U.prefetchframes) {
                return;
        }
 
-       set_timecursor(CFRA);
-       
-       update_for_newframe_nodraw(1);  /* adds no events in UI */
+       CFRA = cfra;
 
        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;
+
+       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;
+
+       /* 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);
        
+               update_for_newframe_nodraw(1);  /* adds no events in UI */
+
+               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, 
+                                       "SEQ-THREAD: Lost sync, "
+                                       "stopping threads, "
+                                       "back to skip mode...\n");
+                               seq_stop_threads();
+                       } else {
+                               while (pf < CFRA) {
+                                       int c;
+                                       pf++;
+                                       c = pf + U.prefetchframes;
+                                       if (c >= PEFRA) {
+                                               c -= PEFRA;
+                                               c += PSFRA;
+                                       }
+
+                                       inner_play_prefetch_frame(curmode, c);
+                               }
+                       }
+                       
+               }
+       }
+
+       last_cfra = CFRA;
+
        /* 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;
+       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, 
+                               "SEQ-THREAD: CFRA running backwards: %d\n",
+                               CFRA);
+               }
        }
-       else {
-               if (U.mixbufsize && (G.scene->audio.flag & AUDIO_SYNC)) CFRA = audiostream_pos();
-               else CFRA++;
-       }
+
 }
 
 /* play_anim: 'mode' defines where to play and if repeat is on (now bitfield):
@@ -3261,22 +3378,24 @@ int play_anim(int mode)
 
        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;
@@ -3317,6 +3436,7 @@ int play_anim(int mode)
        if(event==SPACEKEY);
        else CFRA= cfraont;
        
+       inner_play_prefetch_shutdown(mode);
        audiostream_stop();
 
        if(oldsa!=curarea) areawinset(oldsa->win);
index 9ae46998cbc6f3e8cd5ed3e9034f68b8e6a2ccff..ff70ff74d70a85634436a110f89e0b96103fbc7b 100644 (file)
@@ -1119,7 +1119,9 @@ static void animated_screen(bScreen *sc, short val)
        }
        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 ffa810f6eb87d94e593abd07b744e2949f2675b7..da2581e36dfd82e4bf66aea50e7ee8e45c2f315e 100644 (file)
@@ -115,10 +115,22 @@ static uiBlock *seq_viewmenu(void *arg_unused)
        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 4bac7fdb25085fa26de20fb263ceafdab7f82160..f050906efa50c6626a234ae5237caf27e3bcb0f5 100644 (file)
@@ -95,6 +95,7 @@ static int audio_pos;
 static int audio_scrub=0;
 static int audio_playing=0;
 static int audio_initialised=0;
+static int audio_startframe=0;
 /////
 //
 /* local protos ------------------- */
@@ -506,8 +507,9 @@ void audiostream_play(Uint32 startframe, Uint32 duration, int mixdown)
                }
        }
 
-       audio_pos = ( ((int)( (((float)startframe)
-                              /(float)G.scene->r.frs_sec)
+       audio_startframe = startframe;
+       audio_pos = ( ((int)( (( (double)startframe)
+                              /(double)G.scene->r.frs_sec)
                              *(G.scene->audio.mixrate)*4 )) & (~3) );
        
        audio_scrub = duration;
@@ -537,8 +539,11 @@ int audiostream_pos(void)
 {
        int pos;
        
-       pos = (int) ( ((float)(audio_pos-U.mixbufsize)/( G.scene->audio.mixrate*4 ))*(float)G.scene->r.frs_sec );
-       if (pos<1) pos=1;
+       pos = (int) (((double)(audio_pos-U.mixbufsize)
+                     / ( G.scene->audio.mixrate*4 ))
+                    * (double)G.scene->r.frs_sec );
+
+       if (pos < audio_startframe) pos = audio_startframe;
        return ( pos );
 }
 
index aad0ebf5c5ff5ad2a6cdf521ca3dec611ee25c7d..333f3d24e6ecfa68792e64d0b901538bbc57636a 100644 (file)
@@ -70,6 +70,7 @@
 #include "RE_pipeline.h"               // talks to entire render API
 
 #include "blendef.h"
+#include <pthread.h>
 
 int seqrectx, seqrecty;
 
@@ -1179,6 +1180,325 @@ ImBuf *give_ibuf_seq(int rectx, int recty, int cfra, int chanshown)
 
 }
 
+/* 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 pthread_mutex_t frame_done_lock     = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t  frame_done_cond     = PTHREAD_COND_INITIALIZER;
+
+static volatile int seq_thread_shutdown = FALSE;
+static volatile int seq_last_given_monoton_cfra = 0;
+static int monoton_cfra = 0;
+
+typedef struct PrefetchThread {
+       struct PrefetchThread *next, *prev;
+       struct PrefetchQueueElem *current;
+       pthread_t pthread;
+       int running;
+} PrefetchThread;
+
+typedef struct PrefetchQueueElem {
+       struct PrefetchQueueElem *next, *prev;
+       
+       int rectx;
+       int recty;
+       int cfra;
+       int chanshown;
+
+       int monoton_cfra;
+
+       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_monoton_cfra;
+
+               This->current = e;
+
+               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);
+                       if (!seq_thread_shutdown) {
+                               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->monoton_cfra) {
+                               BLI_remlink(&prefetch_wait, e);
+                               MEM_freeN(e);
+                       }
+               }
+
+               for (e = prefetch_done.first; e; e = e->next) {
+                       if (s_last > e->monoton_cfra) {
+                               if (e->ibuf) {
+                                       IMB_cache_limiter_unref(e->ibuf);
+                               }
+                               BLI_remlink(&prefetch_done, e);
+                               MEM_freeN(e);
+                       }
+               }
+
+               pthread_mutex_unlock(&queue_lock);
+
+               pthread_mutex_lock(&frame_done_lock);
+               pthread_cond_signal(&frame_done_cond);
+               pthread_mutex_unlock(&frame_done_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_monoton_cfra = monoton_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-THREAD: 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-THREAD: seq_stop_threads()\n");
+
+       if (seq_thread_shutdown) {
+               fprintf(stderr, "SEQ-THREAD: ... already stopped\n");
+               return;
+       }
+       
+       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;
+       if (seq_thread_shutdown) {
+               return;
+       }
+
+       e = MEM_callocN(sizeof(PrefetchQueueElem), "prefetch_queue_elem");
+       e->rectx = rectx;
+       e->recty = recty;
+       e->cfra = cfra;
+       e->chanshown = chanshown;
+       e->monoton_cfra = monoton_cfra++;
+
+       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()
+{
+       if (seq_thread_shutdown) {
+               return;
+       }
+
+       fprintf(stderr, "SEQ-THREAD: rendering prefetch frames...\n");
+
+       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);
+
+       fprintf(stderr, "SEQ-THREAD: prefetch done\n");
+}
+
+ImBuf * give_ibuf_threaded(int rectx, int recty, int cfra, int chanshown)
+{
+       PrefetchQueueElem * e = 0;
+       int found_something = FALSE;
+
+       if (seq_thread_shutdown) {
+               return give_ibuf_seq(rectx, recty, cfra, chanshown);
+       }
+
+       while (!e) {
+               int success = FALSE;
+               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) {
+                               success = TRUE;
+                               found_something = TRUE;
+                               break;
+                       }
+               }
+
+               if (!e) {
+                       for (e = prefetch_wait.first; e; e = e->next) {
+                               if (cfra == e->cfra &&
+                                   chanshown == e->chanshown &&
+                                   rectx == e->rectx && 
+                                   recty == e->recty) {
+                                       found_something = TRUE;
+                                       break;
+                               }
+                       }
+               }
+
+               if (!e) {
+                       PrefetchThread *tslot;
+
+                       for(tslot = running_threads.first; 
+                           tslot; tslot= tslot->next) {
+                               if (tslot->current &&
+                                   cfra == tslot->current->cfra &&
+                                   chanshown == tslot->current->chanshown &&
+                                   rectx == tslot->current->rectx && 
+                                   recty == tslot->current->recty) {
+                                       found_something = TRUE;
+                                       break;
+                               }
+                       }
+               }
+
+               /* e->ibuf is unrefed by render thread on next round. */
+
+               if (e) {
+                       seq_last_given_monoton_cfra = e->monoton_cfra;
+               }
+
+               pthread_mutex_unlock(&queue_lock);
+
+               if (!success) {
+                       e = NULL;
+
+                       if (!found_something) {
+                               fprintf(stderr, 
+                                       "SEQ-THREAD: Requested frame "
+                                       "not in queue ???\n");
+                               break;
+                       }
+                       pthread_mutex_lock(&frame_done_lock);
+                       pthread_cond_wait(&frame_done_cond, &frame_done_lock);
+                       pthread_mutex_unlock(&frame_done_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 +1691,12 @@ void do_render_seq(RenderResult *rr, int cfra)
                */
                {
                        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 23bcea7470df73a448338fae9f7767c6b5bd9a5c..5eceb5ee43308dcb940f6b0667133593568f98c1 100644 (file)
@@ -3160,8 +3160,8 @@ void drawinfospace(ScrArea *sa, void *spacedata)
        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];
@@ -3212,6 +3212,7 @@ void drawinfospace(ScrArea *sa, void *spacedata)
        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 */
@@ -3219,6 +3220,7 @@ void drawinfospace(ScrArea *sa, void *spacedata)
        y4label = y4-2;
        y5label = y5-2;
        y6label = y6-2;
+       y7label = y7-2;
 
 
        /* set the color to blue and draw the main 'tab' controls */
@@ -3810,8 +3812,13 @@ void drawinfospace(ScrArea *sa, void *spacedata)
 
 
                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, 
@@ -6274,7 +6281,7 @@ SpaceType *spaceaction_get_type(void)
        
        if (!st) {
                st= spacetype_new("Action");
-               spacetype_set_winfuncs(st, drawactionspace, changeactionspace, winqreadactionspace);
+               spacetype_set_winfuncs(st, NULL, drawactionspace, changeactionspace, winqreadactionspace);
        }
 
        return st;
@@ -6285,7 +6292,7 @@ SpaceType *spacebuts_get_type(void)
        
        if (!st) {
                st= spacetype_new("Buts");
-               spacetype_set_winfuncs(st, drawbutspace, changebutspace, winqreadbutspace);
+               spacetype_set_winfuncs(st, NULL, drawbutspace, changebutspace, winqreadbutspace);
        }
 
        return st;
@@ -6296,7 +6303,7 @@ SpaceType *spacefile_get_type(void)
        
        if (!st) {
                st= spacetype_new("File");
-               spacetype_set_winfuncs(st, drawfilespace, NULL, winqreadfilespace);
+               spacetype_set_winfuncs(st, NULL, drawfilespace, NULL, winqreadfilespace);
        }
 
        return st;
@@ -6307,7 +6314,7 @@ SpaceType *spaceimage_get_type(void)
        
        if (!st) {
                st= spacetype_new("Image");
-               spacetype_set_winfuncs(st, drawimagespace, changeimagepace, winqreadimagespace);
+               spacetype_set_winfuncs(st, NULL, drawimagespace, changeimagepace, winqreadimagespace);
        }
 
        return st;
@@ -6318,7 +6325,7 @@ SpaceType *spaceimasel_get_type(void)
        
        if (!st) {
                st= spacetype_new("Imasel");
-               spacetype_set_winfuncs(st, drawimaselspace, changeimaselspace, winqreadimaselspace);
+               spacetype_set_winfuncs(st, NULL, drawimaselspace, changeimaselspace, winqreadimaselspace);
        }
 
        return st;
@@ -6329,7 +6336,7 @@ SpaceType *spaceinfo_get_type(void)
        
        if (!st) {
                st= spacetype_new("Info");
-               spacetype_set_winfuncs(st, drawinfospace, NULL, winqreadinfospace);
+               spacetype_set_winfuncs(st, NULL, drawinfospace, NULL, winqreadinfospace);
        }
 
        return st;
@@ -6340,7 +6347,7 @@ SpaceType *spaceipo_get_type(void)
        
        if (!st) {
                st= spacetype_new("Ipo");
-               spacetype_set_winfuncs(st, drawipospace, changeview2dspace, winqreadipospace);
+               spacetype_set_winfuncs(st, NULL, drawipospace, changeview2dspace, winqreadipospace);
        }
 
        return st;
@@ -6351,7 +6358,7 @@ SpaceType *spacenla_get_type(void)
        
        if (!st) {
                st= spacetype_new("Nla");
-               spacetype_set_winfuncs(st, drawnlaspace, changeview2dspace, winqreadnlaspace);
+               spacetype_set_winfuncs(st, NULL, drawnlaspace, changeview2dspace, winqreadnlaspace);
        }
 
        return st;
@@ -6362,7 +6369,7 @@ SpaceType *spaceoops_get_type(void)
        
        if (!st) {
                st= spacetype_new("Oops");
-               spacetype_set_winfuncs(st, drawoopsspace, changeview2dspace, winqreadoopsspace);
+               spacetype_set_winfuncs(st, NULL, drawoopsspace, changeview2dspace, winqreadoopsspace);
        }
 
        return st;
@@ -6373,7 +6380,7 @@ SpaceType *spaceseq_get_type(void)
        
        if (!st) {
                st= spacetype_new("Sequence");
-               spacetype_set_winfuncs(st, drawseqspace, changeview2dspace, winqreadseqspace);
+               spacetype_set_winfuncs(st, drawprefetchseqspace, drawseqspace, changeview2dspace, winqreadseqspace);
        }
 
        return st;
@@ -6384,7 +6391,7 @@ SpaceType *spacesound_get_type(void)
        
        if (!st) {
                st= spacetype_new("Sound");
-               spacetype_set_winfuncs(st, drawsoundspace, changeview2dspace, winqreadsoundspace);
+               spacetype_set_winfuncs(st, NULL, drawsoundspace, changeview2dspace, winqreadsoundspace);
        }
 
        return st;
@@ -6395,7 +6402,7 @@ SpaceType *spacetext_get_type(void)
        
        if (!st) {
                st= spacetype_new("Text");
-               spacetype_set_winfuncs(st, drawtextspace, NULL, winqreadtextspace);
+               spacetype_set_winfuncs(st, NULL, drawtextspace, NULL, winqreadtextspace);
        }
 
        return st;
@@ -6419,7 +6426,7 @@ SpaceType *spacescript_get_type(void)
 
        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;
@@ -6430,7 +6437,7 @@ SpaceType *spaceview3d_get_type(void)
        
        if (!st) {
                st= spacetype_new("View3D");
-               spacetype_set_winfuncs(st, drawview3dspace, changeview3dspace, winqreadview3dspace);
+               spacetype_set_winfuncs(st, NULL, drawview3dspace, changeview3dspace, winqreadview3dspace);
        }
 
        return st;
@@ -6441,7 +6448,7 @@ SpaceType *spacetime_get_type(void)
        
        if (!st) {
                st= spacetype_new("Time");
-               spacetype_set_winfuncs(st, drawtimespace, NULL, winqreadtimespace);
+               spacetype_set_winfuncs(st, NULL, drawtimespace, NULL, winqreadtimespace);
        }
        
        return st;
@@ -6453,7 +6460,7 @@ SpaceType *spacenode_get_type(void)
        
        if (!st) {
                st= spacetype_new("Node");
-               spacetype_set_winfuncs(st, drawnodespace, changeview2dspace, winqreadnodespace);
+               spacetype_set_winfuncs(st, NULL, drawnodespace, changeview2dspace, winqreadnodespace);
        }
        
        return st;
index ea0d680e852ec67b494bb44b36bee9c89b6d9d4b..4a0375f2366d60437883b34b11addbb3a96d07fa 100644 (file)
@@ -52,6 +52,7 @@
 struct _SpaceType {
        char                    name[32];
        
+       SpacePrefetchDrawFP winprefetchdraw;
        SpaceDrawFP             windraw;
        SpaceChangeFP   winchange;
        SpaceHandleFP   winhandle;
@@ -70,8 +71,9 @@ SpaceType *spacetype_new(char *name)
        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 @@ static SpaceType *spacetype_from_area(ScrArea *area)
        }
 }
 
+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);