[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17419] branches/projection-paint/source/ blender/src/imagepaint.c: Option to have painting multi-threaded.

Campbell Barton ideasman42 at gmail.com
Wed Nov 12 06:56:39 CET 2008


Revision: 17419
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17419
Author:   campbellbarton
Date:     2008-11-12 06:56:37 +0100 (Wed, 12 Nov 2008)

Log Message:
-----------
Option to have painting multi-threaded.
Each thread process the next free bucket the brush is over until they are all done.

Modified Paths:
--------------
    branches/projection-paint/source/blender/src/imagepaint.c

Modified: branches/projection-paint/source/blender/src/imagepaint.c
===================================================================
--- branches/projection-paint/source/blender/src/imagepaint.c	2008-11-11 23:24:10 UTC (rev 17418)
+++ branches/projection-paint/source/blender/src/imagepaint.c	2008-11-12 05:56:37 UTC (rev 17419)
@@ -49,6 +49,7 @@
 #include "BLI_linklist.h"
 #include "BLI_memarena.h"
 #include "PIL_time.h"
+#include "BLI_threads.h"
 
 #include "IMB_imbuf.h"
 #include "IMB_imbuf_types.h"
@@ -138,6 +139,7 @@
 //#define PROJ_DEBUG_PAINT 1
 #define PROJ_DEBUG_NOSCANLINE 1
 //#define PROJ_DEBUG_NOSEAMBLEED 1
+//#define PROJ_DEBUG_PRINT_THREADS 1
 
 /* projectFaceSeamFlags options */
 //#define PROJ_FACE_IGNORE	1<<0	/* When the face is hidden, backfacing or occluded */
@@ -178,6 +180,7 @@
 	
 	/* projection painting only */
 	MemArena *projectArena;			/* use for alocating many pixel structs and link-lists */
+	MemArena *projectArena_mt[BLENDER_MAX_THREADS];		/* Same as above but use for multithreading */
 	LinkNode **projectBuckets;		/* screen sized 2D array, each pixel has a linked list of ProjectPixel's */
 	LinkNode **projectFaces;		/* projectBuckets alligned array linkList of faces overlapping each bucket */
 	char *projectBucketFlags;		/* store if the bucks have been initialized  */
@@ -193,7 +196,6 @@
 	ImBuf **projectImBufs;			/* array of imbufs we are painting onto while, use so we can get the rect and rect_float quickly */
 	
 	int projectImageTotal;			/* size of projectImages array */
-	int imaContextIndex;			/* current image, use for context switching */
 	
 	float (*projectVertScreenCos)[4];	/* verts projected into floating point screen space */
 	
@@ -216,6 +218,12 @@
 	float viewMax2D[2]; 
 	float viewWidth;			/* Calculated from viewMin2D & viewMax2D */
 	float viewHeight;
+	
+	/* threads */
+	int thread_tot;
+	int min_bucket[2];
+	int max_bucket[2];
+	int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
 } ProjectPaintState;
 
 #ifndef PROJ_DEBUG_NOSCANLINE
@@ -1201,6 +1209,8 @@
 /* 
  * Be tricky with flags, first 4 bits are PROJ_FACE_SEAM1 to 4, last 4 bits are PROJ_FACE_NOSEAM1 to 4
  * 1<<i - where i is (0-3) 
+ * 
+ * If we're multithreadng, make sure threads are locked when this is called
  */
 static void project_face_seams_init(ProjectPaintState *ps, int face_index, int is_quad)
 {
@@ -1280,7 +1290,7 @@
 /* Only run this function once for new ProjectPixelClone's */
 #define pixel_size 4
 
-static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, int x, int y, int bucket_index, int face_index, float pixelScreenCo[4])
+static void project_paint_uvpixel_init(ProjectPaintState *ps, int thread_index, ImBuf *ibuf, int x, int y, int bucket_index, int face_index, int image_index, float pixelScreenCo[4])
 {
 	ProjectPixel *projPixel;
 	short size;
@@ -1308,7 +1318,7 @@
 			size = sizeof(ProjectPixel);
 		}
 		
