Optimize projection painting with big brushes

Multi-threaded partial buffer update, gives about 2x speedup with
big brushes.

Thanks Campbell for testing and benchmarking!
This commit is contained in:
Sergey Sharybin 2016-05-05 14:45:00 +02:00
parent c81d9fda46
commit 6f83710af9
1 changed files with 68 additions and 17 deletions

View File

@ -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;