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. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org http://lists.blender.org/mailman/listinfo/bf-blender-cvs