summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Argiolas <filippo.argiolas@gmail.com>2010-04-23 20:06:48 +0200
committerFilippo Argiolas <filippo.argiolas@gmail.com>2010-04-24 20:13:13 +0200
commit3a43353ac9dabba9470cc78595a2a46b490ad414 (patch)
treeb6bf04c9be901d5e9d9fcf7409432917bb7ae134
parent4fcde4ca2a629bae00786e661ace4c00c4fb65ee (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.c20
-rw-r--r--gst/gl/effects/gstgleffectssources.c56
-rw-r--r--gst/gl/effects/gstgleffectssources.h2
-rw-r--r--gst/gl/effects/gstgleffectxray.c18
-rw-r--r--gst/gl/gstgldifferencematte.c39
-rw-r--r--gst/gl/gstgldifferencematte.h1
-rw-r--r--gst/gl/gstglfilterblur.c30
-rw-r--r--gst/gl/gstglfilterblur.h1
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