eagl: fix handling of surface dimension changes

Detect when the eagl surface changed its dimension (when the user rotates
the device for example) and adapt the egl internals to draw to that,
preventing that ios resizes the image again when drawing.

This is particularly harmful when eagl would scale down a image
to draw and the ios screen would scale it back up because the
surface is now bigger than when the element was configured.
This commit is contained in:
Thiago Santos 2013-05-15 11:49:22 -03:00
parent 27d726fbfa
commit ef66e39d03
2 changed files with 49 additions and 20 deletions

View file

@ -56,11 +56,15 @@ struct _GstEaglContext
EAGLContext *eagl_context;
GLuint framebuffer;
GLuint color_renderbuffer;
GLuint depth_renderbuffer;
UIView *window;
UIView *used_window;
};
static gboolean
gst_egl_adaptation_update_surface (GstEglAdaptationContext * ctx);
void
gst_egl_adaptation_init (GstEglAdaptationContext * ctx)
{
@ -179,8 +183,13 @@ gst_egl_adaptation_create_surface (GstEglAdaptationContext * ctx)
__block CAEAGLLayer *eaglLayer = (CAEAGLLayer *)[ctx->eaglctx->window layer];
dispatch_sync(dispatch_get_main_queue(), ^{
/* Allocate framebuffer */
glGenFramebuffers(1, &framebuffer);
if (ctx->eaglctx->framebuffer) {
framebuffer = ctx->eaglctx->framebuffer;
} else {
/* Allocate framebuffer */
glGenFramebuffers(1, &framebuffer);
}
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
/* Allocate color render buffer */
@ -212,6 +221,9 @@ gst_egl_adaptation_create_surface (GstEglAdaptationContext * ctx)
ctx->eaglctx->framebuffer = framebuffer;
ctx->eaglctx->color_renderbuffer = colorRenderbuffer;
ctx->eaglctx->depth_renderbuffer = colorRenderbuffer;
ctx->surface_width = width;
ctx->surface_height = height;
glBindRenderbuffer(GL_RENDERBUFFER, ctx->eaglctx->color_renderbuffer);
return TRUE;
@ -260,18 +272,18 @@ gboolean
gst_egl_adaptation_update_surface_dimensions (GstEglAdaptationContext *
ctx)
{
GLint width;
GLint height;
CAEAGLLayer *layer = (CAEAGLLayer *)[ctx->eaglctx->window layer];
CGSize size = layer.frame.size;
/* Get renderbuffer width/height */
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
if (width != ctx->surface_width || height != ctx->surface_height) {
ctx->surface_width = width;
ctx->surface_height = height;
GST_INFO_OBJECT (ctx->element, "Got surface of %dx%d pixels", width,
height);
if (size.width != ctx->surface_width || size.height != ctx->surface_height) {
ctx->surface_width = size.width;
ctx->surface_height = size.height;
GST_INFO_OBJECT (ctx->element, "Got surface of %dx%d pixels",
(gint) size.width, (gint) size.height);
if (!gst_egl_adaptation_update_surface (ctx)) {
GST_WARNING_OBJECT (ctx->element, "Failed to update surface "
"to new dimensions");
}
return TRUE;
}
@ -302,6 +314,23 @@ gst_egl_adaptation_destroy_surface (GstEglAdaptationContext * ctx)
}
}
static gboolean
gst_egl_adaptation_update_surface (GstEglAdaptationContext * ctx)
{
glBindFramebuffer(GL_FRAMEBUFFER, ctx->eaglctx->framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(1, &ctx->eaglctx->depth_renderbuffer);
glBindRenderbuffer (GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(1, &ctx->eaglctx->color_renderbuffer);
return gst_egl_adaptation_create_surface (ctx);
}
void
gst_egl_adaptation_destroy_context (GstEglAdaptationContext * ctx)
{

View file

@ -204,8 +204,7 @@ static void gst_eglglessink_set_render_rectangle (GstVideoOverlay * overlay,
/* Utility */
static gboolean gst_eglglessink_create_window (GstEglGlesSink *
eglglessink, gint width, gint height);
static gboolean gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink,
gboolean reset);
static gboolean gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink);
static gboolean
gst_eglglessink_configure_caps (GstEglGlesSink * eglglessink, GstCaps * caps);
static GstFlowReturn gst_eglglessink_upload (GstEglGlesSink * sink,
@ -740,17 +739,17 @@ gst_eglglessink_expose (GstVideoOverlay * overlay)
}
static gboolean
gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink)
{
gdouble render_width, render_height;
gdouble texture_width, texture_height;
gdouble x1, x2, y1, y2;
gdouble tx1, tx2, ty1, ty2;
GST_INFO_OBJECT (eglglessink, "VBO setup. have_vbo:%d, should reset %d",
eglglessink->egl_context->have_vbo, reset);
GST_INFO_OBJECT (eglglessink, "VBO setup. have_vbo:%d",
eglglessink->egl_context->have_vbo);
if (eglglessink->egl_context->have_vbo && reset) {
if (eglglessink->egl_context->have_vbo) {
glDeleteBuffers (1, &eglglessink->egl_context->position_buffer);
glDeleteBuffers (1, &eglglessink->egl_context->index_buffer);
eglglessink->egl_context->have_vbo = FALSE;
@ -929,6 +928,7 @@ gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
goto HANDLE_ERROR_LOCKED;
eglglessink->egl_context->have_vbo = TRUE;
GST_DEBUG_OBJECT (eglglessink, "VBO setup done");
return TRUE;
@ -1673,7 +1673,7 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink)
glClear (GL_COLOR_BUFFER_BIT);
}
if (!gst_eglglessink_setup_vbo (eglglessink, FALSE)) {
if (!gst_eglglessink_setup_vbo (eglglessink)) {
GST_OBJECT_UNLOCK (eglglessink);
GST_ERROR_OBJECT (eglglessink, "VBO setup failed");
goto HANDLE_ERROR;