From 6f83710af94a9f6d117ef60537329941cd8614fa Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 5 May 2016 14:45:00 +0200 Subject: Optimize projection painting with big brushes Multi-threaded partial buffer update, gives about 2x speedup with big brushes. Thanks Campbell for testing and benchmarking! --- source/blender/imbuf/intern/divers.c | 87 ++++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 18 deletions(-) (limited to 'source/blender/imbuf') diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 455b78bce4d..3aabf7e18cc 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -674,25 +674,24 @@ void IMB_rect_from_float(ImBuf *ibuf) ibuf->userflags &= ~IB_RECT_INVALID; } -/* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */ -void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w, int h, bool is_data) -{ - const float *rect_float; +typedef struct PartialThreadData { + ImBuf *ibuf; + float *buffer; uchar *rect_byte; - int profile_from = IB_PROFILE_LINEAR_RGB; - - /* verify we have a float buffer */ - if (ibuf->rect_float == NULL || buffer == NULL) - return; - - /* create byte rect if it didn't exist yet */ - if (ibuf->rect == NULL) - imb_addrectImBuf(ibuf); - - /* do conversion */ - rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels; - rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4; - + const float *rect_float; + int width; + bool is_data; +} PartialThreadData; + +static void partial_rect_from_float_slice(float *buffer, + uchar *rect_byte, + ImBuf *ibuf, + const float *rect_float, + const int w, + const int h, + const bool is_data) +{ + const int profile_from = IB_PROFILE_LINEAR_RGB; if (is_data) { /* exception for non-color data, just copy float */ IMB_buffer_float_from_float(buffer, rect_float, @@ -715,6 +714,58 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w 4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0, w, h, ibuf->x, w); } +} + +static void partial_rect_from_float_thread_do(void *data_v, + int start_scanline, + int num_scanlines) +{ + PartialThreadData *data = (PartialThreadData *)data_v; + ImBuf *ibuf = data->ibuf; + size_t global_offset = ((size_t)ibuf->x) * start_scanline; + size_t local_offset = ((size_t)data->width) * start_scanline; + partial_rect_from_float_slice(data->buffer + local_offset * ibuf->channels, + data->rect_byte + global_offset * 4, + ibuf, + data->rect_float + global_offset * ibuf->channels, + data->width, + num_scanlines, + data->is_data); +} + +/* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */ +void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w, int h, bool is_data) +{ + const float *rect_float; + uchar *rect_byte; + + /* verify we have a float buffer */ + if (ibuf->rect_float == NULL || buffer == NULL) + return; + + /* create byte rect if it didn't exist yet */ + if (ibuf->rect == NULL) + imb_addrectImBuf(ibuf); + + /* do conversion */ + rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels; + rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4; + + if (((size_t)w) * h < 64 * 64) { + partial_rect_from_float_slice( + buffer, rect_byte, ibuf, rect_float, w, h, is_data); + } + else { + PartialThreadData data; + data.ibuf = ibuf; + data.buffer = buffer; + data.rect_byte = rect_byte; + data.rect_float = rect_float; + data.width = w; + data.is_data = is_data; + IMB_processor_apply_threaded_scanlines( + h, partial_rect_from_float_thread_do, &data); + } /* ensure user flag is reset */ ibuf->userflags &= ~IB_RECT_INVALID; -- cgit v1.2.3