eglglessink: Draw black borders and also use a single GL buffer for all vertices

Fixes weird artifacts outside the video frame on
Qualcomm Snapdragon chipsets and should be faster
than glClear() on the complete area all the time.
This commit is contained in:
Sebastian Dröge 2012-10-17 15:04:11 +02:00
parent a65ed4d7c1
commit 9941466ab4

View file

@ -198,6 +198,23 @@ static const char *vert_COPY_prog = {
"}"
};
static const char *vert_COPY_prog_no_tex = {
"attribute vec3 position;"
"void main(void)"
"{"
" gl_Position = vec4(position, 1.0);"
"}"
};
/* Paint all black */
static const char *frag_BLACK_prog = {
"precision mediump float;"
"void main(void)"
"{"
" gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);"
"}"
};
/* Direct fragments copy */
static const char *frag_COPY_prog = {
"precision mediump float;"
@ -325,8 +342,9 @@ static GstStaticPadTemplate gst_eglglessink_sink_template_factory =
GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx ";"
GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";"
GST_VIDEO_CAPS_YUV
("{ AYUV, Y444, I420, YV12, NV12, NV21, YUY2, YVYU, UYVY, Y42B, Y41B }") ";"
GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";" GST_VIDEO_CAPS_RGB_16));
("{ AYUV, Y444, I420, YV12, NV12, NV21, YUY2, YVYU, UYVY, Y42B, Y41B }")
";" GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
GST_VIDEO_CAPS_RGB_16));
/* Filter signals and args */
enum
@ -429,7 +447,7 @@ static void gst_eglglessink_init_egl_exts (GstEglGlesSink * eglglessink);
static gboolean gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink,
gboolean reset);
static gboolean
gst_eglglessink_configure_caps (GstEglGlesSink *eglglessink, GstCaps * caps);
gst_eglglessink_configure_caps (GstEglGlesSink * eglglessink, GstCaps * caps);
static GstFlowReturn gst_eglglessink_render_and_display (GstEglGlesSink * sink,
GstBuffer * buf);
static GstFlowReturn gst_eglglessink_queue_buffer (GstEglGlesSink * sink,
@ -1073,10 +1091,11 @@ render_thread_func (GstEglGlesSink * eglglessink)
while (gst_data_queue_pop (eglglessink->queue, &item)) {
GstBuffer *buf = NULL;
GST_DEBUG_OBJECT (eglglessink, "Handling object %" GST_PTR_FORMAT, item->object);
GST_DEBUG_OBJECT (eglglessink, "Handling object %" GST_PTR_FORMAT,
item->object);
if (item->object) {
GstCaps * caps;
GstCaps *caps;
buf = GST_BUFFER (item->object);
caps = GST_BUFFER_CAPS (buf);
@ -1092,7 +1111,8 @@ render_thread_func (GstEglGlesSink * eglglessink)
}
}
eglglessink->last_flow = gst_eglglessink_render_and_display (eglglessink, buf);
eglglessink->last_flow =
gst_eglglessink_render_and_display (eglglessink, buf);
if (buf) {
g_mutex_lock (eglglessink->render_lock);
g_cond_broadcast (eglglessink->render_cond);
@ -1115,7 +1135,6 @@ render_thread_func (GstEglGlesSink * eglglessink)
if (eglglessink->have_vbo) {
glDeleteBuffers (1, &eglglessink->eglglesctx.position_buffer);
glDeleteBuffers (1, &eglglessink->eglglesctx.texpos_buffer);
glDeleteBuffers (1, &eglglessink->eglglesctx.index_buffer);
eglglessink->have_vbo = FALSE;
}
@ -1127,15 +1146,26 @@ render_thread_func (GstEglGlesSink * eglglessink)
eglglessink->eglglesctx.n_textures = 0;
}
if (eglglessink->eglglesctx.glslprogram) {
glDetachShader (eglglessink->eglglesctx.glslprogram,
eglglessink->eglglesctx.fragshader);
glDetachShader (eglglessink->eglglesctx.glslprogram,
eglglessink->eglglesctx.vertshader);
glDeleteProgram (eglglessink->eglglesctx.glslprogram);
glDeleteShader (eglglessink->eglglesctx.fragshader);
glDeleteShader (eglglessink->eglglesctx.vertshader);
eglglessink->eglglesctx.glslprogram = 0;
if (eglglessink->eglglesctx.glslprogram[0]) {
glDetachShader (eglglessink->eglglesctx.glslprogram[0],
eglglessink->eglglesctx.fragshader[0]);
glDetachShader (eglglessink->eglglesctx.glslprogram[0],
eglglessink->eglglesctx.vertshader[0]);
glDeleteProgram (eglglessink->eglglesctx.glslprogram[0]);
glDeleteShader (eglglessink->eglglesctx.fragshader[0]);
glDeleteShader (eglglessink->eglglesctx.vertshader[0]);
eglglessink->eglglesctx.glslprogram[0] = 0;
}
if (eglglessink->eglglesctx.glslprogram[1]) {
glDetachShader (eglglessink->eglglesctx.glslprogram[1],
eglglessink->eglglesctx.fragshader[1]);
glDetachShader (eglglessink->eglglesctx.glslprogram[1],
eglglessink->eglglesctx.vertshader[1]);
glDeleteProgram (eglglessink->eglglesctx.glslprogram[1]);
glDeleteShader (eglglessink->eglglesctx.fragshader[1]);
glDeleteShader (eglglessink->eglglesctx.vertshader[1]);
eglglessink->eglglesctx.glslprogram[1] = 0;
}
}
@ -1341,8 +1371,10 @@ gst_eglglessink_init_egl_exts (GstEglGlesSink * eglglessink)
eglexts = eglQueryString (eglglessink->eglglesctx.display, EGL_EXTENSIONS);
glexts = glGetString (GL_EXTENSIONS);
GST_DEBUG_OBJECT (eglglessink, "Available EGL extensions: %s\n", GST_STR_NULL (eglexts));
GST_DEBUG_OBJECT (eglglessink, "Available GLES extensions: %s\n", GST_STR_NULL ((const char *) glexts));
GST_DEBUG_OBJECT (eglglessink, "Available EGL extensions: %s\n",
GST_STR_NULL (eglexts));
GST_DEBUG_OBJECT (eglglessink, "Available GLES extensions: %s\n",
GST_STR_NULL ((const char *) glexts));
#ifdef EGL_FAST_RENDERING_POSSIBLE
/* OK Fast rendering should be possible from the declared
@ -1419,111 +1451,165 @@ SLOW_PATH_SELECTED:
static gboolean
gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
{
gdouble surface_width, surface_height;
gdouble x1, x2, y1, y2;
GST_INFO_OBJECT (eglglessink, "VBO setup. have_vbo:%d, should reset %d",
eglglessink->have_vbo, reset);
if (eglglessink->have_vbo && reset) {
glDeleteBuffers (1, &eglglessink->eglglesctx.position_buffer);
glDeleteBuffers (1, &eglglessink->eglglesctx.texpos_buffer);
glDeleteBuffers (1, &eglglessink->eglglesctx.index_buffer);
eglglessink->have_vbo = FALSE;
}
if (!eglglessink->have_vbo) {
GST_DEBUG_OBJECT (eglglessink, "Performing VBO setup");
eglglessink->eglglesctx.position_array[0].x = 1;
eglglessink->eglglesctx.position_array[0].y = 1;
eglglessink->eglglesctx.position_array[0].z = 0;
surface_width = eglglessink->eglglesctx.surface_width;
surface_height = eglglessink->eglglesctx.surface_height;
eglglessink->eglglesctx.position_array[1].x = 1;
eglglessink->eglglesctx.position_array[1].y = -1;
eglglessink->eglglesctx.position_array[1].z = 0;
GST_DEBUG_OBJECT (eglglessink, "Performing VBO setup");
eglglessink->eglglesctx.position_array[2].x = -1;
eglglessink->eglglesctx.position_array[2].y = 1;
eglglessink->eglglesctx.position_array[2].z = 0;
x1 = (eglglessink->display_region.x / surface_width) * 2.0 - 1;
y1 = (eglglessink->display_region.y / surface_height) * 2.0 - 1;
x2 = ((eglglessink->display_region.x +
eglglessink->display_region.w) / surface_width) * 2.0 - 1;
y2 = ((eglglessink->display_region.y +
eglglessink->display_region.h) / surface_height) * 2.0 - 1;
eglglessink->eglglesctx.position_array[3].x = -1;
eglglessink->eglglesctx.position_array[3].y = -1;
eglglessink->eglglesctx.position_array[3].z = 0;
eglglessink->eglglesctx.position_array[0].x = x2;
eglglessink->eglglesctx.position_array[0].y = y2;
eglglessink->eglglesctx.position_array[0].z = 0;
eglglessink->eglglesctx.position_array[0].a = 1;
eglglessink->eglglesctx.position_array[0].b = 0;
eglglessink->eglglesctx.texpos_array[0].x = 1;
eglglessink->eglglesctx.texpos_array[0].y = 0;
eglglessink->eglglesctx.position_array[1].x = x2;
eglglessink->eglglesctx.position_array[1].y = y1;
eglglessink->eglglesctx.position_array[1].z = 0;
eglglessink->eglglesctx.position_array[1].a = 1;
eglglessink->eglglesctx.position_array[1].b = 1;
eglglessink->eglglesctx.texpos_array[1].x = 1;
eglglessink->eglglesctx.texpos_array[1].y = 1;
eglglessink->eglglesctx.position_array[2].x = x1;
eglglessink->eglglesctx.position_array[2].y = y2;
eglglessink->eglglesctx.position_array[2].z = 0;
eglglessink->eglglesctx.position_array[2].a = 0;
eglglessink->eglglesctx.position_array[2].b = 0;
eglglessink->eglglesctx.texpos_array[2].x = 0;
eglglessink->eglglesctx.texpos_array[2].y = 0;
eglglessink->eglglesctx.position_array[3].x = x1;
eglglessink->eglglesctx.position_array[3].y = y1;
eglglessink->eglglesctx.position_array[3].z = 0;
eglglessink->eglglesctx.position_array[3].a = 0;
eglglessink->eglglesctx.position_array[3].b = 1;
eglglessink->eglglesctx.texpos_array[3].x = 0;
eglglessink->eglglesctx.texpos_array[3].y = 1;
if (eglglessink->display_region.x == 0) {
/* Borders top/bottom */
eglglessink->eglglesctx.index_array[0] = 0;
eglglessink->eglglesctx.index_array[1] = 1;
eglglessink->eglglesctx.index_array[2] = 2;
eglglessink->eglglesctx.index_array[3] = 3;
eglglessink->eglglesctx.position_array[4 + 0].x = 1;
eglglessink->eglglesctx.position_array[4 + 0].y = 1;
eglglessink->eglglesctx.position_array[4 + 0].z = 0;
glGenBuffers (1, &eglglessink->eglglesctx.position_buffer);
glGenBuffers (1, &eglglessink->eglglesctx.texpos_buffer);
glGenBuffers (1, &eglglessink->eglglesctx.index_buffer);
if (got_gl_error ("glGenBuffers"))
goto HANDLE_ERROR_LOCKED;
eglglessink->eglglesctx.position_array[4 + 1].x = x2;
eglglessink->eglglesctx.position_array[4 + 1].y = y2;
eglglessink->eglglesctx.position_array[4 + 1].z = 0;
glBindBuffer (GL_ARRAY_BUFFER, eglglessink->eglglesctx.position_buffer);
if (got_gl_error ("glBindBuffer position_buffer"))
goto HANDLE_ERROR_LOCKED;
eglglessink->eglglesctx.position_array[4 + 2].x = -1;
eglglessink->eglglesctx.position_array[4 + 2].y = 1;
eglglessink->eglglesctx.position_array[4 + 2].z = 0;
glBufferData (GL_ARRAY_BUFFER,
sizeof (eglglessink->eglglesctx.position_array),
eglglessink->eglglesctx.position_array, GL_STATIC_DRAW);
if (got_gl_error ("glBufferData position_buffer"))
goto HANDLE_ERROR_LOCKED;
eglglessink->eglglesctx.position_array[4 + 3].x = x1;
eglglessink->eglglesctx.position_array[4 + 3].y = y2;
eglglessink->eglglesctx.position_array[4 + 3].z = 0;
glVertexAttribPointer (eglglessink->eglglesctx.position_loc, 3, GL_FLOAT,
GL_FALSE, 0, 0);
if (got_gl_error ("glVertexAttribPointer"))
goto HANDLE_ERROR_LOCKED;
eglglessink->eglglesctx.position_array[8 + 0].x = 1;
eglglessink->eglglesctx.position_array[8 + 0].y = y1;
eglglessink->eglglesctx.position_array[8 + 0].z = 0;
glEnableVertexAttribArray (eglglessink->eglglesctx.position_loc);
if (got_gl_error ("glEnableVertexAttribArray"))
goto HANDLE_ERROR_LOCKED;
eglglessink->eglglesctx.position_array[8 + 1].x = 1;
eglglessink->eglglesctx.position_array[8 + 1].y = -1;
eglglessink->eglglesctx.position_array[8 + 1].z = 0;
glBindBuffer (GL_ARRAY_BUFFER, eglglessink->eglglesctx.texpos_buffer);
if (got_gl_error ("glBindBuffer texpos_buffer"))
goto HANDLE_ERROR_LOCKED;
eglglessink->eglglesctx.position_array[8 + 2].x = x1;
eglglessink->eglglesctx.position_array[8 + 2].y = y1;
eglglessink->eglglesctx.position_array[8 + 2].z = 0;
glBufferData (GL_ARRAY_BUFFER,
sizeof (eglglessink->eglglesctx.texpos_array),
eglglessink->eglglesctx.texpos_array, GL_STATIC_DRAW);
if (got_gl_error ("glBufferData texpos_buffer"))
goto HANDLE_ERROR_LOCKED;
glVertexAttribPointer (eglglessink->eglglesctx.texpos_loc, 2, GL_FLOAT,
GL_FALSE, 0, 0);
if (got_gl_error ("glVertexAttribPointer"))
goto HANDLE_ERROR_LOCKED;
glEnableVertexAttribArray (eglglessink->eglglesctx.texpos_loc);
if (got_gl_error ("glEnableVertexAttribArray"))
goto HANDLE_ERROR_LOCKED;
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
eglglessink->eglglesctx.index_buffer);
if (got_gl_error ("glBindBuffer index_buffer"))
goto HANDLE_ERROR_LOCKED;
glBufferData (GL_ELEMENT_ARRAY_BUFFER,
sizeof (eglglessink->eglglesctx.index_array),
eglglessink->eglglesctx.index_array, GL_STATIC_DRAW);
if (got_gl_error ("glBufferData index_buffer"))
goto HANDLE_ERROR_LOCKED;
eglglessink->have_vbo = TRUE;
eglglessink->eglglesctx.position_array[8 + 3].x = -1;
eglglessink->eglglesctx.position_array[8 + 3].y = -1;
eglglessink->eglglesctx.position_array[8 + 3].z = 0;
} else {
GST_INFO_OBJECT (eglglessink, "Won't perform VBO setup");
/* Borders left/right */
eglglessink->eglglesctx.position_array[4 + 0].x = x1;
eglglessink->eglglesctx.position_array[4 + 0].y = 1;
eglglessink->eglglesctx.position_array[4 + 0].z = 0;
eglglessink->eglglesctx.position_array[4 + 1].x = x1;
eglglessink->eglglesctx.position_array[4 + 1].y = -1;
eglglessink->eglglesctx.position_array[4 + 1].z = 0;
eglglessink->eglglesctx.position_array[4 + 2].x = -1;
eglglessink->eglglesctx.position_array[4 + 2].y = 1;
eglglessink->eglglesctx.position_array[4 + 2].z = 0;
eglglessink->eglglesctx.position_array[4 + 3].x = -1;
eglglessink->eglglesctx.position_array[4 + 3].y = -1;
eglglessink->eglglesctx.position_array[4 + 3].z = 0;
eglglessink->eglglesctx.position_array[8 + 0].x = 1;
eglglessink->eglglesctx.position_array[8 + 0].y = 1;
eglglessink->eglglesctx.position_array[8 + 0].z = 0;
eglglessink->eglglesctx.position_array[8 + 1].x = 1;
eglglessink->eglglesctx.position_array[8 + 1].y = -1;
eglglessink->eglglesctx.position_array[8 + 1].z = 0;
eglglessink->eglglesctx.position_array[8 + 2].x = x2;
eglglessink->eglglesctx.position_array[8 + 2].y = y2;
eglglessink->eglglesctx.position_array[8 + 2].z = 0;
eglglessink->eglglesctx.position_array[8 + 3].x = x2;
eglglessink->eglglesctx.position_array[8 + 3].y = -1;
eglglessink->eglglesctx.position_array[8 + 3].z = 0;
}
eglglessink->eglglesctx.index_array[0] = 0;
eglglessink->eglglesctx.index_array[1] = 1;
eglglessink->eglglesctx.index_array[2] = 2;
eglglessink->eglglesctx.index_array[3] = 3;
glGenBuffers (1, &eglglessink->eglglesctx.position_buffer);
glGenBuffers (1, &eglglessink->eglglesctx.index_buffer);
if (got_gl_error ("glGenBuffers"))
goto HANDLE_ERROR_LOCKED;
glBindBuffer (GL_ARRAY_BUFFER, eglglessink->eglglesctx.position_buffer);
if (got_gl_error ("glBindBuffer position_buffer"))
goto HANDLE_ERROR_LOCKED;
glBufferData (GL_ARRAY_BUFFER,
sizeof (eglglessink->eglglesctx.position_array),
eglglessink->eglglesctx.position_array, GL_STATIC_DRAW);
if (got_gl_error ("glBufferData position_buffer"))
goto HANDLE_ERROR_LOCKED;
/* Map the texpos already */
glUseProgram (eglglessink->eglglesctx.glslprogram[0]);
glVertexAttribPointer (eglglessink->eglglesctx.texpos_loc, 2, GL_FLOAT,
GL_FALSE, 5 * sizeof (gfloat), (gpointer) (3 * sizeof (gfloat)));
if (got_gl_error ("glVertexAttribPointer"))
goto HANDLE_ERROR_LOCKED;
glUseProgram (0);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, eglglessink->eglglesctx.index_buffer);
if (got_gl_error ("glBindBuffer index_buffer"))
goto HANDLE_ERROR_LOCKED;
glBufferData (GL_ELEMENT_ARRAY_BUFFER,
sizeof (eglglessink->eglglesctx.index_array),
eglglessink->eglglesctx.index_array, GL_STATIC_DRAW);
if (got_gl_error ("glBufferData index_buffer"))
goto HANDLE_ERROR_LOCKED;
eglglessink->have_vbo = TRUE;
GST_DEBUG_OBJECT (eglglessink, "VBO setup done");
return TRUE;
HANDLE_ERROR_LOCKED:
@ -1565,23 +1651,25 @@ gst_eglglessink_context_make_current (GstEglGlesSink * eglglessink,
EGLContext *ctx = eglGetCurrentContext ();
if (ctx == eglglessink->eglglesctx.eglcontext) {
GST_DEBUG_OBJECT (eglglessink, "Already attached the context to thread %p", g_thread_self ());
GST_DEBUG_OBJECT (eglglessink,
"Already attached the context to thread %p", g_thread_self ());
return TRUE;
}
GST_DEBUG_OBJECT (eglglessink, "Attaching context to thread %p", g_thread_self ());
GST_DEBUG_OBJECT (eglglessink, "Attaching context to thread %p",
g_thread_self ());
if (!eglMakeCurrent (eglglessink->eglglesctx.display,
eglglessink->eglglesctx.surface,
eglglessink->eglglesctx.surface,
eglglessink->eglglesctx.surface, eglglessink->eglglesctx.surface,
eglglessink->eglglesctx.eglcontext)) {
show_egl_error ("eglMakeCurrent");
GST_ERROR_OBJECT (eglglessink, "Couldn't bind context");
return FALSE;
}
} else {
GST_DEBUG_OBJECT (eglglessink, "Detaching context from thread %p", g_thread_self ());
if (!eglMakeCurrent (eglglessink->eglglesctx.display,
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
GST_DEBUG_OBJECT (eglglessink, "Detaching context from thread %p",
g_thread_self ());
if (!eglMakeCurrent (eglglessink->eglglesctx.display, EGL_NO_SURFACE,
EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
show_egl_error ("eglMakeCurrent");
GST_ERROR_OBJECT (eglglessink, "Couldn't unbind context");
return FALSE;
@ -1633,12 +1721,11 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
eglglessink->eglglesctx.pixel_aspect_ratio = EGL_DISPLAY_SCALING;
} else {
eglQuerySurface (eglglessink->eglglesctx.display,
eglglessink->eglglesctx.surface, EGL_PIXEL_ASPECT_RATIO,
&display_par);
/* Fix for outbound DAR reporting on some implementations not
* honoring the 'should return w/h * EGL_DISPLAY_SCALING' spec
* requirement
*/
eglglessink->eglglesctx.surface, EGL_PIXEL_ASPECT_RATIO, &display_par);
/* Fix for outbound DAR reporting on some implementations not
* honoring the 'should return w/h * EGL_DISPLAY_SCALING' spec
* requirement
*/
if (display_par == EGL_UNKNOWN || display_par < EGL_SANE_DAR_MIN ||
display_par > EGL_SANE_DAR_MAX) {
GST_DEBUG_OBJECT (eglglessink, "Nonsensical PAR value returned: %d. "
@ -1669,37 +1756,39 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
goto HANDLE_ERROR;
}
eglglessink->eglglesctx.vertshader = glCreateShader (GL_VERTEX_SHADER);
/* Build shader program for video texture rendering */
eglglessink->eglglesctx.vertshader[0] = glCreateShader (GL_VERTEX_SHADER);
GST_DEBUG_OBJECT (eglglessink, "Sending %s to handle %d", vert_COPY_prog,
eglglessink->eglglesctx.vertshader);
glShaderSource (eglglessink->eglglesctx.vertshader, 1, &vert_COPY_prog,
eglglessink->eglglesctx.vertshader[0]);
glShaderSource (eglglessink->eglglesctx.vertshader[0], 1, &vert_COPY_prog,
NULL);
if (got_gl_error ("glShaderSource vertex"))
goto HANDLE_ERROR;
glCompileShader (eglglessink->eglglesctx.vertshader);
glCompileShader (eglglessink->eglglesctx.vertshader[0]);
if (got_gl_error ("glCompileShader vertex"))
goto HANDLE_ERROR;
glGetShaderiv (eglglessink->eglglesctx.vertshader, GL_COMPILE_STATUS, &test);
glGetShaderiv (eglglessink->eglglesctx.vertshader[0], GL_COMPILE_STATUS,
&test);
if (test != GL_FALSE)
GST_DEBUG_OBJECT (eglglessink, "Successfully compiled vertex shader");
else {
GST_ERROR_OBJECT (eglglessink, "Couldn't compile vertex shader");
glGetShaderiv (eglglessink->eglglesctx.vertshader, GL_INFO_LOG_LENGTH,
glGetShaderiv (eglglessink->eglglesctx.vertshader[0], GL_INFO_LOG_LENGTH,
&test);
info_log = g_new0 (GLchar, test);
glGetShaderInfoLog (eglglessink->eglglesctx.vertshader, test, NULL,
glGetShaderInfoLog (eglglessink->eglglesctx.vertshader[0], test, NULL,
info_log);
GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log);
g_free (info_log);
goto HANDLE_ERROR;
}
eglglessink->eglglesctx.fragshader = glCreateShader (GL_FRAGMENT_SHADER);
eglglessink->eglglesctx.fragshader[0] = glCreateShader (GL_FRAGMENT_SHADER);
switch (eglglessink->format) {
case GST_VIDEO_FORMAT_AYUV:
glShaderSource (eglglessink->eglglesctx.fragshader, 1, &frag_AYUV_prog,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1, &frag_AYUV_prog,
NULL);
eglglessink->eglglesctx.n_textures = 1;
texnames[0] = "tex";
@ -1709,7 +1798,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B:
glShaderSource (eglglessink->eglglesctx.fragshader, 1,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1,
&frag_PLANAR_YUV_prog, NULL);
eglglessink->eglglesctx.n_textures = 3;
texnames[0] = "Ytex";
@ -1718,7 +1807,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
break;
case GST_VIDEO_FORMAT_YUY2:
tmp_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'r', 'g', 'a');
glShaderSource (eglglessink->eglglesctx.fragshader, 1,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1,
(const GLchar **) &tmp_prog, NULL);
eglglessink->eglglesctx.n_textures = 2;
texnames[0] = "Ytex";
@ -1726,7 +1815,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
break;
case GST_VIDEO_FORMAT_YVYU:
tmp_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'r', 'a', 'g');
glShaderSource (eglglessink->eglglesctx.fragshader, 1,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1,
(const GLchar **) &tmp_prog, NULL);
eglglessink->eglglesctx.n_textures = 2;
texnames[0] = "Ytex";
@ -1734,7 +1823,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
break;
case GST_VIDEO_FORMAT_UYVY:
tmp_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'a', 'r', 'b');
glShaderSource (eglglessink->eglglesctx.fragshader, 1,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1,
(const GLchar **) &tmp_prog, NULL);
eglglessink->eglglesctx.n_textures = 2;
texnames[0] = "Ytex";
@ -1742,7 +1831,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
break;
case GST_VIDEO_FORMAT_NV12:
tmp_prog = g_strdup_printf (frag_NV12_NV21_prog, 'r', 'a');
glShaderSource (eglglessink->eglglesctx.fragshader, 1,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1,
(const GLchar **) &tmp_prog, NULL);
eglglessink->eglglesctx.n_textures = 2;
texnames[0] = "Ytex";
@ -1750,7 +1839,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
break;
case GST_VIDEO_FORMAT_NV21:
tmp_prog = g_strdup_printf (frag_NV12_NV21_prog, 'a', 'r');
glShaderSource (eglglessink->eglglesctx.fragshader, 1,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1,
(const GLchar **) &tmp_prog, NULL);
eglglessink->eglglesctx.n_textures = 2;
texnames[0] = "Ytex";
@ -1760,7 +1849,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_BGRA:
tmp_prog = g_strdup_printf (frag_REORDER_prog, 'b', 'g', 'r');
glShaderSource (eglglessink->eglglesctx.fragshader, 1,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1,
(const GLchar **) &tmp_prog, NULL);
eglglessink->eglglesctx.n_textures = 1;
texnames[0] = "tex";
@ -1768,7 +1857,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
case GST_VIDEO_FORMAT_xRGB:
case GST_VIDEO_FORMAT_ARGB:
tmp_prog = g_strdup_printf (frag_REORDER_prog, 'g', 'b', 'a');
glShaderSource (eglglessink->eglglesctx.fragshader, 1,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1,
(const GLchar **) &tmp_prog, NULL);
eglglessink->eglglesctx.n_textures = 1;
texnames[0] = "tex";
@ -1776,7 +1865,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
case GST_VIDEO_FORMAT_xBGR:
case GST_VIDEO_FORMAT_ABGR:
tmp_prog = g_strdup_printf (frag_REORDER_prog, 'a', 'b', 'g');
glShaderSource (eglglessink->eglglesctx.fragshader, 1,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1,
(const GLchar **) &tmp_prog, NULL);
eglglessink->eglglesctx.n_textures = 1;
texnames[0] = "tex";
@ -1785,7 +1874,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
case GST_VIDEO_FORMAT_RGBx:
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_RGB16:
glShaderSource (eglglessink->eglglesctx.fragshader, 1, &frag_COPY_prog,
glShaderSource (eglglessink->eglglesctx.fragshader[0], 1, &frag_COPY_prog,
NULL);
eglglessink->eglglesctx.n_textures = 1;
texnames[0] = "tex";
@ -1798,38 +1887,40 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
if (got_gl_error ("glShaderSource fragment"))
goto HANDLE_ERROR;
glCompileShader (eglglessink->eglglesctx.fragshader);
glCompileShader (eglglessink->eglglesctx.fragshader[0]);
if (got_gl_error ("glCompileShader fragment"))
goto HANDLE_ERROR;
glGetShaderiv (eglglessink->eglglesctx.fragshader, GL_COMPILE_STATUS, &test);
glGetShaderiv (eglglessink->eglglesctx.fragshader[0], GL_COMPILE_STATUS,
&test);
if (test != GL_FALSE)
GST_DEBUG_OBJECT (eglglessink, "Successfully compiled fragment shader");
else {
GST_ERROR_OBJECT (eglglessink, "Couldn't compile fragment shader");
glGetShaderiv (eglglessink->eglglesctx.fragshader, GL_INFO_LOG_LENGTH,
glGetShaderiv (eglglessink->eglglesctx.fragshader[0], GL_INFO_LOG_LENGTH,
&test);
info_log = g_new0 (GLchar, test);
glGetShaderInfoLog (eglglessink->eglglesctx.fragshader, test, NULL,
glGetShaderInfoLog (eglglessink->eglglesctx.fragshader[0], test, NULL,
info_log);
GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log);
g_free (info_log);
goto HANDLE_ERROR;
}
eglglessink->eglglesctx.glslprogram = glCreateProgram ();
eglglessink->eglglesctx.glslprogram[0] = glCreateProgram ();
if (got_gl_error ("glCreateProgram"))
goto HANDLE_ERROR;
glAttachShader (eglglessink->eglglesctx.glslprogram,
eglglessink->eglglesctx.vertshader);
glAttachShader (eglglessink->eglglesctx.glslprogram[0],
eglglessink->eglglesctx.vertshader[0]);
if (got_gl_error ("glAttachShader vertices"))
goto HANDLE_ERROR;
glAttachShader (eglglessink->eglglesctx.glslprogram,
eglglessink->eglglesctx.fragshader);
glAttachShader (eglglessink->eglglesctx.glslprogram[0],
eglglessink->eglglesctx.fragshader[0]);
if (got_gl_error ("glAttachShader fragments"))
goto HANDLE_ERROR;
glLinkProgram (eglglessink->eglglesctx.glslprogram);
glGetProgramiv (eglglessink->eglglesctx.glslprogram, GL_LINK_STATUS, &test);
glLinkProgram (eglglessink->eglglesctx.glslprogram[0]);
glGetProgramiv (eglglessink->eglglesctx.glslprogram[0], GL_LINK_STATUS,
&test);
if (test != GL_FALSE)
GST_DEBUG_OBJECT (eglglessink, "GLES: Successfully linked program");
else {
@ -1837,14 +1928,104 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
goto HANDLE_ERROR;
}
glUseProgram (eglglessink->eglglesctx.glslprogram);
if (got_gl_error ("glUseProgram"))
eglglessink->eglglesctx.position_loc[0] =
glGetAttribLocation (eglglessink->eglglesctx.glslprogram[0], "position");
eglglessink->eglglesctx.texpos_loc =
glGetAttribLocation (eglglessink->eglglesctx.glslprogram[0], "texpos");
glEnableVertexAttribArray (eglglessink->eglglesctx.position_loc[0]);
if (got_gl_error ("glEnableVertexAttribArray"))
goto HANDLE_ERROR;
eglglessink->eglglesctx.position_loc =
glGetAttribLocation (eglglessink->eglglesctx.glslprogram, "position");
eglglessink->eglglesctx.texpos_loc =
glGetAttribLocation (eglglessink->eglglesctx.glslprogram, "texpos");
glEnableVertexAttribArray (eglglessink->eglglesctx.texpos_loc);
if (got_gl_error ("glEnableVertexAttribArray"))
goto HANDLE_ERROR;
/* Build shader program for black borders */
eglglessink->eglglesctx.vertshader[1] = glCreateShader (GL_VERTEX_SHADER);
GST_DEBUG_OBJECT (eglglessink, "Sending %s to handle %d", vert_COPY_prog,
eglglessink->eglglesctx.vertshader[1]);
glShaderSource (eglglessink->eglglesctx.vertshader[1], 1,
&vert_COPY_prog_no_tex, NULL);
if (got_gl_error ("glShaderSource vertex"))
goto HANDLE_ERROR;
glCompileShader (eglglessink->eglglesctx.vertshader[1]);
if (got_gl_error ("glCompileShader vertex"))
goto HANDLE_ERROR;
glGetShaderiv (eglglessink->eglglesctx.vertshader[1], GL_COMPILE_STATUS,
&test);
if (test != GL_FALSE)
GST_DEBUG_OBJECT (eglglessink, "Successfully compiled vertex shader");
else {
GST_ERROR_OBJECT (eglglessink, "Couldn't compile vertex shader");
glGetShaderiv (eglglessink->eglglesctx.vertshader[1], GL_INFO_LOG_LENGTH,
&test);
info_log = g_new0 (GLchar, test);
glGetShaderInfoLog (eglglessink->eglglesctx.vertshader[1], test, NULL,
info_log);
GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log);
g_free (info_log);
goto HANDLE_ERROR;
}
eglglessink->eglglesctx.fragshader[1] = glCreateShader (GL_FRAGMENT_SHADER);
glShaderSource (eglglessink->eglglesctx.fragshader[1], 1, &frag_BLACK_prog,
NULL);
if (got_gl_error ("glShaderSource fragment"))
goto HANDLE_ERROR;
glCompileShader (eglglessink->eglglesctx.fragshader[1]);
if (got_gl_error ("glCompileShader fragment"))
goto HANDLE_ERROR;
glGetShaderiv (eglglessink->eglglesctx.fragshader[1], GL_COMPILE_STATUS,
&test);
if (test != GL_FALSE)
GST_DEBUG_OBJECT (eglglessink, "Successfully compiled fragment shader");
else {
GST_ERROR_OBJECT (eglglessink, "Couldn't compile fragment shader");
glGetShaderiv (eglglessink->eglglesctx.fragshader[1], GL_INFO_LOG_LENGTH,
&test);
info_log = g_new0 (GLchar, test);
glGetShaderInfoLog (eglglessink->eglglesctx.fragshader[1], test, NULL,
info_log);
GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log);
g_free (info_log);
goto HANDLE_ERROR;
}
eglglessink->eglglesctx.glslprogram[1] = glCreateProgram ();
if (got_gl_error ("glCreateProgram"))
goto HANDLE_ERROR;
glAttachShader (eglglessink->eglglesctx.glslprogram[1],
eglglessink->eglglesctx.vertshader[1]);
if (got_gl_error ("glAttachShader vertices"))
goto HANDLE_ERROR;
glAttachShader (eglglessink->eglglesctx.glslprogram[1],
eglglessink->eglglesctx.fragshader[1]);
if (got_gl_error ("glAttachShader fragments"))
goto HANDLE_ERROR;
glLinkProgram (eglglessink->eglglesctx.glslprogram[1]);
glGetProgramiv (eglglessink->eglglesctx.glslprogram[1], GL_LINK_STATUS,
&test);
if (test != GL_FALSE)
GST_DEBUG_OBJECT (eglglessink, "GLES: Successfully linked program");
else {
GST_ERROR_OBJECT (eglglessink, "Couldn't link program");
goto HANDLE_ERROR;
}
eglglessink->eglglesctx.position_loc[1] =
glGetAttribLocation (eglglessink->eglglesctx.glslprogram[1], "position");
glEnableVertexAttribArray (eglglessink->eglglesctx.position_loc[1]);
if (got_gl_error ("glEnableVertexAttribArray"))
goto HANDLE_ERROR;
glUseProgram (eglglessink->eglglesctx.glslprogram[0]);
/* Generate and bind texture */
if (!eglglessink->have_texture) {
@ -1869,7 +2050,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
goto HANDLE_ERROR_LOCKED;
eglglessink->eglglesctx.tex_loc[i] =
glGetUniformLocation (eglglessink->eglglesctx.glslprogram,
glGetUniformLocation (eglglessink->eglglesctx.glslprogram[0],
texnames[i]);
glUniform1i (eglglessink->eglglesctx.tex_loc[i], i);
@ -1888,6 +2069,7 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
eglglessink->have_texture = TRUE;
}
glUseProgram (0);
g_free (tmp_prog);
@ -1955,8 +2137,7 @@ gst_eglglessink_choose_config (GstEglGlesSink * eglglessink)
if ((eglChooseConfig (eglglessink->eglglesctx.display,
eglglessink->selected_fmt->attribs,
&eglglessink->eglglesctx.config, 1,
&egl_configs)) == EGL_FALSE) {
&eglglessink->eglglesctx.config, 1, &egl_configs)) == EGL_FALSE) {
show_egl_error ("eglChooseConfig");
GST_ERROR_OBJECT (eglglessink, "eglChooseConfig failed");
goto HANDLE_EGL_ERROR;
@ -2041,8 +2222,7 @@ queue_item_destroy (GstDataQueueItem * item)
}
static GstFlowReturn
gst_eglglessink_queue_buffer (GstEglGlesSink * eglglessink,
GstBuffer * buf)
gst_eglglessink_queue_buffer (GstEglGlesSink * eglglessink, GstBuffer * buf)
{
GstDataQueueItem *item = g_slice_new0 (GstDataQueueItem);
@ -2065,7 +2245,8 @@ gst_eglglessink_queue_buffer (GstEglGlesSink * eglglessink,
if (buf) {
GST_DEBUG_OBJECT (eglglessink, "Waiting for buffer to be rendered");
g_cond_wait (eglglessink->render_cond, eglglessink->render_lock);
GST_DEBUG_OBJECT (eglglessink, "Buffer rendered: %s", gst_flow_get_name (eglglessink->last_flow));
GST_DEBUG_OBJECT (eglglessink, "Buffer rendered: %s",
gst_flow_get_name (eglglessink->last_flow));
g_mutex_unlock (eglglessink->render_lock);
}
@ -2272,8 +2453,7 @@ gst_eglglessink_render_and_display (GstEglGlesSink * eglglessink,
if (!eglglessink->force_aspect_ratio) {
eglglessink->display_region.x = 0;
eglglessink->display_region.y = 0;
eglglessink->display_region.w =
eglglessink->eglglesctx.surface_width;
eglglessink->display_region.w = eglglessink->eglglesctx.surface_width;
eglglessink->display_region.h =
eglglessink->eglglesctx.surface_height;
} else {
@ -2311,11 +2491,53 @@ gst_eglglessink_render_and_display (GstEglGlesSink * eglglessink,
&eglglessink->display_region, TRUE);
}
GST_OBJECT_UNLOCK (eglglessink);
glViewport (eglglessink->display_region.x,
eglglessink->display_region.y,
eglglessink->display_region.w, eglglessink->display_region.h);
glViewport (0, 0,
eglglessink->eglglesctx.surface_width,
eglglessink->eglglesctx.surface_height);
if (!gst_eglglessink_setup_vbo (eglglessink, FALSE)) {
GST_ERROR_OBJECT (eglglessink, "VBO setup failed");
goto HANDLE_ERROR;
}
}
/* Draw black borders */
GST_DEBUG_OBJECT (eglglessink, "Drawing black border 1");
glUseProgram (eglglessink->eglglesctx.glslprogram[1]);
glVertexAttribPointer (eglglessink->eglglesctx.position_loc[1], 3,
GL_FLOAT, GL_FALSE, sizeof (coord5),
(gpointer) (4 * sizeof (coord5)));
if (got_gl_error ("glVertexAttribPointer"))
goto HANDLE_ERROR;
glDrawElements (GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);
if (got_gl_error ("glDrawElements"))
goto HANDLE_ERROR;
GST_DEBUG_OBJECT (eglglessink, "Drawing black border 2");
glVertexAttribPointer (eglglessink->eglglesctx.position_loc[1], 3,
GL_FLOAT, GL_FALSE, sizeof (coord5),
(gpointer) (8 * sizeof (coord5)));
if (got_gl_error ("glVertexAttribPointer"))
goto HANDLE_ERROR;
glDrawElements (GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);
if (got_gl_error ("glDrawElements"))
goto HANDLE_ERROR;
/* Draw video frame */
GST_DEBUG_OBJECT (eglglessink, "Drawing video frame");
glUseProgram (eglglessink->eglglesctx.glslprogram[0]);
glVertexAttribPointer (eglglessink->eglglesctx.position_loc[0], 3,
GL_FLOAT, GL_FALSE, sizeof (coord5),
(gpointer) (0 * sizeof (coord5)));
if (got_gl_error ("glVertexAttribPointer"))
goto HANDLE_ERROR;
glDrawElements (GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);
if (got_gl_error ("glDrawElements"))
goto HANDLE_ERROR;
@ -2381,7 +2603,7 @@ gst_eglglessink_getcaps (GstBaseSink * bsink)
}
static gboolean
gst_eglglessink_configure_caps (GstEglGlesSink *eglglessink, GstCaps * caps)
gst_eglglessink_configure_caps (GstEglGlesSink * eglglessink, GstCaps * caps)
{
gboolean ret = TRUE;
gint width, height;
@ -2431,7 +2653,6 @@ gst_eglglessink_configure_caps (GstEglGlesSink *eglglessink, GstCaps * caps)
if (eglglessink->have_vbo) {
glDeleteBuffers (1, &eglglessink->eglglesctx.position_buffer);
glDeleteBuffers (1, &eglglessink->eglglesctx.texpos_buffer);
glDeleteBuffers (1, &eglglessink->eglglesctx.index_buffer);
eglglessink->have_vbo = FALSE;
}
@ -2443,15 +2664,26 @@ gst_eglglessink_configure_caps (GstEglGlesSink *eglglessink, GstCaps * caps)
eglglessink->eglglesctx.n_textures = 0;
}
if (eglglessink->eglglesctx.glslprogram) {
glDetachShader (eglglessink->eglglesctx.glslprogram,
eglglessink->eglglesctx.fragshader);
glDetachShader (eglglessink->eglglesctx.glslprogram,
eglglessink->eglglesctx.vertshader);
glDeleteProgram (eglglessink->eglglesctx.glslprogram);
glDeleteShader (eglglessink->eglglesctx.fragshader);
glDeleteShader (eglglessink->eglglesctx.vertshader);
eglglessink->eglglesctx.glslprogram = 0;
if (eglglessink->eglglesctx.glslprogram[0]) {
glDetachShader (eglglessink->eglglesctx.glslprogram[0],
eglglessink->eglglesctx.fragshader[0]);
glDetachShader (eglglessink->eglglesctx.glslprogram[0],
eglglessink->eglglesctx.vertshader[0]);
glDeleteProgram (eglglessink->eglglesctx.glslprogram[0]);
glDeleteShader (eglglessink->eglglesctx.fragshader[0]);
glDeleteShader (eglglessink->eglglesctx.vertshader[0]);
eglglessink->eglglesctx.glslprogram[0] = 0;
}
if (eglglessink->eglglesctx.glslprogram[1]) {
glDetachShader (eglglessink->eglglesctx.glslprogram[1],
eglglessink->eglglesctx.fragshader[1]);
glDetachShader (eglglessink->eglglesctx.glslprogram[1],
eglglessink->eglglesctx.vertshader[1]);
glDeleteProgram (eglglessink->eglglesctx.glslprogram[1]);
glDeleteShader (eglglessink->eglglesctx.fragshader[1]);
glDeleteShader (eglglessink->eglglesctx.vertshader[1]);
eglglessink->eglglesctx.glslprogram[1] = 0;
}
}
@ -2509,7 +2741,8 @@ gst_eglglessink_configure_caps (GstEglGlesSink *eglglessink, GstCaps * caps)
eglglessink->eglglesctx.window = window;
eglglessink->have_window = TRUE;
}
GST_DEBUG_OBJECT (eglglessink, "Using window handle %p", eglglessink->eglglesctx.window);
GST_DEBUG_OBJECT (eglglessink, "Using window handle %p",
eglglessink->eglglesctx.window);
eglglessink->eglglesctx.used_window = eglglessink->eglglesctx.window;
GST_OBJECT_UNLOCK (eglglessink);
gst_x_overlay_got_window_handle (GST_X_OVERLAY (eglglessink),
@ -2522,13 +2755,6 @@ gst_eglglessink_configure_caps (GstEglGlesSink *eglglessink, GstCaps * caps)
}
}
if (!eglglessink->have_vbo) {
if (!gst_eglglessink_setup_vbo (eglglessink, FALSE)) {
GST_ERROR_OBJECT (eglglessink, "VBO setup failed");
goto HANDLE_ERROR;
}
}
SUCCEED:
GST_INFO_OBJECT (eglglessink, "Configured caps successfully");
return TRUE;
@ -2657,7 +2883,7 @@ gst_eglglessink_finalize (GObject * object)
g_cond_free (eglglessink->render_cond);
eglglessink->render_cond = NULL;
if (eglglessink->render_lock);
g_mutex_free (eglglessink->render_lock);
g_mutex_free (eglglessink->render_lock);
eglglessink->render_lock = NULL;
G_OBJECT_CLASS (parent_class)->finalize (object);
@ -2781,7 +3007,8 @@ gst_eglglessink_class_init (GstEglGlesSinkClass * klass)
}
static gboolean
queue_check_full_func (GstDataQueue * queue, guint visible, guint bytes, guint64 time, gpointer checkdata)
queue_check_full_func (GstDataQueue * queue, guint visible, guint bytes,
guint64 time, gpointer checkdata)
{
return visible != 0;
}