-		projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->projectArena, size);
+		projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->projectArena_mt[thread_index], size);
 		
 		if (ibuf->rect_float) {
 			projPixel->pixel = (void *) ((( float * ) ibuf->rect_float) + (( x + y * ibuf->x ) * pixel_size));
@@ -1345,12 +1355,12 @@
 		if (ibuf->rect_float)	((float *)projPixel->pixel)[1] = 0;
 		else					((char *)projPixel->pixel)[1] = 0;
 #endif
-		projPixel->image_index = ps->imaContextIndex;
+		projPixel->image_index = image_index;
 		
 		BLI_linklist_prepend_arena(
 			&ps->projectBuckets[ bucket_index ],
 			projPixel,
-			ps->projectArena
+			ps->projectArena_mt[thread_index]
 		);
 	}
 }
@@ -1493,9 +1503,51 @@
 	VecAddf(insetCos[2], insetCos[2], cent);
 }
 
-/**/
-static void project_paint_face_init(ProjectPaintState *ps, int bucket_index, int face_index, float bucket_bounds[4], ImBuf *ibuf)
+static void rect_to_uvspace(
+		ProjectPaintState *ps, float bucket_bounds[4],
+		float *v1coSS, float *v2coSS, float *v3coSS,
+		float *uv1co, float *uv2co, float *uv3co,
+		float bucket_bounds_uv[4][2]
+	)
 {
+	float uv[2];
+	float w[3];
+	
+	/* get the UV space bounding box */
+	uv[0] = bucket_bounds[PROJ_BUCKET_RIGHT];
+	uv[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
+	if (ps->projectIsOrtho)	BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);	
+	else					BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);	
+	bucket_bounds_uv[0][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+	bucket_bounds_uv[0][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
+	
+	//uv[0] = bucket_bounds[PROJ_BUCKET_RIGHT]; // set above
+	uv[1] = bucket_bounds[PROJ_BUCKET_TOP];
+	if (ps->projectIsOrtho)	BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+	else					BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
+	bucket_bounds_uv[1][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+	bucket_bounds_uv[1][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
+	
+	
+	uv[0] = bucket_bounds[PROJ_BUCKET_LEFT];
+	//uv[1] = bucket_bounds[PROJ_BUCKET_TOP]; // set above
+	if (ps->projectIsOrtho)	BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+	else			BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
+	bucket_bounds_uv[2][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+	bucket_bounds_uv[2][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
+	
+	//uv[0] = bucket_bounds[PROJ_BUCKET_LEFT]; // set above
+	uv[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
+	if (ps->projectIsOrtho)	BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+	else					BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
+	bucket_bounds_uv[3][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+	bucket_bounds_uv[3][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];	
+}
+
+
+/* initialize pixels from this face where it intersects with the bucket_index, initialize pixels for removing seams */
+static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int bucket_index, int face_index, int image_index, float bucket_bounds[4], ImBuf *ibuf)
+{
 	/* Projection vars, to get the 3D locations into screen space  */
 	
 	MFace *mf = ps->dm_mface + face_index;
@@ -1508,7 +1560,7 @@
 	
 	int min_px[2], max_px[2]; /* UV Bounds converted to int's for pixel */
 	int min_px_tf[2], max_px_tf[2]; /* UV Bounds converted to int's for pixel */
-	int min_px_bucket[2][2], max_px_bucket[2][2]; /* Bucket Bounds converted to int's for pixel */
+	int min_px_bucket[2], max_px_bucket[2]; /* Bucket Bounds converted to int's for pixel */
 	float *v1coSS, *v2coSS, *v3coSS, *v4coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
 	float *v1co, *v2co, *v3co; /* vert co */
 	float *vCo[4]; /* vertex screenspace coords */
@@ -1551,43 +1603,15 @@
 		v2coSS = ps->projectVertScreenCos[ (*(&mf->v1 + i2)) ];
 		v3coSS = ps->projectVertScreenCos[ (*(&mf->v1 + i3)) ];
 		
-		/* get the UV space bounding box */
-		uv[0] = bucket_bounds[PROJ_BUCKET_RIGHT];
-		uv[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
-		if (ps->projectIsOrtho)	BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);	
-		else					BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);	
-		bucket_bounds_uv[0][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
-		bucket_bounds_uv[0][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
+		rect_to_uvspace(ps, bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv);
 		
-		//uv[0] = bucket_bounds[PROJ_BUCKET_RIGHT]; // set above
-		uv[1] = bucket_bounds[PROJ_BUCKET_TOP];
-		if (ps->projectIsOrtho)	BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
-		else					BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
-		bucket_bounds_uv[1][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
-		bucket_bounds_uv[1][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
-		
-		
-		uv[0] = bucket_bounds[PROJ_BUCKET_LEFT];
-		//uv[1] = bucket_bounds[PROJ_BUCKET_TOP]; // set above
-		if (ps->projectIsOrtho)	BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
-		else			BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
-		bucket_bounds_uv[2][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
-		bucket_bounds_uv[2][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
-		
-		//uv[0] = bucket_bounds[PROJ_BUCKET_LEFT]; // set above
-		uv[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
-		if (ps->projectIsOrtho)	BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
-		else					BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
-		bucket_bounds_uv[3][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
-		bucket_bounds_uv[3][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
-		
 		//printf("Bounds: %f | %f | %f | %f\n", bucket_bounds[0], bucket_bounds[1], bucket_bounds[2], bucket_bounds[3]);
 
 		if (	uv_image_rect(uv1co, uv2co, uv3co, NULL, min_px_tf, max_px_tf, ibuf->x, ibuf->y, 0) && 
-				uv_image_rect(bucket_bounds_uv[0], bucket_bounds_uv[1], bucket_bounds_uv[2], bucket_bounds_uv[3], min_px_bucket[i], max_px_bucket[i], ibuf->x, ibuf->y, 1) )
+				uv_image_rect(bucket_bounds_uv[0], bucket_bounds_uv[1], bucket_bounds_uv[2], bucket_bounds_uv[3], min_px_bucket, max_px_bucket, ibuf->x, ibuf->y, 1) )
 		{
 			
-			uvpixel_rect_intersect(min_px, max_px, min_px_bucket[i], max_px_bucket[i], min_px_tf, max_px_tf);
+			uvpixel_rect_intersect(min_px, max_px, min_px_bucket, max_px_bucket, min_px_tf, max_px_tf);
 			
 			/* clip face and */
 
@@ -1607,7 +1631,7 @@
 							screen_px_from_persp(ps, uv, vCo[i1],vCo[i2],vCo[i3], uv1co,uv2co,uv3co, pixelScreenCo);
 						}
 						
-						project_paint_uvpixel_init(ps, ibuf, x,y, bucket_index, face_index, pixelScreenCo);
+						project_paint_uvpixel_init(ps, thread_index, ibuf, x,y, bucket_index, face_index, image_index, pixelScreenCo);
 					}
 				}
 			}
@@ -1615,21 +1639,30 @@
 	} while(i--);
 #ifndef PROJ_DEBUG_NOSEAMBLEED
 	if (ps->projectSeamBleed > 0.0) {
+		int face_seam_flag;
 		
-		int flag = ps->projectFaceSeamFlags[face_index];
+		if (ps->thread_tot > 1)
+			BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
 		
+		face_seam_flag = ps->projectFaceSeamFlags[face_index];
+		
 		/* are any of our edges un-initialized? */
-		if ((flag & (PROJ_FACE_SEAM1|PROJ_FACE_NOSEAM1))==0 || 
-			(flag & (PROJ_FACE_SEAM2|PROJ_FACE_NOSEAM2))==0 || 
-			(flag & (PROJ_FACE_SEAM3|PROJ_FACE_NOSEAM3))==0 || 
-			(flag & (PROJ_FACE_SEAM4|PROJ_FACE_NOSEAM4))==0
+		if ((face_seam_flag & (PROJ_FACE_SEAM1|PROJ_FACE_NOSEAM1))==0 || 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list