Speedup of regular 2D painting
Yet another commit which makes painting aware of multi-threaded systems.
This commit is contained in:
parent
204f55c189
commit
ef0c02cb4d
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -446,51 +446,62 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & IB_zbuf) {
|
||||
if (addzbufImBuf(ibuf) == false) {
|
||||
IMB_freeImBuf(ibuf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & IB_zbuffloat) {
|
||||
if (addzbuffloatImBuf(ibuf) == false) {
|
||||
IMB_freeImBuf(ibuf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* assign default spaces */
|
||||
colormanage_imbuf_set_default_spaces(ibuf);
|
||||
}
|
||||
|
||||
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_rectfloat) {
|
||||
if (imb_addrectfloatImBuf(ibuf) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & IB_zbuf) {
|
||||
if (addzbufImBuf(ibuf) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & IB_zbuffloat) {
|
||||
if (addzbuffloatImBuf(ibuf) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* assign default spaces */
|
||||
colormanage_imbuf_set_default_spaces(ibuf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* does no zbuffers? */
|
||||
ImBuf *IMB_dupImBuf(ImBuf *ibuf1)
|
||||
{
|
||||
|
|
|
@ -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])
|
||||
|
|
Loading…
Reference in New Issue