[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.
This commit is contained in:
Filippo Argiolas 2010-04-23 20:06:48 +02:00 committed by Matthew Waters
parent e602d818e3
commit 98752e51da
8 changed files with 74 additions and 93 deletions

View file

@ -20,10 +20,8 @@
#include <gstgleffects.h> #include <gstgleffects.h>
static gfloat gauss_kernel[9] = { 0.060493f, 0.075284f, 0.088016f, static gboolean kernel_ready = FALSE;
0.096667f, 0.099736f, 0.096667f, static float gauss_kernel[9];
0.088016f, 0.075284f, 0.060493f
};
static void static void
gst_gl_effects_glow_step_one (gint width, gint height, guint texture, 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); GstGLEffects *effects = GST_GL_EFFECTS (stuff);
GstGLShader *shader; 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"); shader = g_hash_table_lookup (effects->shaderstable, "glow1");
if (!shader) { 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); 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, g_return_if_fail (gst_gl_shader_compile_and_check (shader,
hconv9_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)); 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); glDisable (GL_TEXTURE_RECTANGLE_ARB);
gst_gl_shader_set_uniform_1i (shader, "tex", 1); 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_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); 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); glDisable (GL_TEXTURE_RECTANGLE_ARB);
gst_gl_shader_set_uniform_1i (shader, "tex", 1); 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_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); gst_gl_effects_draw_texture (effects, texture);
} }

View file

@ -20,6 +20,7 @@
#include <gstgleffects.h> #include <gstgleffects.h>
#include <gstgleffectssources.h> #include <gstgleffectssources.h>
#include <math.h>
/* A common file for sources is needed since shader sources can be /* A common file for sources is needed since shader sources can be
* generic and reused by several effects */ * generic and reused by several effects */
@ -28,6 +29,33 @@
/* Move sooner or later into single .frag .vert files and either bake /* 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 */ * 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* */ /* *INDENT-OFF* */
/* Vertex shader */ /* Vertex shader */
@ -276,44 +304,36 @@ const gchar *sobel_fragment_source =
const gchar *hconv9_fragment_source = const gchar *hconv9_fragment_source =
"#extension GL_ARB_texture_rectangle : enable\n" "#extension GL_ARB_texture_rectangle : enable\n"
"uniform sampler2DRect tex;" "uniform sampler2DRect tex;"
"uniform float norm_const;"
"uniform float norm_offset;"
"uniform float kernel[9];" "uniform float kernel[9];"
"void main () {" "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;" " vec2 texturecoord = gl_TexCoord[0].st;"
" texturecoord.s -= 4.0;"
" int i;" " int i;"
" vec4 sum = vec4 (0.0);" " vec4 sum = vec4 (0.0);"
" for (i = 0; i < 9; i++) { " " for (i = 0; i < 9; i++) { "
" ++offset;" " vec4 neighbor = texture2DRect(tex, texturecoord); "
" vec4 neighbor = texture2DRect(tex, vec2(texturecoord.s+offset, texturecoord.t)); " " ++texturecoord.s;"
" sum += neighbor * kernel[i]/norm_const; " " sum += neighbor * kernel[i];"
" }" " }"
" gl_FragColor = sum + norm_offset;" " gl_FragColor = sum;"
"}"; "}";
/* vertical convolution */ /* vertical convolution */
const gchar *vconv9_fragment_source = const gchar *vconv9_fragment_source =
"#extension GL_ARB_texture_rectangle : enable\n" "#extension GL_ARB_texture_rectangle : enable\n"
"uniform sampler2DRect tex;" "uniform sampler2DRect tex;"
"uniform float norm_const;"
"uniform float norm_offset;"
"uniform float kernel[9];" "uniform float kernel[9];"
"void main () {" "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;" " vec2 texturecoord = gl_TexCoord[0].st;"
" texturecoord.t -= 4.0;"
" int i;" " int i;"
" vec4 sum = vec4 (0.0);" " vec4 sum = vec4 (0.0);"
" for (i = 0; i < 9; i++) { " " for (i = 0; i < 9; i++) { "
" ++offset;" " vec4 neighbor = texture2DRect(tex, texturecoord); "
" vec4 neighbor = texture2DRect(tex, vec2(texturecoord.s, texturecoord.t+offset)); " " ++texturecoord.t;"
" sum += neighbor * kernel[i]/norm_const; " " sum += neighbor * kernel[i]; "
" }" " }"
" gl_FragColor = sum + norm_offset;" " gl_FragColor = sum;"
"}"; "}";

