[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