Sequencer: Speedup gaussian blur effect

Apply X and Y blur as separate step, this reduces number of accumulations
required and makes effect more realtime.

Another quick thing for the Nieve project.
This commit is contained in:
Sergey Sharybin 2016-01-22 00:11:37 +05:00
parent 7788681eda
commit 8cde671f8b
1 changed files with 311 additions and 131 deletions

View File

@ -2667,183 +2667,211 @@ static float *make_gaussian_blur_kernel(float rad, int size)
return gausstab;
}
static void do_gaussian_blur_effect_byte(Sequence *seq,
int start_line,
int x, int y,
int frame_width, int frame_height,
unsigned char *rect,
unsigned char *out)
static void do_gaussian_blur_effect_byte_x(Sequence *seq,
int start_line,
int x, int y,
int frame_width,
int UNUSED(frame_height),
unsigned char *rect,
unsigned char *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
GaussianBlurVars *data = seq->effectdata;
const int size_x = (int) (data->size_x + 0.5f);
const int size_y = (int) (data->size_y + 0.5f);
int i, j;
/* Make gaussian weight tabke. */
float *gausstab_x, *gausstab_y;
float *gausstab_x;
gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
if (data->size_x == data->size_y) {
gausstab_y = gausstab_x;
}
else {
gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
}
for (i = 0; i < y; ++i) {
for (j = 0; j < x; ++j) {
int out_index = INDEX(j, i);
int current_x, current_y;
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
for (current_y = i - size_y;
current_y <= i + size_y;
++current_y)
for (int current_x = j - size_x;
current_x <= j + size_x;
++current_x)
{
if (current_y < -start_line ||
current_y + start_line >= frame_height)
{
if (current_x < 0 || current_x >= frame_width) {
/* Out of bounds. */
continue;
}
for (current_x = j - size_x;
current_x <= j + size_x;
++current_x)
{
float weight;
int index = INDEX(current_x, current_y + start_line);
if (current_x < 0 || current_x >= frame_width) {
/* Out of bounds. */
continue;
}
BLI_assert(index >= 0);
BLI_assert(index < frame_width * frame_height * 4);
if (size_x != 0 && size_y != 0) {
weight = gausstab_x[current_x - j + size_x] *
gausstab_y[current_y - i + size_y];
}
else if (size_x == 0) {
weight = gausstab_y[current_y - i + size_y];
}
else {
weight = gausstab_x[current_x - j + size_x];
}
accum[0] += rect[index] * weight;
accum[1] += rect[index + 1] * weight;
accum[2] += rect[index + 2] * weight;
accum[3] += rect[index + 3] * weight;
accum_weight += weight;
}
int index = INDEX(current_x, i + start_line);
float weight = gausstab_x[current_x - j + size_x];
accum[0] += rect[index] * weight;
accum[1] += rect[index + 1] * weight;
accum[2] += rect[index + 2] * weight;
accum[3] += rect[index + 3] * weight;
accum_weight += weight;
}
out[out_index + 0] = accum[0] / accum_weight;
out[out_index + 1] = accum[1] / accum_weight;
out[out_index + 2] = accum[2] / accum_weight;
out[out_index + 3] = accum[3] / accum_weight;
float inv_accum_weight = 1.0f / accum_weight;
out[out_index + 0] = accum[0] * inv_accum_weight;
out[out_index + 1] = accum[1] * inv_accum_weight;
out[out_index + 2] = accum[2] * inv_accum_weight;
out[out_index + 3] = accum[3] * inv_accum_weight;
}
}
MEM_freeN(gausstab_x);
if (gausstab_x != gausstab_y) {
MEM_freeN(gausstab_y);
}
#undef INDEX
}
static void do_gaussian_blur_effect_float(Sequence *seq,
int start_line,
int x, int y,
int frame_width, int frame_height,
float *rect,
float *out)
static void do_gaussian_blur_effect_byte_y(Sequence *seq,
int start_line,
int x, int y,
int UNUSED(frame_width),
int frame_height,
unsigned char *rect,
unsigned char *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
GaussianBlurVars *data = seq->effectdata;
const int size_x = (int) (data->size_x + 0.5f);
const int size_y = (int) (data->size_y + 0.5f);
int i, j;
/* Make gaussian weight tabke. */
float *gausstab_x, *gausstab_y;
gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
if (data->size_x == data->size_y) {
gausstab_y = gausstab_x;
}
else {
gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
}
float *gausstab_y;
gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
for (i = 0; i < y; ++i) {
for (j = 0; j < x; ++j) {
int out_index = INDEX(j, i);
int current_x, current_y;
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
for (current_y = i - size_y;
for (int current_y = i - size_y;
current_y <= i + size_y;
++current_y)
{
float weight;
if (current_y < -start_line ||
current_y + start_line >= frame_height)
{
/* Out of bounds. */
continue;
}
int index = INDEX(j, current_y + start_line);
float weight = gausstab_y[current_y - i + size_y];
accum[0] += rect[index] * weight;
accum[1] += rect[index + 1] * weight;
accum[2] += rect[index + 2] * weight;
accum[3] += rect[index + 3] * weight;
accum_weight += weight;
}
float inv_accum_weight = 1.0f / accum_weight;
out[out_index + 0] = accum[0] * inv_accum_weight;
out[out_index + 1] = accum[1] * inv_accum_weight;
out[out_index + 2] = accum[2] * inv_accum_weight;
out[out_index + 3] = accum[3] * inv_accum_weight;
}
}
for (current_x = j - size_x;
current_x <= j + size_x;
++current_x)
{
int index = INDEX(current_x, current_y + start_line);
if (current_x < 0 || current_x >= frame_width) {
/* Out of bounds. */
continue;
}
MEM_freeN(gausstab_y);
#undef INDEX
}
if (size_x != 0 && size_y != 0) {
weight = gausstab_x[current_x - j + size_x] *
gausstab_y[current_y - i + size_y];
}
else if (size_x == 0) {
weight = gausstab_y[current_y - i + size_y];
}
else {
weight = gausstab_x[current_x - j + size_x];
}
madd_v4_v4fl(accum, &rect[index], weight);
accum_weight += weight;
static void do_gaussian_blur_effect_float_x(Sequence *seq,
int start_line,
int x, int y,
int frame_width,
int UNUSED(frame_height),
float *rect,
float *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
GaussianBlurVars *data = seq->effectdata;
const int size_x = (int) (data->size_x + 0.5f);
int i, j;
/* Make gaussian weight tabke. */
float *gausstab_x;
gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
for (i = 0; i < y; ++i) {
for (j = 0; j < x; ++j) {
int out_index = INDEX(j, i);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
for (int current_x = j - size_x;
current_x <= j + size_x;
++current_x)
{
if (current_x < 0 || current_x >= frame_width) {
/* Out of bounds. */
continue;
}
int index = INDEX(current_x, i + start_line);
float weight = gausstab_x[current_x - j + size_x];
madd_v4_v4fl(accum, &rect[index], weight);
accum_weight += weight;
}
mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight);
}
}
MEM_freeN(gausstab_x);
if (gausstab_x != gausstab_y) {
MEM_freeN(gausstab_y);
}
#undef INDEX
}
static void do_gaussian_blur_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(cfra),
float UNUSED(facf0),
float UNUSED(facf1),
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
int start_line,
int total_lines,
ImBuf *out)
static void do_gaussian_blur_effect_float_y(Sequence *seq,
int start_line,
int x, int y,
int UNUSED(frame_width),
int frame_height,
float *rect,
float *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
GaussianBlurVars *data = seq->effectdata;
const int size_y = (int) (data->size_y + 0.5f);
int i, j;
/* Make gaussian weight tabke. */
float *gausstab_y;
gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
for (i = 0; i < y; ++i) {
for (j = 0; j < x; ++j) {
int out_index = INDEX(j, i);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
for (int current_y = i - size_y;
current_y <= i + size_y;
++current_y)
{
if (current_y < -start_line ||
current_y + start_line >= frame_height)
{
/* Out of bounds. */
continue;
}
int index = INDEX(j, current_y + start_line);
float weight = gausstab_y[current_y - i + size_y];
madd_v4_v4fl(accum, &rect[index], weight);
accum_weight += weight;
}
mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight);
}
}
MEM_freeN(gausstab_y);
#undef INDEX
}
static void do_gaussian_blur_effect_x_cb(const SeqRenderData *context,
Sequence *seq,
ImBuf *ibuf,
int start_line,
int total_lines,
ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_float_buffers(context,
ibuf1, ibuf2,
ibuf,
NULL,
NULL,
out,
start_line,
@ -2852,20 +2880,21 @@ static void do_gaussian_blur_effect(const SeqRenderData *context,
NULL,
&rect_out);
do_gaussian_blur_effect_float(seq,
start_line,
context->rectx,
total_lines,
context->rectx,
context->recty,
ibuf1->rect_float,
rect_out);
do_gaussian_blur_effect_float_x(seq,
start_line,
context->rectx,
total_lines,
context->rectx,
context->recty,
ibuf->rect_float,
rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_byte_buffers(context,
ibuf1, ibuf2,
ibuf,
NULL,
NULL,
out,
start_line,
@ -2874,17 +2903,169 @@ static void do_gaussian_blur_effect(const SeqRenderData *context,
NULL,
&rect_out);
do_gaussian_blur_effect_byte(seq,
start_line,
context->rectx,
total_lines,
context->rectx,
context->recty,
(unsigned char *) ibuf1->rect,
rect_out);
do_gaussian_blur_effect_byte_x(seq,
start_line,
context->rectx,
total_lines,
context->rectx,
context->recty,
(unsigned char *) ibuf->rect,
rect_out);
}
}
static void do_gaussian_blur_effect_y_cb(const SeqRenderData *context,
Sequence *seq,
ImBuf *ibuf,
int start_line,
int total_lines,
ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_float_buffers(context,
ibuf,
NULL,
NULL,
out,
start_line,
&rect1,
&rect2,
NULL,
&rect_out);
do_gaussian_blur_effect_float_y(seq,
start_line,
context->rectx,
total_lines,
context->rectx,
context->recty,
ibuf->rect_float,
rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_byte_buffers(context,
ibuf,
NULL,
NULL,
out,
start_line,
&rect1,
&rect2,
NULL,
&rect_out);
do_gaussian_blur_effect_byte_y(seq,
start_line,
context->rectx,
total_lines,
context->rectx,
context->recty,
(unsigned char *) ibuf->rect,
rect_out);
}
}
typedef struct RenderGaussianBlurEffectInitData {
const SeqRenderData *context;
Sequence *seq;
ImBuf *ibuf;
ImBuf *out;
} RenderGaussianBlurEffectInitData;
typedef struct RenderGaussianBlurEffectThread {
const SeqRenderData *context;
Sequence *seq;
ImBuf *ibuf;
ImBuf *out;
int start_line, tot_line;
} RenderGaussianBlurEffectThread;
static void render_effect_execute_init_handle(void *handle_v,
int start_line,
int tot_line,
void *init_data_v)
{
RenderGaussianBlurEffectThread *handle = (RenderGaussianBlurEffectThread *) handle_v;
RenderGaussianBlurEffectInitData *init_data = (RenderGaussianBlurEffectInitData *) init_data_v;
handle->context = init_data->context;
handle->seq = init_data->seq;
handle->ibuf = init_data->ibuf;
handle->out = init_data->out;
handle->start_line = start_line;
handle->tot_line = tot_line;
}
static void *render_effect_execute_do_x_thread(void *thread_data_v)
{
RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v;
do_gaussian_blur_effect_x_cb(thread_data->context,
thread_data->seq,
thread_data->ibuf,
thread_data->start_line,
thread_data->tot_line,
thread_data->out);
return NULL;
}
static void *render_effect_execute_do_y_thread(void *thread_data_v)
{
RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v;
do_gaussian_blur_effect_y_cb(thread_data->context,
thread_data->seq,
thread_data->ibuf,
thread_data->start_line,
thread_data->tot_line,
thread_data->out);
return NULL;
}
static ImBuf* do_gaussian_blur_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(cfra),
float UNUSED(facf0),
float UNUSED(facf1),
ImBuf *ibuf1,
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3))
{
ImBuf *out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);
RenderGaussianBlurEffectInitData init_data;
init_data.context = context;
init_data.seq = seq;
init_data.ibuf = ibuf1;
init_data.out = out;
IMB_processor_apply_threaded(out->y,
sizeof(RenderGaussianBlurEffectThread),
&init_data,
render_effect_execute_init_handle,
render_effect_execute_do_x_thread);
ibuf1 = out;
init_data.ibuf = ibuf1;
out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);;
init_data.out = out;
IMB_processor_apply_threaded(out->y,
sizeof(RenderGaussianBlurEffectThread),
&init_data,
render_effect_execute_init_handle,
render_effect_execute_do_y_thread);
IMB_freeImBuf(ibuf1);
return out;
}
/*********************** text *************************/
static void init_text_effect(Sequence *seq)
{
@ -3215,13 +3396,12 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
rval.execute = do_adjustment;
break;
case SEQ_TYPE_GAUSSIAN_BLUR:
rval.multithreaded = true;
rval.init = init_gaussian_blur_effect;
rval.num_inputs = num_inputs_gaussian_blur;
rval.free = free_gaussian_blur_effect;
rval.copy = copy_gaussian_blur_effect;
rval.early_out = early_out_gaussian_blur;
rval.execute_slice = do_gaussian_blur_effect;
rval.execute = do_gaussian_blur_effect;
break;
case SEQ_TYPE_TEXT:
rval.num_inputs = num_inputs_text;