[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [55311] trunk/blender/source/blender: Further improvement for multi-threaded proxies

Sergey Sharybin sergey.vfx at gmail.com
Fri Mar 15 17:57:20 CET 2013


Revision: 55311
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=55311
Author:   nazgul
Date:     2013-03-15 16:57:19 +0000 (Fri, 15 Mar 2013)
Log Message:
-----------
Further improvement for multi-threaded proxies

Handle sequences in a special case for dealing with
sequence sources.

Namely handle separate frames in separate threads,
but do disk read from a critical section since HDD
is not so friendly with lots threads requesting for
data from it.

Makes proxy building much faster than it was before.

Modified Paths:
--------------
    trunk/blender/source/blender/blenkernel/BKE_movieclip.h
    trunk/blender/source/blender/blenkernel/intern/movieclip.c
    trunk/blender/source/blender/editors/space_clip/clip_ops.c

Modified: trunk/blender/source/blender/blenkernel/BKE_movieclip.h
===================================================================
--- trunk/blender/source/blender/blenkernel/BKE_movieclip.h	2013-03-15 16:16:11 UTC (rev 55310)
+++ trunk/blender/source/blender/blenkernel/BKE_movieclip.h	2013-03-15 16:57:19 UTC (rev 55311)
@@ -64,9 +64,14 @@
 void BKE_movieclip_build_proxy_frame(struct MovieClip *clip, int clip_flag, struct MovieDistortion *distortion,
                                      int cfra, int *build_sizes, int build_count, int undistorted);
 
+void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip, struct ImBuf *ibuf, struct MovieDistortion *distortion,
+                                              int cfra, int *build_sizes, int build_count, int undistorted);
+
 float BKE_movieclip_remap_scene_to_clip_frame(struct MovieClip *clip, float framenr);
 float BKE_movieclip_remap_clip_to_scene_frame(struct MovieClip *clip, float framenr);
 
+void BKE_movieclip_filename_for_frame(struct MovieClip *clip, int framenr, char *name);
+
 /* cacheing flags */
 #define MOVIECLIP_CACHE_SKIP        (1 << 0)
 

Modified: trunk/blender/source/blender/blenkernel/intern/movieclip.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/movieclip.c	2013-03-15 16:16:11 UTC (rev 55310)
+++ trunk/blender/source/blender/blenkernel/intern/movieclip.c	2013-03-15 16:57:19 UTC (rev 55311)
@@ -1230,7 +1230,7 @@
 	scopes->ok = TRUE;
 }
 
-static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, int proxy_render_size, int undistorted)
+static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, int proxy_render_size, int undistorted, bool threaded)
 {
 	char name[FILE_MAX];
 	int quality, rectx, recty;
@@ -1244,7 +1244,10 @@
 
 	scaleibuf = IMB_dupImBuf(ibuf);
 
-	IMB_scaleImBuf_threaded(scaleibuf, (short)rectx, (short)recty);
+	if (threaded)
+		IMB_scaleImBuf_threaded(scaleibuf, (short)rectx, (short)recty);
+	else
+		IMB_scaleImBuf(scaleibuf, (short)rectx, (short)recty);
 
 	quality = clip->proxy.quality;
 	scaleibuf->ftype = JPG | quality;
@@ -1253,6 +1256,10 @@
 	if (scaleibuf->planes == 32)
 		scaleibuf->planes = 24;
 
+	/* TODO: currently the most weak part of multithreaded proxies,
+	 *       could be solved in a way that thread only prepares memory
+	 *       buffer and write to disk happens separately
+	 */
 	BLI_lock_thread(LOCK_MOVIECLIP);
 
 	BLI_make_existing_file(name);
@@ -1264,6 +1271,9 @@
 	IMB_freeImBuf(scaleibuf);
 }
 
+/* note: currently used by proxy job for movies, threading happens within single frame
+ * (meaning scaling shall be threaded)
+ */
 void BKE_movieclip_build_proxy_frame(MovieClip *clip, int clip_flag, struct MovieDistortion *distortion,
                                      int cfra, int *build_sizes, int build_count, int undistorted)
 {
@@ -1287,7 +1297,7 @@
 			tmpibuf = get_undistorted_ibuf(clip, distortion, ibuf);
 
 		for (i = 0; i < build_count; i++)
-			movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted);
+			movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted, true);
 
 		IMB_freeImBuf(ibuf);
 
