[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>
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);
}

View file

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

View file

@ -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__ */

View file

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

View file

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

View file

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

View file

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

View file

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