diff options
author | Filippo Argiolas <filippo.argiolas@gmail.com> | 2010-04-23 20:06:48 +0200 |
---|---|---|
committer | Filippo Argiolas <filippo.argiolas@gmail.com> | 2010-04-24 20:13:13 +0200 |
commit | 3a43353ac9dabba9470cc78595a2a46b490ad414 (patch) | |
tree | b6bf04c9be901d5e9d9fcf7409432917bb7ae134 | |
parent | 4fcde4ca2a629bae00786e661ace4c00c4fb65ee (diff) |
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.
-rw-r--r-- | gst/gl/effects/gstgleffectglow.c | 20 | ||||
-rw-r--r-- | gst/gl/effects/gstgleffectssources.c | 56 | ||||
-rw-r--r-- | gst/gl/effects/gstgleffectssources.h | 2 | ||||
-rw-r--r-- | gst/gl/effects/gstgleffectxray.c | 18 | ||||
-rw-r--r-- | gst/gl/gstgldifferencematte.c | 39 | ||||
-rw-r--r-- | gst/gl/gstgldifferencematte.h | 1 | ||||
-rw-r--r-- | gst/gl/gstglfilterblur.c | 30 | ||||
-rw-r--r-- | 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 4930249..d6422e6 100644 --- a/gst/gl/effects/gstgleffectglow.c +++ b/gst/gl/effects/gstgleffectglow.c @@ -20,10 +20,8 @@ #include <gstgleffects.h> -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 9ed7560..4defe95 100644 --- a/gst/gl/effects/gstgleffectssources.c +++ b/gst/gl/effects/gstgleffectssources.c @@ -20,6 +20,7 @@ #include <gstgleffects.h> #include <gstgleffectssources.h> +#include <math.h> /* 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 c93c59b..20bc991 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 d086843..d5f9e16 100644 --- a/gst/gl/effects/gstgleffectxray.c +++ b/gst/gl/effects/gstgleffectxray.c @@ -22,11 +22,8 @@ #include <gstgleffectscurves.h> #include <gstgleffectlumatocurve.h> -/* 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 59cfc25..4e3f7a8 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 50c7070..06f1d0a 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 8853a5c..f2c561f 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 7a5f8ae..7157281 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 |