diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2016-05-06 12:48:07 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2016-05-06 12:49:09 +0300 |
commit | ef0c02cb4dbd5f74fd0cb7c7ef119e4ca1936249 (patch) | |
tree | 1000d42908297b93b1f767209438bc88ef3f5f18 /source | |
parent | 204f55c189d7e7a7b7808b6730a285326e7ac38a (diff) |
Speedup of regular 2D painting
Yet another commit which makes painting aware of multi-threaded systems.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image_2d.c | 112 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_imbuf.h | 17 | ||||
-rw-r--r-- | source/blender/imbuf/intern/allocimbuf.c | 81 | ||||
-rw-r--r-- | source/blender/imbuf/intern/rectop.c | 63 |
4 files changed, 208 insertions, 65 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 59b50e28ce7..080bd5b73c7 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -42,6 +42,7 @@ #include "BLI_math_color_blend.h" #include "BLI_stack.h" #include "BLI_bitmap.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_depsgraph.h" @@ -1019,6 +1020,64 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[ ipos[1] = (int)floorf((pos[1] - ibufb->y / 2)); } +static void paint_2d_do_making_brush(ImagePaintState *s, + ImagePaintRegion *region, + unsigned short *curveb, + unsigned short *texmaskb, + ImBuf *frombuf, + float mask_max, + short blend, + int tilex, int tiley, + int tilew, int tileh) +{ + ImBuf tmpbuf; + IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); + + for (int ty = tiley; ty <= tileh; ty++) { + for (int tx = tilex; tx <= tilew; tx++) { + /* retrieve original pixels + mask from undo buffer */ + unsigned short *mask; + int origx = region->destx - tx * IMAPAINT_TILE_SIZE; + int origy = region->desty - ty * IMAPAINT_TILE_SIZE; + + if (s->canvas->rect_float) + tmpbuf.rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); + else + tmpbuf.rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); + + IMB_rectblend(s->canvas, &tmpbuf, frombuf, mask, + curveb, texmaskb, mask_max, + region->destx, region->desty, + origx, origy, + region->srcx, region->srcy, + region->width, region->height, + blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0)); + } + } +} + +typedef struct Paint2DForeachData { + ImagePaintState *s; + ImagePaintRegion *region; + unsigned short *curveb; + unsigned short *texmaskb; + ImBuf *frombuf; + float mask_max; + short blend; + int tilex; + int tilew; +} Paint2DForeachData; + +static void paint_2d_op_foreach_do(void *data_v, const int iter) +{ + Paint2DForeachData *data = (Paint2DForeachData *)data_v; + paint_2d_do_making_brush(data->s, data->region, data->curveb, + data->texmaskb, data->frombuf, data->mask_max, + data->blend, + data->tilex, iter, + data->tilew, iter); +} + static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2]) { ImagePaintState *s = ((ImagePaintState *)state); @@ -1072,45 +1131,40 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign if (s->do_masking) { /* masking, find original pixels tiles from undo buffer to composite over */ - int tilex, tiley, tilew, tileh, tx, ty; - ImBuf *tmpbuf; + int tilex, tiley, tilew, tileh; imapaint_region_tiles(s->canvas, region[a].destx, region[a].desty, region[a].width, region[a].height, &tilex, &tiley, &tilew, &tileh); - tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); - - for (ty = tiley; ty <= tileh; ty++) { - for (tx = tilex; tx <= tilew; tx++) { - /* retrieve original pixels + mask from undo buffer */ - unsigned short *mask; - int origx = region[a].destx - tx * IMAPAINT_TILE_SIZE; - int origy = region[a].desty - ty * IMAPAINT_TILE_SIZE; - - if (s->canvas->rect_float) - tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); - else - tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); - - IMB_rectblend(s->canvas, tmpbuf, frombuf, mask, - curveb, texmaskb, mask_max, - region[a].destx, region[a].desty, - origx, origy, - region[a].srcx, region[a].srcy, - region[a].width, region[a].height, blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0)); - } + if (tiley == tileh) { + paint_2d_do_making_brush(s, ®ion[a], curveb, texmaskb, frombuf, + mask_max, blend, tilex, tiley, tilew, tileh); } + else { + Paint2DForeachData data; + data.s = s; + data.region = ®ion[a]; + data.curveb = curveb; + data.texmaskb = texmaskb; + data.frombuf = frombuf; + data.mask_max = mask_max; + data.blend = blend; + data.tilex = tilex; + data.tilew = tilew; + BLI_task_parallel_range(tiley, tileh + 1, &data, + paint_2d_op_foreach_do, + true); - IMB_freeImBuf(tmpbuf); + } } else { /* no masking, composite brush directly onto canvas */ - IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max, - region[a].destx, region[a].desty, - region[a].destx, region[a].desty, - region[a].srcx, region[a].srcy, - region[a].width, region[a].height, blend, false); + IMB_rectblend_threaded(s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max, + region[a].destx, region[a].desty, + region[a].destx, region[a].desty, + region[a].srcx, region[a].srcy, + region[a].width, region[a].height, blend, false); } } diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 383a5f19c4a..93d2b3e0cd0 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -130,7 +130,18 @@ void IMB_freeImBuf(struct ImBuf *ibuf); * \attention Defined in allocimbuf.c */ struct ImBuf *IMB_allocImBuf(unsigned int x, unsigned int y, - unsigned char d, unsigned int flags); + unsigned char planes, unsigned int flags); + +/** + * Initialize given ImBuf. + * + * Use in cases when temporary image buffer is allocated on stack. + * + * \attention Defined in allocimbuf.c + */ +bool IMB_initImBuf(struct ImBuf *ibuf, + unsigned int x, unsigned int y, + unsigned char planes, unsigned int flags); /** * Create a copy of a pixel buffer and wrap it to a new ImBuf @@ -213,6 +224,10 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf, unsigned short *dmask, unsigned short *curvemask, unsigned short *mmask, float mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, IMB_BlendMode mode, bool accumulate); +void IMB_rectblend_threaded(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf, + unsigned short *dmask, unsigned short *curvemask, unsigned short *mmask, float mask_max, + int destx, int desty, int origx, int origy, int srcx, int srcy, + int width, int height, IMB_BlendMode mode, bool accumulate); /** * diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 988f43ff9fa..ef3743d9c8a 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -446,49 +446,60 @@ ImBuf *IMB_allocImBuf(unsigned int x, unsigned int y, uchar planes, unsigned int { ImBuf *ibuf; - ibuf = MEM_callocN(sizeof(ImBuf), "ImBuf_struct"); + ibuf = MEM_mallocN(sizeof(ImBuf), "ImBuf_struct"); if (ibuf) { - ibuf->x = x; - ibuf->y = y; - ibuf->planes = planes; - ibuf->ftype = IMB_FTYPE_PNG; - ibuf->foptions.quality = 15; /* the 15 means, set compression to low ratio but not time consuming */ - ibuf->channels = 4; /* float option, is set to other values when buffers get assigned */ - ibuf->ppm[0] = ibuf->ppm[1] = IMB_DPI_DEFAULT / 0.0254f; /* IMB_DPI_DEFAULT -> pixels-per-meter */ - - if (flags & IB_rect) { - if (imb_addrectImBuf(ibuf) == false) { - IMB_freeImBuf(ibuf); - return NULL; - } + if (!IMB_initImBuf(ibuf, x, y, planes, flags)) { + IMB_freeImBuf(ibuf); + return NULL; } - - if (flags & IB_rectfloat) { - if (imb_addrectfloatImBuf(ibuf) == false) { - IMB_freeImBuf(ibuf); - return NULL; - } + } + + return (ibuf); +} + +bool IMB_initImBuf(struct ImBuf *ibuf, + unsigned int x, unsigned int y, + unsigned char planes, unsigned int flags) +{ + memset(ibuf, 0, sizeof(ImBuf)); + + ibuf->x = x; + ibuf->y = y; + ibuf->planes = planes; + ibuf->ftype = IMB_FTYPE_PNG; + ibuf->foptions.quality = 15; /* the 15 means, set compression to low ratio but not time consuming */ + ibuf->channels = 4; /* float option, is set to other values when buffers get assigned */ + ibuf->ppm[0] = ibuf->ppm[1] = IMB_DPI_DEFAULT / 0.0254f; /* IMB_DPI_DEFAULT -> pixels-per-meter */ + + if (flags & IB_rect) { + if (imb_addrectImBuf(ibuf) == false) { + return false; } - - if (flags & IB_zbuf) { - if (addzbufImBuf(ibuf) == false) { - IMB_freeImBuf(ibuf); - return NULL; - } + } + + if (flags & IB_rectfloat) { + if (imb_addrectfloatImBuf(ibuf) == false) { + return false; } - - if (flags & IB_zbuffloat) { - if (addzbuffloatImBuf(ibuf) == false) { - IMB_freeImBuf(ibuf); - return NULL; - } + } + + if (flags & IB_zbuf) { + if (addzbufImBuf(ibuf) == false) { + return false; } + } - /* assign default spaces */ - colormanage_imbuf_set_default_spaces(ibuf); + if (flags & IB_zbuffloat) { + if (addzbuffloatImBuf(ibuf) == false) { + return false; + } } - return (ibuf); + + /* assign default spaces */ + colormanage_imbuf_set_default_spaces(ibuf); + + return true; } /* does no zbuffers? */ diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index c7b347cb20c..3360fd7548e 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -693,6 +693,69 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, } } +typedef struct RectBlendThreadData { + ImBuf *dbuf, *obuf, *sbuf; + unsigned short *dmask, *curvemask, *texmask; + float mask_max; + int destx, desty, origx, origy; + int srcx, srcy, width; + IMB_BlendMode mode; + bool accumulate; +} RectBlendThreadData; + +static void rectblend_thread_do(void *data_v, + int start_scanline, + int num_scanlines) +{ + RectBlendThreadData *data = (RectBlendThreadData *)data_v; + IMB_rectblend(data->dbuf, data->obuf, data->sbuf, + data->dmask, data->curvemask, data->texmask, + data->mask_max, + data->destx, + data->desty + start_scanline, + data->origx, + data->origy + start_scanline, + data->srcx, + data->srcy + start_scanline, + data->width, num_scanlines, + data->mode, data->accumulate); +} + +void IMB_rectblend_threaded(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, + unsigned short *dmask, unsigned short *curvemask, + unsigned short *texmask, float mask_max, + int destx, int desty, int origx, int origy, + int srcx, int srcy, int width, int height, + IMB_BlendMode mode, bool accumulate) +{ + if (((size_t)width) * height < 64 * 64) { + IMB_rectblend(dbuf, obuf, sbuf, dmask, curvemask, texmask, + mask_max, destx, desty, origx, origy, + srcx, srcy, width, height, mode, accumulate); + } + else { + RectBlendThreadData data; + data.dbuf = dbuf; + data.obuf = obuf; + data.sbuf = sbuf; + data.dmask = dmask; + data.curvemask = curvemask; + data.texmask = texmask; + data.mask_max = mask_max; + data.destx = destx; + data.desty = desty; + data.origx = origx; + data.origy = origy; + data.srcx = srcx; + data.srcy = srcy; + data.width = width; + data.mode = mode; + data.accumulate = accumulate; + IMB_processor_apply_threaded_scanlines( + height, rectblend_thread_do, &data); + } +} + /* fill */ void IMB_rectfill(ImBuf *drect, const float col[4]) |