mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 17:50:36 +00:00
[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:
parent
e602d818e3
commit
98752e51da
8 changed files with 74 additions and 93 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;"
|
||||
"}";
|
||||
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ struct _GstGLDifferenceMatte
|
|||
GLuint newbgtexture;
|
||||
GLuint midtexture[4];
|
||||
GLuint intexture;
|
||||
float kernel[9];
|
||||
};
|
||||
|
||||
struct _GstGLDifferenceMatteClass
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ struct _GstGLFilterBlur
|
|||
GstGLShader *shader1;
|
||||
|
||||
GLuint midtexture;
|
||||
float gauss_kernel[9];
|
||||
};
|
||||
|
||||
struct _GstGLFilterBlurClass
|
||||
|
|
Loading…
Reference in a new issue