Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Schlaile <peter@schlaile.de>2007-10-01 12:03:11 +0400
committerPeter Schlaile <peter@schlaile.de>2007-10-01 12:03:11 +0400
commit5b1d6690068876843c5bec284056b17db3af9f0b (patch)
tree9a49117282c1ab016189a2aedcc388a69956c2c9 /source/blender/src/sequence.c
parent2182f53a9a5e69c76d9efbbee46134935df242a6 (diff)
== Sequencer ==
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...
Diffstat (limited to 'source/blender/src/sequence.c')
-rw-r--r--source/blender/src/sequence.c325
1 files changed, 323 insertions, 2 deletions
diff --git a/source/blender/src/sequence.c b/source/blender/src/sequence.c
index aad0ebf5c5f..333f3d24e6e 100644
--- a/source/blender/src/sequence.c
+++ b/source/blender/src/sequence.c
@@ -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 "