From ef66e39d0384576b06eff506dcc9f61e9e6a49fe Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 15 May 2013 11:49:22 -0300 Subject: [PATCH] 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. --- ext/eglgles/gstegladaptation_eagl.m | 55 ++++++++++++++++++++++------- ext/eglgles/gsteglglessink.c | 14 ++++---- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/ext/eglgles/gstegladaptation_eagl.m b/ext/eglgles/gstegladaptation_eagl.m index aae27215d2..2e091b8b66 100644 --- a/ext/eglgles/gstegladaptation_eagl.m +++ b/ext/eglgles/gstegladaptation_eagl.m @@ -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) { diff --git a/ext/eglgles/gsteglglessink.c b/ext/eglgles/gsteglglessink.c index 6cc0af87e8..0e17b7bab1 100644 --- a/ext/eglgles/gsteglglessink.c +++ b/ext/eglgles/gsteglglessink.c @@ -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;