From 98752e51da4cb376b5f82270856ac9f42fb6e1a3 Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Fri, 23 Apr 2010 20:06:48 +0200 Subject: [PATCH] [423/906] convolution: generate gaussian kernel on the fly Generate a normalized gaussian kernel with given size and standard deviation on the fly. Remove "norm_const" uniform from convolution shaders and provide a normalized kernel instead. Remove norm_offset uniform as it was always zero, will reintroduce it if really needed in the future. Thanks to Eric Anholt for suggesting it. Save some ALU instruction calculating directly the coordinate for texture lookup instead of summing an offset. Still exceed maximum indirect texture lookups on i915, the only solution I see is using a 3x3 kernel. --- gst/gl/effects/gstgleffectglow.c | 20 ++++------ gst/gl/effects/gstgleffectssources.c | 56 +++++++++++++++++++--------- gst/gl/effects/gstgleffectssources.h | 2 + gst/gl/effects/gstgleffectxray.c | 18 ++++----- gst/gl/gstgldifferencematte.c | 39 ++++++------------- gst/gl/gstgldifferencematte.h | 1 + gst/gl/gstglfilterblur.c | 30 +++------------ gst/gl/gstglfilterblur.h | 1 + 8 files changed, 74 insertions(+), 93 deletions(-) diff --git a/gst/gl/effects/gstgleffectglow.c b/gst/gl/effects/gstgleffectglow.c index 49302497be..d6422e6c2f 100644 --- a/gst/gl/effects/gstgleffectglow.c +++ b/gst/gl/effects/gstgleffectglow.c @@ -20,10 +20,8 @@ #include -static gfloat gauss_kernel[9] = { 0.060493f, 0.075284f, 0.088016f, - 0.096667f, 0.099736f, 0.096667f, - 0.088016f, 0.075284f, 0.060493f -}; +static gboolean kernel_ready = FALSE; +static float gauss_kernel[9]; static void gst_gl_effects_glow_step_one (gint width, gint height, guint texture, @@ -64,9 +62,6 @@ gst_gl_effects_glow_step_two (gint width, gint height, guint texture, GstGLEffects *effects = GST_GL_EFFECTS (stuff); GstGLShader *shader; - /* hard coded kernel, it could be easily generated at runtime with a - * property to change standard deviation */ - shader = g_hash_table_lookup (effects->shaderstable, "glow1"); if (!shader) { @@ -74,6 +69,11 @@ gst_gl_effects_glow_step_two (gint width, gint height, guint texture, g_hash_table_insert (effects->shaderstable, "glow1", shader); } + if (!kernel_ready) { + fill_gaussian_kernel (gauss_kernel, 9, 10.0); + kernel_ready = TRUE; + } + g_return_if_fail (gst_gl_shader_compile_and_check (shader, hconv9_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)); @@ -88,10 +88,7 @@ gst_gl_effects_glow_step_two (gint width, gint height, guint texture, glDisable (GL_TEXTURE_RECTANGLE_ARB); gst_gl_shader_set_uniform_1i (shader, "tex", 1); - gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel); - gst_gl_shader_set_uniform_1f (shader, "norm_const", 0.740656f); - gst_gl_shader_set_uniform_1f (shader, "norm_offset", 0.0f); gst_gl_effects_draw_texture (effects, texture); } @@ -124,10 +121,7 @@ gst_gl_effects_glow_step_three (gint width, gint height, guint texture, glDisable (GL_TEXTURE_RECTANGLE_ARB); gst_gl_shader_set_uniform_1i (shader, "tex", 1); - gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel); - gst_gl_shader_set_uniform_1f (shader, "norm_const", 0.740656f); - gst_gl_shader_set_uniform_1f (shader, "norm_offset", 0.0f); gst_gl_effects_draw_texture (effects, texture); } diff --git a/gst/gl/effects/gstgleffectssources.c b/gst/gl/effects/gstgleffectssources.c index 9ed7560798..4defe95458 100644 --- a/gst/gl/effects/gstgleffectssources.c +++ b/gst/gl/effects/gstgleffectssources.c @@ -20,6 +20,7 @@ #include #include +#include /* A common file for sources is needed since shader sources can be * generic and reused by several effects */ @@ -28,6 +29,33 @@ /* Move sooner or later into single .frag .vert files and either bake * them into a c file at compile time or load them at run time */ + +/* fill a normalized and zero centered gaussian vector for separable + * gaussian convolution */ + +void +fill_gaussian_kernel (float *kernel, int size, float sigma) +{ + int i; + float sum; + int l; + + /* need an odd sized vector to center it at zero */ + g_return_if_fail ((size % 2) != 0); + + sum = 0.0; + l = (size - 1) / 2.0; + + for (i = 0; i < size; i++) { + kernel[i] = exp (-pow ((i - l), 2.0) / (2 * sigma)); + sum += kernel[i]; + } + + for (i = 0; i < size; i++) { + kernel[i] /= sum; + } +} + /* *INDENT-OFF* */ /* Vertex shader */ @@ -276,44 +304,36 @@ const gchar *sobel_fragment_source = const gchar *hconv9_fragment_source = "#extension GL_ARB_texture_rectangle : enable\n" "uniform sampler2DRect tex;" - "uniform float norm_const;" - "uniform float norm_offset;" "uniform float kernel[9];" "void main () {" -/* "float offset[9] = float[9] (-4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0);" */ -/* don't use array constructor so we don't have to depend on #version 120 */ - " float offset = - 4.0;" " vec2 texturecoord = gl_TexCoord[0].st;" + " texturecoord.s -= 4.0;" " int i;" " vec4 sum = vec4 (0.0);" " for (i = 0; i < 9; i++) { " - " ++offset;" - " vec4 neighbor = texture2DRect(tex, vec2(texturecoord.s+offset, texturecoord.t)); " - " sum += neighbor * kernel[i]/norm_const; " + " vec4 neighbor = texture2DRect(tex, texturecoord); " + " ++texturecoord.s;" + " sum += neighbor * kernel[i];" " }" - " gl_FragColor = sum + norm_offset;" + " gl_FragColor = sum;" "}"; /* vertical convolution */ const gchar *vconv9_fragment_source = "#extension GL_ARB_texture_rectangle : enable\n" "uniform sampler2DRect tex;" - "uniform float norm_const;" - "uniform float norm_offset;" "uniform float kernel[9];" "void main () {" -/* "float offset[9] = float[9] (-4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0);" */ -/* don't use array constructor so we don't have to depend on #version 120 */ - " float offset = - 4.0;" " vec2 texturecoord = gl_TexCoord[0].st;" + " texturecoord.t -= 4.0;" " int i;" " vec4 sum = vec4 (0.0);" " for (i = 0; i < 9; i++) { " - " ++offset;" - " vec4 neighbor = texture2DRect(tex, vec2(texturecoord.s, texturecoord.t+offset)); " - " sum += neighbor * kernel[i]/norm_const; " + " vec4 neighbor = texture2DRect(tex, texturecoord); " + " ++texturecoord.t;" + " sum += neighbor * kernel[i]; " " }" - " gl_FragColor = sum + norm_offset;" + " gl_FragColor = sum;" "}"; diff --git a/gst/gl/effects/gstgleffectssources.h b/gst/gl/effects/gstgleffectssources.h index c93c59b3eb..20bc991756 100644 --- a/gst/gl/effects/gstgleffectssources.h +++ b/gst/gl/effects/gstgleffectssources.h @@ -44,4 +44,6 @@ extern const gchar *texture_interp_fragment_source; extern const gchar *difference_fragment_source; extern const gchar *multiply_fragment_source; +void fill_gaussian_kernel (float *kernel, int size, float sigma); + #endif /* __GST_GL_EFFECTS_SOURCES_H__ */ diff --git a/gst/gl/effects/gstgleffectxray.c b/gst/gl/effects/gstgleffectxray.c index d0868436a2..d5f9e16d7e 100644 --- a/gst/gl/effects/gstgleffectxray.c +++ b/gst/gl/effects/gstgleffectxray.c @@ -22,11 +22,8 @@ #include #include -/* Gaussian Kernel: std = 1.200000, size = 9x1 */ -static gfloat gauss_kernel[9] = { 0.001285f, 0.014607f, 0.082898f, - 0.234927f, 0.332452f, 0.234927f, - 0.082898f, 0.014607f, 0.001285f -}; +static gboolean kernel_ready = FALSE; +static float gauss_kernel[9]; /* Normalization Constant = 0.999885 */ @@ -54,6 +51,11 @@ gst_gl_effects_xray_step_two (gint width, gint height, guint texture, g_hash_table_insert (effects->shaderstable, "xray1", shader); } + if (!kernel_ready) { + fill_gaussian_kernel (gauss_kernel, 9, 1.5); + kernel_ready = TRUE; + } + g_return_if_fail (gst_gl_shader_compile_and_check (shader, hconv9_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)); @@ -68,10 +70,7 @@ gst_gl_effects_xray_step_two (gint width, gint height, guint texture, glDisable (GL_TEXTURE_RECTANGLE_ARB); gst_gl_shader_set_uniform_1i (shader, "tex", 1); - gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel); - gst_gl_shader_set_uniform_1f (shader, "norm_const", 0.999885f); - gst_gl_shader_set_uniform_1f (shader, "norm_offset", 0.0f); gst_gl_effects_draw_texture (effects, texture); } @@ -104,10 +103,7 @@ gst_gl_effects_xray_step_three (gint width, gint height, guint texture, glDisable (GL_TEXTURE_RECTANGLE_ARB); gst_gl_shader_set_uniform_1i (shader, "tex", 1); - gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel); - gst_gl_shader_set_uniform_1f (shader, "norm_const", 0.999885f); - gst_gl_shader_set_uniform_1f (shader, "norm_offset", 0.0f); gst_gl_effects_draw_texture (effects, texture); } diff --git a/gst/gl/gstgldifferencematte.c b/gst/gl/gstgldifferencematte.c index 59cfc25993..4e3f7a8aea 100644 --- a/gst/gl/gstgldifferencematte.c +++ b/gst/gl/gstgldifferencematte.c @@ -203,6 +203,8 @@ gst_gl_differencematte_init (GstGLDifferenceMatte * differencematte, differencematte->savedbgtexture = 0; differencematte->newbgtexture = 0; differencematte->bg_has_changed = FALSE; + + fill_gaussian_kernel (differencematte->kernel, 9, 3.0); } static void @@ -274,8 +276,8 @@ init_pixbuf_texture (GstGLDisplay * display, gpointer data) glGenTextures (1, &differencematte->newbgtexture); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, differencematte->newbgtexture); glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - (gint) differencematte->pbuf_width, (gint) differencematte->pbuf_height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, differencematte->pixbuf); + (gint) differencematte->pbuf_width, (gint) differencematte->pbuf_height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, differencematte->pixbuf); if (differencematte->savedbgtexture == 0) { glGenTextures (1, &differencematte->savedbgtexture); @@ -326,11 +328,6 @@ gst_gl_differencematte_hblur (gint width, gint height, guint texture, gpointer stuff) { GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff); - gfloat gauss_kernel[9] = { - 0.026995f, 0.064759f, 0.120985f, - 0.176033f, 0.199471f, 0.176033f, - 0.120985f, 0.064759f, 0.026995f - }; glMatrixMode (GL_PROJECTION); glLoadIdentity (); @@ -345,11 +342,7 @@ gst_gl_differencematte_hblur (gint width, gint height, guint texture, gst_gl_shader_set_uniform_1i (differencematte->shader[1], "tex", 0); gst_gl_shader_set_uniform_1fv (differencematte->shader[1], "kernel", 9, - gauss_kernel); - gst_gl_shader_set_uniform_1f (differencematte->shader[1], "norm_const", - 0.977016f); - gst_gl_shader_set_uniform_1f (differencematte->shader[1], "norm_offset", - 0.0f); + differencematte->kernel); gst_gl_differencematte_draw_texture (differencematte, texture); } @@ -359,11 +352,6 @@ gst_gl_differencematte_vblur (gint width, gint height, guint texture, gpointer stuff) { GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff); - gfloat gauss_kernel[9] = { - 0.026995f, 0.064759f, 0.120985f, - 0.176033f, 0.199471f, 0.176033f, - 0.120985f, 0.064759f, 0.026995f - }; glMatrixMode (GL_PROJECTION); glLoadIdentity (); @@ -378,11 +366,7 @@ gst_gl_differencematte_vblur (gint width, gint height, guint texture, gst_gl_shader_set_uniform_1i (differencematte->shader[2], "tex", 0); gst_gl_shader_set_uniform_1fv (differencematte->shader[2], "kernel", 9, - gauss_kernel); - gst_gl_shader_set_uniform_1f (differencematte->shader[2], "norm_const", - 0.977016f); - gst_gl_shader_set_uniform_1f (differencematte->shader[2], "norm_offset", - 0.0f); + differencematte->kernel); gst_gl_differencematte_draw_texture (differencematte, texture); } @@ -413,14 +397,14 @@ gst_gl_differencematte_interp (gint width, gint height, guint texture, gst_gl_shader_set_uniform_1i (differencematte->shader[3], "base", 1); gst_gl_shader_set_uniform_1f (differencematte->shader[3], - "base_width", (gfloat) differencematte->pbuf_width); + "base_width", (gfloat) differencematte->pbuf_width); gst_gl_shader_set_uniform_1f (differencematte->shader[3], - "base_height", (gfloat) differencematte->pbuf_height); + "base_height", (gfloat) differencematte->pbuf_height); gst_gl_shader_set_uniform_1f (differencematte->shader[3], - "final_width", (gfloat) filter->width); + "final_width", (gfloat) filter->width); gst_gl_shader_set_uniform_1f (differencematte->shader[3], - "final_height", (gfloat) filter->height); + "final_height", (gfloat) filter->height); glActiveTexture (GL_TEXTURE2); glEnable (GL_TEXTURE_RECTANGLE_ARB); @@ -572,7 +556,8 @@ gst_gl_differencematte_loader (GstGLFilter * filter) differencematte->pbuf_width = width; differencematte->pbuf_height = height; - differencematte->pixbuf = (guchar *) malloc (sizeof (guchar) * width * height * 4); + differencematte->pixbuf = + (guchar *) malloc (sizeof (guchar) * width * height * 4); rows = (guchar **) malloc (sizeof (guchar *) * height); diff --git a/gst/gl/gstgldifferencematte.h b/gst/gl/gstgldifferencematte.h index 50c70702e4..06f1d0a315 100644 --- a/gst/gl/gstgldifferencematte.h +++ b/gst/gl/gstgldifferencematte.h @@ -48,6 +48,7 @@ struct _GstGLDifferenceMatte GLuint newbgtexture; GLuint midtexture[4]; GLuint intexture; + float kernel[9]; }; struct _GstGLDifferenceMatteClass diff --git a/gst/gl/gstglfilterblur.c b/gst/gl/gstglfilterblur.c index 8853a5cf85..f2c561fa1d 100644 --- a/gst/gl/gstglfilterblur.c +++ b/gst/gl/gstglfilterblur.c @@ -125,6 +125,10 @@ gst_gl_filterblur_init (GstGLFilterBlur * filterblur, filterblur->shader0 = NULL; filterblur->shader1 = NULL; filterblur->midtexture = 0; + /* gaussian kernel (well, actually vector), size 9, standard + * deviation 3.0 */ + /* FIXME: eventually make this a runtime property */ + fill_gaussian_kernel (filterblur->gauss_kernel, 9, 3.0); } static void @@ -223,14 +227,6 @@ gst_gl_filterblur_hcallback (gint width, gint height, guint texture, { GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (stuff); - /* hard coded kernel, it could be easily generated at runtime with a - * property to change standard deviation */ - gfloat gauss_kernel[9] = { - 0.026995f, 0.064759f, 0.120985f, - 0.176033f, 0.199471f, 0.176033f, - 0.120985f, 0.064759f, 0.026995f - }; - glMatrixMode (GL_PROJECTION); glLoadIdentity (); @@ -242,11 +238,8 @@ gst_gl_filterblur_hcallback (gint width, gint height, guint texture, glDisable (GL_TEXTURE_RECTANGLE_ARB); gst_gl_shader_set_uniform_1i (filterblur->shader0, "tex", 1); - gst_gl_shader_set_uniform_1fv (filterblur->shader0, "kernel", 9, - gauss_kernel); - gst_gl_shader_set_uniform_1f (filterblur->shader0, "norm_const", 0.977016f); - gst_gl_shader_set_uniform_1f (filterblur->shader0, "norm_offset", 0.0f); + filterblur->gauss_kernel); gst_gl_filterblur_draw_texture (filterblur, texture); } @@ -258,14 +251,6 @@ gst_gl_filterblur_vcallback (gint width, gint height, guint texture, { GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (stuff); - /* hard coded kernel, it could be easily generated at runtime with a - * property to change standard deviation */ - gfloat gauss_kernel[9] = { - 0.026995f, 0.064759f, 0.120985f, - 0.176033f, 0.199471f, 0.176033f, - 0.120985f, 0.064759f, 0.026995f - }; - glMatrixMode (GL_PROJECTION); glLoadIdentity (); @@ -277,11 +262,8 @@ gst_gl_filterblur_vcallback (gint width, gint height, guint texture, glDisable (GL_TEXTURE_RECTANGLE_ARB); gst_gl_shader_set_uniform_1i (filterblur->shader1, "tex", 1); - gst_gl_shader_set_uniform_1fv (filterblur->shader1, "kernel", 9, - gauss_kernel); - gst_gl_shader_set_uniform_1f (filterblur->shader1, "norm_const", 0.977016f); - gst_gl_shader_set_uniform_1f (filterblur->shader1, "norm_offset", 0.0f); + filterblur->gauss_kernel); gst_gl_filterblur_draw_texture (filterblur, texture); } diff --git a/gst/gl/gstglfilterblur.h b/gst/gl/gstglfilterblur.h index 7a5f8ae4ee..71572810e9 100644 --- a/gst/gl/gstglfilterblur.h +++ b/gst/gl/gstglfilterblur.h @@ -40,6 +40,7 @@ struct _GstGLFilterBlur GstGLShader *shader1; GLuint midtexture; + float gauss_kernel[9]; }; struct _GstGLFilterBlurClass