@@ -1296,6 +1306,30 @@
 	}
 }
 
+/* note: currently used by proxy job for sequences, threading happens within sequence
+ * (different threads handles different frames, no threading within frame is needed)
+ */
+void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, ImBuf *ibuf, struct MovieDistortion *distortion,
+                                              int cfra, int *build_sizes, int build_count, int undistorted)
+{
+	if (!build_count)
+		return;
+
+	if (ibuf) {
+		ImBuf *tmpibuf = ibuf;
+		int i;
+
+		if (undistorted)
+			tmpibuf = get_undistorted_ibuf(clip, distortion, ibuf);
+
+		for (i = 0; i < build_count; i++)
+			movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted, false);
+
+		if (tmpibuf != ibuf)
+			IMB_freeImBuf(tmpibuf);
+	}
+}
+
 void BKE_movieclip_free(MovieClip *clip)
 {
 	BKE_sequencer_clear_movieclip_in_clipboard(clip);
@@ -1384,3 +1418,14 @@
 {
 	return framenr + (float) clip->start_frame - 1.0f;
 }
+
+void BKE_movieclip_filename_for_frame(MovieClip *clip, int framenr, char *name)
+{
+	if (clip->source != MCLIP_SRC_MOVIE) {
+		get_sequence_fname(clip, framenr, name);
+	}
+	else {
+		BLI_strncpy(name, clip->name, FILE_MAX);
+		BLI_path_abs(name, ID_BLEND_PATH(G.main, &clip->id));
+	}
+}

Modified: trunk/blender/source/blender/editors/space_clip/clip_ops.c
===================================================================
--- trunk/blender/source/blender/editors/space_clip/clip_ops.c	2013-03-15 16:16:11 UTC (rev 55310)
+++ trunk/blender/source/blender/editors/space_clip/clip_ops.c	2013-03-15 16:57:19 UTC (rev 55311)
@@ -30,13 +30,22 @@
  */
 
 #include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
 
+#ifndef WIN32
+#  include <unistd.h>
+#else
+#  include <io.h>
+#endif
+
 #include "MEM_guardedalloc.h"
 
 #include "DNA_userdef_types.h"
 #include "DNA_scene_types.h"	/* min/max frames */
 
 #include "BLI_utildefines.h"
+#include "BLI_fileops.h"
 #include "BLI_path_util.h"
 #include "BLI_math.h"
 #include "BLI_rect.h"
@@ -972,49 +981,39 @@
 	return build_count;
 }
 
-/* only this runs inside thread */
-static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
+/* simple case for movies -- handle frame-by-frame, do threading within single frame */
+static void do_movie_proxy(void *pjv, int *UNUSED(build_sizes), int UNUSED(build_count),
+                           int *build_undistort_sizes, int build_undistort_count,
+                           short *stop, short *do_update, float *progress)
 {
 	ProxyJob *pj = pjv;
 	Scene *scene = pj->scene;
 	MovieClip *clip = pj->clip;
 	struct MovieDistortion *distortion = NULL;
-	short size_flag;
 	int cfra, sfra = SFRA, efra = EFRA;
-	int build_sizes[4], build_count = 0;
-	int build_undistort_sizes[4], build_undistort_count = 0;
 
-	size_flag = clip->proxy.build_size_flag;
+	if (pj->index_context)
+		IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress);
 
-	build_count = proxy_bitflag_to_array(size_flag, build_sizes, 0);
-	build_undistort_count = proxy_bitflag_to_array(size_flag, build_undistort_sizes, 1);
+	if (!build_undistort_count) {
+		if (*stop)
+			pj->stop = 1;
 
-	if (clip->source == MCLIP_SRC_MOVIE) {
-		if (pj->index_context)
-			IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress);
-
-		if (!build_undistort_count) {
-			if (*stop)
-				pj->stop = 1;
-
-			return;
-		}
-		else {
-			sfra = 1;
-			efra = IMB_anim_get_duration(clip->anim, IMB_TC_NONE);
-		}
+		return;
 	}