View file

@ -44,4 +44,6 @@ extern const gchar *texture_interp_fragment_source;
extern const gchar *difference_fragment_source; extern const gchar *difference_fragment_source;
extern const gchar *multiply_fragment_source; extern const gchar *multiply_fragment_source;
void fill_gaussian_kernel (float *kernel, int size, float sigma);
#endif /* __GST_GL_EFFECTS_SOURCES_H__ */ #endif /* __GST_GL_EFFECTS_SOURCES_H__ */

View file

@ -22,11 +22,8 @@
#include <gstgleffectscurves.h> #include <gstgleffectscurves.h>
#include <gstgleffectlumatocurve.h> #include <gstgleffectlumatocurve.h>
/* Gaussian Kernel: std = 1.200000, size = 9x1 */ static gboolean kernel_ready = FALSE;
static gfloat gauss_kernel[9] = { 0.001285f, 0.014607f, 0.082898f, static float gauss_kernel[9];
0.234927f, 0.332452f, 0.234927f,
0.082898f, 0.014607f, 0.001285f
};
/* Normalization Constant = 0.999885 */ /* 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); 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, g_return_if_fail (gst_gl_shader_compile_and_check (shader,
hconv9_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)); 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); glDisable (GL_TEXTURE_RECTANGLE_ARB);
gst_gl_shader_set_uniform_1i (shader, "tex", 1); 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_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); 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); glDisable (GL_TEXTURE_RECTANGLE_ARB);
gst_gl_shader_set_uniform_1i (shader, "tex", 1); 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_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); gst_gl_effects_draw_texture (effects, texture);
} }

View file

@ -203,6 +203,8 @@ gst_gl_differencematte_init (GstGLDifferenceMatte * differencematte,
differencematte->savedbgtexture = 0; differencematte->savedbgtexture = 0;
differencematte->newbgtexture = 0; differencematte->newbgtexture = 0;
differencematte->bg_has_changed = FALSE; differencematte->bg_has_changed = FALSE;
fill_gaussian_kernel (differencematte->kernel, 9, 3.0);
} }
static void static void
@ -274,8 +276,8 @@ init_pixbuf_texture (GstGLDisplay * display, gpointer data)
glGenTextures (1, &differencematte->newbgtexture); glGenTextures (1, &differencematte->newbgtexture);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, differencematte->newbgtexture); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, differencematte->newbgtexture);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
(gint) differencematte->pbuf_width, (gint) differencematte->pbuf_height, 0, (gint) differencematte->pbuf_width, (gint) differencematte->pbuf_height,
GL_RGBA, GL_UNSIGNED_BYTE, differencematte->pixbuf); 0, GL_RGBA, GL_UNSIGNED_BYTE, differencematte->pixbuf);
if (differencematte->savedbgtexture == 0) { if (differencematte->savedbgtexture == 0) {
glGenTextures (1, &differencematte->savedbgtexture); glGenTextures (1, &differencematte->savedbgtexture);
@ -326,11 +328,6 @@ gst_gl_differencematte_hblur (gint width, gint height, guint texture,
gpointer stuff) gpointer stuff)
{ {
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (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); glMatrixMode (GL_PROJECTION);
glLoadIdentity (); 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_1i (differencematte->shader[1], "tex", 0);
gst_gl_shader_set_uniform_1fv (differencematte->shader[1], "kernel", 9, gst_gl_shader_set_uniform_1fv (differencematte->shader[1], "kernel", 9,
gauss_kernel); differencematte->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);
gst_gl_differencematte_draw_texture (differencematte, texture); gst_gl_differencematte_draw_texture (differencematte, texture);
} }
@ -359,11 +352,6 @@ gst_gl_differencematte_vblur (gint width, gint height, guint texture,
gpointer stuff) gpointer stuff)
{ {
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (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); glMatrixMode (GL_PROJECTION);
glLoadIdentity (); 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_1i (differencematte->shader[2], "tex", 0);
gst_gl_shader_set_uniform_1fv (differencematte->shader[2], "kernel", 9, gst_gl_shader_set_uniform_1fv (differencematte->shader[2], "kernel", 9,
gauss_kernel); differencematte->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);
gst_gl_differencematte_draw_texture (differencematte, texture); gst_gl_differencematte_draw_texture (differencematte, texture);
} }
@ -572,7 +556,8 @@ gst_gl_differencematte_loader (GstGLFilter * filter)
differencematte->pbuf_width = width; differencematte->pbuf_width = width;
differencematte->pbuf_height = height; 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); rows = (guchar **) malloc (sizeof (guchar *) * height);

View file

@ -48,6 +48,7 @@ struct _GstGLDifferenceMatte
GLuint newbgtexture; GLuint newbgtexture;
GLuint midtexture[4]; GLuint midtexture[4];
GLuint intexture; GLuint intexture;
float kernel[9];
}; };
struct _GstGLDifferenceMatteClass struct _GstGLDifferenceMatteClass

View file

@ -125,6 +125,10 @@ gst_gl_filterblur_init (GstGLFilterBlur * filterblur,
filterblur->shader0 = NULL; filterblur->shader0 = NULL;
filterblur->shader1 = NULL; filterblur->shader1 = NULL;
filterblur->midtexture = 0; 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 static void
@ -223,14 +227,6 @@ gst_gl_filterblur_hcallback (gint width, gint height, guint texture,
{ {
GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (stuff); 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); glMatrixMode (GL_PROJECTION);
glLoadIdentity (); glLoadIdentity ();
@ -242,11 +238,8 @@ gst_gl_filterblur_hcallback (gint width, gint height, guint texture,
glDisable (GL_TEXTURE_RECTANGLE_ARB); glDisable (GL_TEXTURE_RECTANGLE_ARB);
gst_gl_shader_set_uniform_1i (filterblur->shader0, "tex", 1); gst_gl_shader_set_uniform_1i (filterblur->shader0, "tex", 1);
gst_gl_shader_set_uniform_1fv (filterblur->shader0, "kernel", 9, gst_gl_shader_set_uniform_1fv (filterblur->shader0, "kernel", 9,
gauss_kernel); filterblur->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);
gst_gl_filterblur_draw_texture (filterblur, texture); 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); 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); glMatrixMode (GL_PROJECTION);
glLoadIdentity (); glLoadIdentity ();
@ -277,11 +262,8 @@ gst_gl_filterblur_vcallback (gint width, gint height, guint texture,
glDisable (GL_TEXTURE_RECTANGLE_ARB); glDisable (GL_TEXTURE_RECTANGLE_ARB);
gst_gl_shader_set_uniform_1i (filterblur->shader1, "tex", 1); gst_gl_shader_set_uniform_1i (filterblur->shader1, "tex", 1);
gst_gl_shader_set_uniform_1fv (filterblur->shader1, "kernel", 9, gst_gl_shader_set_uniform_1fv (filterblur->shader1, "kernel", 9,
gauss_kernel); filterblur->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);
gst_gl_filterblur_draw_texture (filterblur, texture); gst_gl_filterblur_draw_texture (filterblur, texture);
} }

View file

@ -40,6 +40,7 @@ struct _GstGLFilterBlur
GstGLShader *shader1; GstGLShader *shader1;
GLuint midtexture; GLuint midtexture;
float gauss_kernel[9];
}; };
struct _GstGLFilterBlurClass struct _GstGLFilterBlurClass