gl_common: Add API for redirecting render to texture
authorDerek Foreman <derekf@osg.samsung.com>
Mon, 28 Mar 2016 17:06:46 +0000 (12:06 -0500)
committerMike Blumenkrantz <zmike@osg.samsung.com>
Fri, 1 Apr 2016 10:49:50 +0000 (06:49 -0400)
New API allows a context to be redirected to texture.  When rendering is
complete the texture can be unbound from the frame buffer and used for
post-processing effects.

Signed-off-by: Derek Foreman <derekf@osg.samsung.com>
Signed-off-by: Mike Blumenkrantz <zmike@osg.samsung.com>
src/modules/evas/engines/gl_common/evas_gl_common.h
src/modules/evas/engines/gl_common/evas_gl_context.c

index 4acb119..e16076d 100644 (file)
@@ -348,6 +348,13 @@ struct _Evas_Engine_GL_Context
    int gles_version;
 
    RGBA_Image *font_surface;
+
+   struct {
+      GLuint fb;
+      GLuint texture;
+      GLuint depth_buffer;
+      Eina_Bool active : 1;
+   } redirect;
 };
 
 struct _Evas_GL_Texture_Pool
@@ -525,6 +532,7 @@ EAPI void        *evas_gl_common_current_context_get(void);
 typedef int (*Evas_GL_Preload)(void);
 typedef void (*Evas_GL_Common_Image_Call)(Evas_GL_Image *im);
 typedef void (*Evas_GL_Common_Context_Call)(Evas_Engine_GL_Context *gc);
+typedef GLuint (*Evas_GL_Common_Context_Call_GLuint_Return)(Evas_Engine_GL_Context *gc);
 typedef Evas_GL_Image *(*Evas_GL_Common_Image_New_From_Data)(Evas_Engine_GL_Context *gc, unsigned int w, unsigned int h, DATA32 *data, int alpha, Evas_Colorspace cspace);
 typedef void (*Evas_GL_Preload_Render_Call)(evas_gl_make_current_cb make_current, void *engine_data);
 typedef Evas_Engine_GL_Context *(*Evas_GL_Common_Context_New)(void);
@@ -534,6 +542,13 @@ typedef void (*Evas_Gl_Symbols)(void *(*GetProcAddress)(const char *sym));
 
 EAPI void __evas_gl_err(int err, const char *file, const char *func, int line, const char *op);
 
+EAPI void         evas_gl_common_context_unredirect(Evas_Engine_GL_Context *gc);
+EAPI void         evas_gl_common_context_redirect(Evas_Engine_GL_Context *gc);
+EAPI GLuint       evas_gl_common_context_redirect_texture_get(Evas_Engine_GL_Context *gc);
+EAPI void         evas_gl_common_context_redirect_bind(Evas_Engine_GL_Context *gc);
+EAPI void         evas_gl_common_context_redirect_unbind(Evas_Engine_GL_Context *gc);
+
+
 void              evas_gl_common_tiling_start(Evas_Engine_GL_Context *gc,
                                               int rot, int gw, int gh,
                                               int cx, int cy, int cw, int ch,
index 9d5ffb0..53810b7 100644 (file)
@@ -1164,6 +1164,7 @@ EAPI void
 evas_gl_common_context_resize(Evas_Engine_GL_Context *gc, int w, int h, int rot)
 {
    if ((gc->w == w) && (gc->h == h) && (gc->rot == rot)) return;
+   if (gc->redirect.active) evas_gl_common_context_redirect(gc);
    evas_gl_common_context_flush(gc);
    gc->change.size = 1;
    gc->rot = rot;
@@ -1172,6 +1173,68 @@ evas_gl_common_context_resize(Evas_Engine_GL_Context *gc, int w, int h, int rot)
    if (_evas_gl_common_context == gc) _evas_gl_common_viewport_set(gc);
 }
 
+EAPI void
+evas_gl_common_context_unredirect(Evas_Engine_GL_Context *gc)
+{
+   glBindFramebuffer(GL_FRAMEBUFFER, 0);
+   glDeleteTextures(1, &gc->redirect.texture);
+   glDeleteRenderbuffers(1, &gc->redirect.depth_buffer);
+   glDeleteFramebuffers(1, &gc->redirect.fb);
+   gc->redirect.active = EINA_FALSE;
+}
+
+EAPI void
+evas_gl_common_context_redirect(Evas_Engine_GL_Context *gc)
+{
+   if (gc->redirect.active) evas_gl_common_context_unredirect(gc);
+
+   /* Create a framebuffer object for RTT */
+   glGenTextures(1, &gc->redirect.texture);
+   glBindTexture(GL_TEXTURE_2D, gc->redirect.texture);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gc->w, gc->h,
+                0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+   glGenFramebuffers(1, &gc->redirect.fb);
+   glBindFramebuffer(GL_FRAMEBUFFER, gc->redirect.fb);
+
+   glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                          GL_TEXTURE_2D, gc->redirect.texture, 0);
+
+   glGenRenderbuffers(1, &gc->redirect.depth_buffer);
+   glBindRenderbuffer(GL_RENDERBUFFER, gc->redirect.depth_buffer);
+   glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, gc->w, gc->h);
+   glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                             GL_RENDERBUFFER, gc->redirect.depth_buffer);
+
+   glBindFramebuffer(GL_FRAMEBUFFER, gc->redirect.fb);
+   gc->redirect.active = EINA_TRUE;
+}
+
+EAPI GLuint
+evas_gl_common_context_redirect_texture_get(Evas_Engine_GL_Context *gc)
+{
+   if (!gc->redirect.active) return 0;
+   return gc->redirect.texture;
+}
+
+EAPI void
+evas_gl_common_context_redirect_bind(Evas_Engine_GL_Context *gc)
+{
+   if (!gc->redirect.active) return;
+   glBindFramebuffer(GL_FRAMEBUFFER, gc->redirect.fb);
+}
+
+EAPI void
+evas_gl_common_context_redirect_unbind(Evas_Engine_GL_Context *gc EINA_UNUSED)
+{
+   glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
 void
 evas_gl_common_tiling_start(Evas_Engine_GL_Context *gc EINA_UNUSED,
                             int rot, int gw, int gh,
@@ -1262,7 +1325,10 @@ evas_gl_common_context_target_surface_set(Evas_Engine_GL_Context *gc,
 # endif
 #endif
    if (gc->pipe[0].shader.surface == gc->def_surface)
-     glsym_glBindFramebuffer(GL_FRAMEBUFFER, 0);
+     {
+        if (gc->redirect.active) glBindFramebuffer(GL_FRAMEBUFFER, gc->redirect.fb);
+        else glsym_glBindFramebuffer(GL_FRAMEBUFFER, 0);
+     }
    else
       glsym_glBindFramebuffer(GL_FRAMEBUFFER, surface->tex->pt->fb);
    _evas_gl_common_viewport_set(gc);