Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2016-05-06 12:48:07 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2016-05-06 12:49:09 +0300
commitef0c02cb4dbd5f74fd0cb7c7ef119e4ca1936249 (patch)
tree1000d42908297b93b1f767209438bc88ef3f5f18 /source
parent204f55c189d7e7a7b7808b6730a285326e7ac38a (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.c112
-rw-r--r--source/blender/imbuf/IMB_imbuf.h17
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c81
-rw-r--r--source/blender/imbuf/intern/rectop.c63
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, &region[a], curveb, texmaskb, frombuf,
+ mask_max, blend, tilex, tiley, tilew, tileh);
}
+ else {
+ Paint2DForeachData data;
+ data.s = s;
+ data.region = &region[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])