+	else {
+		sfra = 1;
+		efra = IMB_anim_get_duration(clip->anim, IMB_TC_NONE);
+	}
 
 	if (build_undistort_count) {
 		int threads = BLI_system_thread_count();
+
 		distortion = BKE_tracking_distortion_new();
 		BKE_tracking_distortion_set_threads(distortion, threads);
 	}
 
 	for (cfra = sfra; cfra <= efra; cfra++) {
-		if (clip->source != MCLIP_SRC_MOVIE)
-			BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, NULL, cfra, build_sizes, build_count, 0);
-
 		BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, distortion, cfra,
 		                                build_undistort_sizes, build_undistort_count, 1);
 
@@ -1032,6 +1031,193 @@
 		pj->stop = 1;
 }
 
+/* *****
+ * special case for sequences -- handle different frames in different threads,
+ * loading from disk happens in critical section, decoding frame happens from
+ * thread for maximal speed
+ */
+
+typedef struct ProxyQueue {
+	int cfra;
+	int sfra;
+	int efra;
+	SpinLock spin;
+
+	short *stop;
+	short *do_update;
+	float *progress;
+} ProxyQueue;
+
+typedef struct ProxyThread {
+	MovieClip *clip;
+	ProxyQueue *queue;
+
+	struct MovieDistortion *distortion;
+
+	int *build_sizes, build_count;
+	int *build_undistort_sizes, build_undistort_count;
+} ProxyThread;
+
+static unsigned char *proxy_thread_next_frame(ProxyQueue *queue, MovieClip *clip, size_t *size_r, int *cfra_r)
+{
+	unsigned char *mem = NULL;
+
+	BLI_spin_lock(&queue->spin);
+	if (!*queue->stop && queue->cfra <= queue->efra) {
+		char name[FILE_MAX];
+		size_t size;
+		int file;
+
+		BKE_movieclip_filename_for_frame(clip, queue->cfra, name);
+
+		file = open(name, O_BINARY | O_RDONLY, 0);
+		if (file < 0) {
+			BLI_spin_unlock(&queue->spin);
+			return NULL;
+		}
+
+		size = BLI_file_descriptor_size(file);
+		if (size < 1) {
+			close(file);
+			BLI_spin_unlock(&queue->spin);
+			return NULL;
+		}
+
+		mem = MEM_mallocN(size, "movieclip proxy memory file");
+
+		if (read(file, mem, size) != size) {
+			close(file);
+			BLI_spin_unlock(&queue->spin);
+			MEM_freeN(mem);
+			return NULL;
+		}
+
+		*size_r = size;
+		*cfra_r = queue->cfra;
+
+		queue->cfra++;
+		close(file);
+
+		*queue->do_update = 1;
+		*queue->progress = (float)(queue->cfra - queue->sfra) / (queue->efra - queue->sfra);
+	}
+	BLI_spin_unlock(&queue->spin);
+
+	return mem;
+}
+
+static void *do_proxy_thread(void *data_v)
+{
+	ProxyThread *data = (ProxyThread *) data_v;
+	unsigned char *mem;
+	size_t size;
+	int cfra;
+
+	while ((mem = proxy_thread_next_frame(data->queue, data->clip, &size, &cfra))) {
+		ImBuf *ibuf;
+
+		ibuf = IMB_ibImageFromMemory(mem, size, IB_rect | IB_multilayer | IB_alphamode_detect, NULL, "proxy frame");
+
+		BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, NULL, cfra,
+		                                         data->build_sizes, data->build_count, FALSE);
+
+		BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, data->distortion, cfra,
+		                                         data->build_undistort_sizes, data->build_undistort_count, TRUE);
+
+		IMB_freeImBuf(ibuf);
+
+		MEM_freeN(mem);
+	}
+
+	return NULL;
+}
+
+static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
+                              int *build_undistort_sizes, int build_undistort_count,
+							  short *stop, short *do_update, float *progress)
+{
+	ProxyJob *pj = pjv;
+	MovieClip *clip = pj->clip;
+	Scene *scene = pj->scene;
+	int sfra = SFRA, efra = EFRA;
+	ProxyThread *handles;
+	ListBase threads;
+	int i, tot_thread = BLI_system_thread_count();
+	ProxyQueue queue;
+
+	BLI_spin_init(&queue.spin);
+
+	queue.cfra = sfra;
+	queue.sfra = sfra;
+	queue.efra = efra;
+	queue.stop = stop;
+	queue.do_update = do_update;
+	queue.progress = progress;
+
+	handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles");
+
+	if (tot_thread > 1)

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list