ector/gl: updated antialiasing drawing in gl backend.
authorsubhransu mohanty <smohantty@gmail.com>
Wed, 30 Nov 2016 07:24:34 +0000 (16:24 +0900)
committerWonki Kim <wonki_.kim@samsung.com>
Mon, 2 Jan 2017 07:23:56 +0000 (16:23 +0900)
Change-Id: I5a0a6b39c4ec605f825c426821f821459ae0e776

src/lib/ector/ector_gl_internal.h
src/lib/ector/ector_main.c
src/lib/ector/gl/ector_gl_private.h
src/lib/ector/gl/ector_gl_surface.c

index 3dc073a..6a73cd0 100644 (file)
@@ -781,6 +781,8 @@ struct _Ector_GL_API {
    // Struct is same as Evas_GL_API version 1 without extensions
 
    int            init;
+   int            version;
+   int            ext_ms_render_to_tex;
 
    void         (*glActiveTexture) (GLenum texture);
    void         (*glAttachShader) (GLuint program, GLuint shader);
@@ -880,7 +882,6 @@ struct _Ector_GL_API {
    void         (*glReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
    void         (*glReleaseShaderCompiler) (void);
    void         (*glRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-   void         (*glRenderbufferStorageMultisample) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
    void         (*glSampleCoverage) (GLclampf value, GLboolean invert);
    void         (*glScissor) (GLint x, GLint y, GLsizei width, GLsizei height);
    void         (*glShaderBinary) (GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length);
@@ -928,9 +929,21 @@ struct _Ector_GL_API {
    void         (*glVertexAttrib4fv) (GLuint indx, const GLfloat* values);
    void         (*glVertexAttribPointer) (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
    void         (*glViewport) (GLint x, GLint y, GLsizei width, GLsizei height);
+   void*        (*glXGetProcAddress)(char const * procname);
+   void*        (*eglGetProcAddress)(char const * procname);
+
+   // openGL ES 2 MSAA extension GL_EXT_multisampled_render_to_texture
+   void         (*glRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+   void         (*glFramebufferTexture2DMultisampleEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, int level, GLsizei samples);
+
+   // openGL ES 3
+   void         (*glRenderbufferStorageMultisample) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
    void         (*glBlitFramebuffer) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+
+
    // custom function
    Eina_Bool    (*glFuncExist) (void* gl_func);
+   void         (*finalize)(void);
 };
 
 #endif
index f5c963c..bea7600 100644 (file)
@@ -57,28 +57,101 @@ ector_init(void)
    return 0;
 }
 
-static void
-no_gl_impl()
+static int
+_gl_version()
 {
+   char *str;
+
+   str = (char *)GL.glGetString(GL_VERSION);
+   if (!str)
+     {
+        return 0;
+     }
 
+   if (strstr(str, "OpenGL ES 3"))
+     {
+        return 3;
+     }
+
+   if (strstr(str, "OpenGL ES 2"))
+     {
+        return 2;
+     }
+
+    if (strstr(str, "3.") || strstr(str, "4."))
+     {
+        return 3;
+     }
+
+    if (strstr(str, "2."))
+     {
+        return 2;
+     }
+   return 0;
+}
+
+static int
+_gl_extension(const char * extension)
+{
+   char *extensions;
+   extensions = (char *)GL.glGetString(GL_EXTENSIONS);
+   if (strstr(extensions, extension))
+      return 1;
+   return 0;
 }
 
 static Eina_Bool
 gl_func_exist(void *fp)
 {
-   if (fp == no_gl_impl) return EINA_FALSE;
+   if (!fp) return EINA_FALSE;
 
    return EINA_TRUE;
 }
 
+static void
+_gl_finalize()
+{
+   if (GL.init) return;
+   GL.init = EINA_TRUE;
+   GL.version = _gl_version();
+
+   if (GL.version == 2)
+     {
+        GL.glRenderbufferStorageMultisample = NULL;
+        GL.glBlitFramebuffer = NULL;
+        GL.glRenderbufferStorageMultisampleEXT = NULL;
+        GL.glFramebufferTexture2DMultisampleEXT = NULL;
+        if (_gl_extension("GL_EXT_multisampled_render_to_texture"))
+          {
+             if (GL.eglGetProcAddress)
+               {
+                  GL.glRenderbufferStorageMultisampleEXT = GL.eglGetProcAddress("glRenderbufferStorageMultisampleEXT");
+                  GL.glFramebufferTexture2DMultisampleEXT = GL.eglGetProcAddress("glFramebufferTexture2DMultisampleEXT");
+               }
+             if (GL.glXGetProcAddress)
+               {
+                  GL.glRenderbufferStorageMultisampleEXT = GL.glXGetProcAddress("glRenderbufferStorageMultisampleEXT");
+                  GL.glFramebufferTexture2DMultisampleEXT = GL.glXGetProcAddress("glFramebufferTexture2DMultisampleEXT");
+               }
+             GL.ext_ms_render_to_tex = 1;
+          }
+     }
+   if (GL.version == 3)
+     {
+        GL.glRenderbufferStorageMultisampleEXT = 0;
+        GL.glFramebufferTexture2DMultisampleEXT = 0;
+     }
+
+}
+
 EAPI Eina_Bool
 ector_glsym_set(void *(*glsym)(void *lib, const char *name), void *lib)
 {
-   Eina_Bool r = EINA_TRUE;
+   GL.init = 0;
 
    if (!glsym) return EINA_FALSE;
 
-#define ORD(a) do { GL.a = glsym(lib, #a); if (!GL.a) { GL.a = (void*) no_gl_impl; r = EINA_FALSE; } } while (0)
+#define ORD(a) GL.a = glsym(lib, #a);
 
    ORD(glActiveTexture);
    ORD(glAttachShader);
@@ -178,7 +251,6 @@ ector_glsym_set(void *(*glsym)(void *lib, const char *name), void *lib)
    ORD(glReadPixels);
    ORD(glReleaseShaderCompiler);
    ORD(glRenderbufferStorage);
-   ORD(glRenderbufferStorageMultisample);
    ORD(glSampleCoverage);
    ORD(glScissor);
    ORD(glShaderBinary);
@@ -226,10 +298,16 @@ ector_glsym_set(void *(*glsym)(void *lib, const char *name), void *lib)
    ORD(glVertexAttrib4fv);
    ORD(glVertexAttribPointer);
    ORD(glViewport);
+   ORD(eglGetProcAddress);
+   ORD(glXGetProcAddress);
+
+   ORD(glRenderbufferStorageMultisample);
    ORD(glBlitFramebuffer);
+   GL.finalize = _gl_finalize;
    GL.glFuncExist = gl_func_exist;
-   GL.init = r;
-   return r;
+   GL.ext_ms_render_to_tex = 0;
+
+   return EINA_TRUE;
 }
 
 EAPI int
index b00e737..67053d2 100644 (file)
@@ -2,11 +2,27 @@
 #define ECTOR_GL_PRIVATE_H_
 
 #define SHAD_VERTEX 0
+#define SHAD_TEXUV  1
+
 #define GL_STENCIL_HIGH_BIT  0x80
 
 typedef struct _Ector_Renderer_Gl_Gradient_Data    Ector_Renderer_Gl_Gradient_Data;
 typedef struct _Ector_Gl_Surface_Data              Ector_Gl_Surface_Data;
 
+typedef struct _Shader_Program                     Shader_Program;
+
+struct _Shader_Program
+{
+  GLuint program;
+  GLuint v_shader;
+  GLuint f_shader;
+  GLuint u_color;
+  GLuint u_mvp;
+  GLuint u_pos;
+  GLuint u_texture;
+};
+
+
 struct _Ector_Gl_Surface_Data
 {
    struct {
@@ -15,12 +31,9 @@ struct _Ector_Gl_Surface_Data
    struct {
       int x, y;
    } offset;
-   int width;
-   int height;
-   GLuint simple_program;
-   GLuint uniform_color;
-   GLuint uniform_mvp;
-   GLuint uniform_pos;
+
+   Shader_Program *simple_shader;
+   Shader_Program *texture_shader;
 
    struct {
       int w, h;
@@ -28,12 +41,14 @@ struct _Ector_Gl_Surface_Data
    } dest_fbo;
 
    struct {
-      int w, h;
-      GLuint fbo;
-      GLuint rbo_color;
-      GLuint rbo_stencil;
+      int       w, h;
+      GLuint    fbo;
+      GLuint    texture;
+      GLuint    rbo_color;
+      GLuint    rbo_stencil;
       Eina_Bool msaa;
-      int msaa_level;
+      Eina_Bool ext_msaa;
+      int       msaa_level;
    } scratch_fbo;
 };
 
index bff877f..7978e84 100644 (file)
@@ -17,6 +17,7 @@ static const char vertex_shader[] =
    "precision mediump float;\n"
    "#endif\n"
    "attribute vec4 vertex;\n"
+   "attribute vec2 tex_coord;\n"
    "uniform mat4 mvp;\n"
    "uniform vec4 pos;\n"
    "void main()\n"
@@ -35,6 +36,33 @@ static const char fragment_shader[] =
    "   gl_FragColor = color;\n"
    "}\n";
 
+static const char tex_vertex_shader[] =
+   "#ifdef GL_ES\n"
+   "precision mediump float;\n"
+   "#endif\n"
+   "attribute vec4 vertex;\n"
+   "attribute vec2 tex_coord;\n"
+   "uniform mat4 mvp;\n"
+   "uniform vec4 pos;\n"
+   "varying vec2 v_tex_coord;\n"
+   "void main()\n"
+   "{\n"
+   "   vec4 new_vert = pos + vertex;\n"
+   "   gl_Position = mvp * new_vert;\n"
+   "   v_tex_coord = tex_coord;\n"
+   "}\n";
+
+static const char tex_fragment_shader[] =
+   "#ifdef GL_ES\n"
+   "precision mediump float;\n"
+   "# endif\n"
+   "varying vec2 v_tex_coord;\n"
+   "uniform sampler2D texture;\n"
+   "void main()\n"
+   "{\n"
+   "   gl_FragColor = texture2D(texture, v_tex_coord);\n"
+   "}\n";
+
 static void
 init_matrix(float matrix[16])
 {
@@ -116,56 +144,65 @@ matrix_ortho(GLfloat *m,
    m[15] = (m[3] * tx) + (m[7] * ty) + orth;
 }
 
-static GLuint
-_init_shader()
+static void
+_destroy_shader_program(Shader_Program *shader)
 {
-   const char *p;
-   unsigned int     program;
-   unsigned int     vtx_shader;
-   unsigned int     fgmt_shader;
+   if (shader)
+     {
+        if (shader->v_shader) GL.glDeleteShader(shader->v_shader);
+        if (shader->f_shader)GL.glDeleteShader(shader->f_shader);
+        if (shader->program) GL.glDeleteProgram(shader->program);
+        free(shader);
+     }
+}
+static Shader_Program *
+_create_shader_program(const char *v_shader, const char* f_shader)
+{
+   Shader_Program *shader = calloc(1, sizeof(Shader_Program));
    GLint ok = 0;
 
-   p = vertex_shader;
-   vtx_shader = GL.glCreateShader(GL_VERTEX_SHADER);
-   GL.glShaderSource(vtx_shader, 1, &p, NULL);
-   GL.glCompileShader(vtx_shader);
-   GL.glGetShaderiv(vtx_shader, GL_COMPILE_STATUS, &ok);
+   shader->v_shader = GL.glCreateShader(GL_VERTEX_SHADER);
+   GL.glShaderSource(shader->v_shader, 1, &v_shader, NULL);
+   GL.glCompileShader(shader->v_shader);
+   GL.glGetShaderiv(shader->v_shader, GL_COMPILE_STATUS, &ok);
    if (!ok)
      {
         ERR("vertex shader compilation failed ");
-        GL.glDeleteShader(vtx_shader);
-        return 0;
+        goto fail;
      }
 
-   p = fragment_shader;
-   fgmt_shader = GL.glCreateShader(GL_FRAGMENT_SHADER);
-   GL.glShaderSource(fgmt_shader, 1, &p, NULL);
-   GL.glCompileShader(fgmt_shader);
-   GL.glGetShaderiv(fgmt_shader, GL_COMPILE_STATUS, &ok);
+   shader->f_shader = GL.glCreateShader(GL_FRAGMENT_SHADER);
+   GL.glShaderSource(shader->f_shader, 1, &f_shader, NULL);
+   GL.glCompileShader(shader->f_shader);
+   GL.glGetShaderiv(shader->f_shader, GL_COMPILE_STATUS, &ok);
    if (!ok)
      {
         ERR("fragment shader compilation failed ");
-        GL.glDeleteShader(fgmt_shader);
-        return 0;
+        goto fail;
      }
 
-   program = GL.glCreateProgram();
-   GL.glAttachShader(program, vtx_shader);
-   GL.glAttachShader(program, fgmt_shader);
-   GL.glBindAttribLocation(program, SHAD_VERTEX, "vertex");
-   GL.glLinkProgram(program);
-   GL.glGetProgramiv(program, GL_LINK_STATUS, &ok);
+   shader->program = GL.glCreateProgram();
+   GL.glAttachShader(shader->program, shader->v_shader);
+   GL.glAttachShader(shader->program, shader->f_shader);
+   GL.glBindAttribLocation(shader->program, SHAD_VERTEX, "vertex");
+   GL.glBindAttribLocation(shader->program, SHAD_TEXUV,  "v_tex_coord");
+   GL.glLinkProgram(shader->program);
+   GL.glGetProgramiv(shader->program, GL_LINK_STATUS, &ok);
    if (!ok)
      {
         ERR("linking failed for shader program");
-        GL.glDeleteShader(vtx_shader);
-        GL.glDeleteShader(fgmt_shader);
-        return 0;
+        goto fail;
      }
-   return program;
+   shader->u_color = GL.glGetUniformLocation(shader->program, "color");
+   shader->u_pos = GL.glGetUniformLocation(shader->program, "pos");
+   shader->u_mvp = GL.glGetUniformLocation(shader->program, "mvp");
+   shader->u_texture = GL.glGetUniformLocation(shader->program, "texture");
+   return shader;
+fail:
+   _destroy_shader_program(shader);
+   return NULL;
 }
 
-
 static Ector_Renderer *
 _ector_gl_surface_ector_generic_surface_renderer_factory_new(Eo *obj,
                                                              Ector_Gl_Surface_Data *pd EINA_UNUSED,
@@ -192,8 +229,7 @@ _ector_gl_surface_path_fill(Eo *obj EINA_UNUSED,
 {
    unsigned int i, previous_stop = 0, stop = 0;
 
-   GL.glUniform4f(pd->uniform_color, (R_VAL(&color)/255.0), (G_VAL(&color)/255.0), (B_VAL(&color)/255.0), (A_VAL(&color)/255.0));
-
+   GL.glUniform4f(pd->simple_shader->u_color, (R_VAL(&color)/255.0), (G_VAL(&color)/255.0), (B_VAL(&color)/255.0), (A_VAL(&color)/255.0));
    GL.glVertexAttribPointer(SHAD_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, vertex);
 
    // 1. Disable color writes
@@ -249,7 +285,7 @@ _ector_gl_surface_path_stroke(Eo *obj EINA_UNUSED,
                             unsigned int vertex_count,
                             unsigned int color)
 {
-   GL.glUniform4f(pd->uniform_color, (R_VAL(&color)/255.0), (G_VAL(&color)/255.0), (B_VAL(&color)/255.0), (A_VAL(&color)/255.0));
+   GL.glUniform4f(pd->simple_shader->u_color, (R_VAL(&color)/255.0), (G_VAL(&color)/255.0), (B_VAL(&color)/255.0), (A_VAL(&color)/255.0));
    GL.glVertexAttribPointer(SHAD_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, vertex);
 
    if (A_VAL(&color) == 255)
@@ -293,38 +329,29 @@ _ector_gl_surface_path_stroke(Eo *obj EINA_UNUSED,
      }
 }
 
-Eina_Bool
-_update_scratch_fbo(Ector_Gl_Surface_Data *pd, int width, int height)
+static void
+_delete_fbo(Ector_Gl_Surface_Data *pd)
 {
-   GLint current_fbo;
-
-   GL.glGetIntegerv(GL_FRAMEBUFFER_BINDING, &current_fbo);
-   // update dest info
-   pd->dest_fbo.fbo = current_fbo;
-   pd->dest_fbo.w = width;
-   pd->dest_fbo.h = height;
-
-   if (!pd->scratch_fbo.msaa) return EINA_TRUE;
-
-   if (pd->scratch_fbo.w >= width && pd->scratch_fbo.h >= height)
-     {
-        // no need to update the scratch buffer
-        GL.glBindFramebuffer(GL_FRAMEBUFFER, pd->scratch_fbo.fbo);
-        return EINA_TRUE;
-     }
-
-   // delete old buffer if any
+   if (!pd->scratch_fbo.fbo) return;
+
+   if (pd->scratch_fbo.rbo_color)
+     GL.glDeleteRenderbuffers(1, &(pd->scratch_fbo.rbo_color));
+   if (pd->scratch_fbo.rbo_stencil)
+     GL.glDeleteRenderbuffers(1, &(pd->scratch_fbo.rbo_stencil));
+   if (pd->scratch_fbo.texture)
+     GL.glDeleteTextures(1, &(pd->scratch_fbo.texture));
    if (pd->scratch_fbo.fbo)
-     {
-        GL.glDeleteRenderbuffers(1, &(pd->scratch_fbo.rbo_color));
-        GL.glDeleteRenderbuffers(1, &(pd->scratch_fbo.rbo_stencil));
-        GL.glDeleteFramebuffers(1, &(pd->scratch_fbo.fbo));
-        pd->scratch_fbo.fbo = 0;
-     }
+     GL.glDeleteFramebuffers(1, &(pd->scratch_fbo.fbo));
 
-   pd->scratch_fbo.w = pd->dest_fbo.w;
-   pd->scratch_fbo.h = pd->dest_fbo.h;
+   pd->scratch_fbo.fbo = 0;
+   pd->scratch_fbo.rbo_color = 0;
+   pd->scratch_fbo.rbo_stencil = 0;
+   pd->scratch_fbo.texture = 0;
+}
 
+static void
+_create_msaa_fbo_rbo(Ector_Gl_Surface_Data *pd)
+{
    GL.glGenRenderbuffers(1, &pd->scratch_fbo.rbo_color);
    GL.glBindRenderbuffer(GL_RENDERBUFFER, pd->scratch_fbo.rbo_color);
    GL.glRenderbufferStorageMultisample(GL_RENDERBUFFER,
@@ -350,7 +377,7 @@ _update_scratch_fbo(Ector_Gl_Surface_Data *pd, int width, int height)
                                 GL_RENDERBUFFER,
                                 pd->scratch_fbo.rbo_color);
 
-   // attach depthbuffer image to FBO
+   // attach stencil buffer to FBO
    GL.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                                 GL_STENCIL_ATTACHMENT,
                                 GL_RENDERBUFFER,
@@ -360,14 +387,151 @@ _update_scratch_fbo(Ector_Gl_Surface_Data *pd, int width, int height)
    GLenum status = GL.glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if(status != GL_FRAMEBUFFER_COMPLETE)
      {
-        ERR("cretaing MSAA fbo failed");
+        ERR("cretaing MSAA fbo rbo failed");
         GL.glDeleteRenderbuffers(1, &(pd->scratch_fbo.rbo_color));
         GL.glDeleteRenderbuffers(1, &(pd->scratch_fbo.rbo_stencil));
         GL.glDeleteFramebuffers(1, &(pd->scratch_fbo.fbo));
         pd->scratch_fbo.fbo = 0;
-        return EINA_FALSE;
      }
+}
+
+static void
+_create_msaa_fbo_texture_ext(Ector_Gl_Surface_Data *pd)
+{
+   GL.glGenTextures(1, &pd->scratch_fbo.texture);
+   GL.glBindTexture(GL_TEXTURE_2D, pd->scratch_fbo.texture);
+   GL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   GL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   GL.glTexImage2D(GL_TEXTURE_2D, 0,
+                   GL_RGBA, pd->scratch_fbo.w, pd->scratch_fbo.h, 0, GL_RGBA,
+                   GL_UNSIGNED_BYTE, NULL);
+   GL.glBindTexture(GL_TEXTURE_2D, 0);
 
+
+   // create a MSAA renderbuffer object for stencil buffer
+   GL.glGenRenderbuffers(1, &pd->scratch_fbo.rbo_stencil);
+   GL.glBindRenderbuffer(GL_RENDERBUFFER, pd->scratch_fbo.rbo_stencil);
+   GL.glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER,
+                                          pd->scratch_fbo.msaa_level,
+                                          GL_STENCIL_INDEX8,
+                                          pd->scratch_fbo.w, pd->scratch_fbo.h);
+
+
+   GL.glGenFramebuffers(1, &pd->scratch_fbo.fbo);
+   GL.glBindFramebuffer(GL_FRAMEBUFFER, pd->scratch_fbo.fbo);
+
+   // attach texture to FBO
+   GL.glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER,
+                                           GL_COLOR_ATTACHMENT0,
+                                           GL_TEXTURE_2D,
+                                           pd->scratch_fbo.texture,
+                                           0,
+                                           pd->scratch_fbo.msaa_level);
+
+   // attach stencil buffer to FBO
+   GL.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+                                GL_STENCIL_ATTACHMENT,
+                                GL_RENDERBUFFER,
+                                pd->scratch_fbo.rbo_stencil);
+
+   // check FBO status
+   GLenum status = GL.glCheckFramebufferStatus(GL_FRAMEBUFFER);
+   if(status != GL_FRAMEBUFFER_COMPLETE)
+     {
+        ERR("cretaing MSAA fbo texture failed");
+        GL.glDeleteTextures(1, &(pd->scratch_fbo.texture));
+        GL.glDeleteRenderbuffers(1, &(pd->scratch_fbo.rbo_stencil));
+        GL.glDeleteFramebuffers(1, &(pd->scratch_fbo.fbo));
+        pd->scratch_fbo.fbo = 0;
+     }
+}
+
+static void
+_create_fbo_texture(Ector_Gl_Surface_Data *pd)
+{
+   GL.glGenTextures(1, &pd->scratch_fbo.texture);
+   GL.glBindTexture(GL_TEXTURE_2D, pd->scratch_fbo.texture);
+   GL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   GL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   GL.glTexImage2D(GL_TEXTURE_2D, 0,
+                   GL_RGBA, pd->scratch_fbo.w, pd->scratch_fbo.h, 0, GL_RGBA,
+                   GL_UNSIGNED_BYTE, NULL);
+   GL.glBindTexture(GL_TEXTURE_2D, 0);
+
+
+   GL.glGenRenderbuffers(1, &pd->scratch_fbo.rbo_stencil);
+   GL.glBindRenderbuffer(GL_RENDERBUFFER, pd->scratch_fbo.rbo_stencil);
+   GL.glRenderbufferStorage(GL_RENDERBUFFER,
+                            GL_STENCIL_INDEX8,
+                            pd->scratch_fbo.w, pd->scratch_fbo.h);
+
+
+   GL.glGenFramebuffers(1, &pd->scratch_fbo.fbo);
+   GL.glBindFramebuffer(GL_FRAMEBUFFER, pd->scratch_fbo.fbo);
+
+   // attach texture to FBO
+   GL.glFramebufferTexture2D(GL_FRAMEBUFFER,
+                             GL_COLOR_ATTACHMENT0,
+                             GL_TEXTURE_2D,
+                             pd->scratch_fbo.texture,
+                             0);
+
+   // attach stencil buffer to FBO
+   GL.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+                                GL_STENCIL_ATTACHMENT,
+                                GL_RENDERBUFFER,
+                                pd->scratch_fbo.rbo_stencil);
+
+   // check FBO status
+   GLenum status = GL.glCheckFramebufferStatus(GL_FRAMEBUFFER);
+   if(status != GL_FRAMEBUFFER_COMPLETE)
+     {
+        ERR("cretaing normal fbo texture failed");
+        GL.glDeleteTextures(1, &(pd->scratch_fbo.texture));
+        GL.glDeleteRenderbuffers(1, &(pd->scratch_fbo.rbo_stencil));
+        GL.glDeleteFramebuffers(1, &(pd->scratch_fbo.fbo));
+        pd->scratch_fbo.fbo = 0;
+     }
+}
+
+
+Eina_Bool
+_update_scratch_fbo(Ector_Gl_Surface_Data *pd, int width, int height)
+{
+   GLint current_fbo;
+
+   GL.glGetIntegerv(GL_FRAMEBUFFER_BINDING, &current_fbo);
+   // update dest info
+   pd->dest_fbo.fbo = current_fbo;
+   pd->dest_fbo.w = width;
+   pd->dest_fbo.h = height;
+
+   if (pd->scratch_fbo.w >= width && pd->scratch_fbo.h >= height)
+     {
+        // no need to update the scratch buffer
+        GL.glBindFramebuffer(GL_FRAMEBUFFER, pd->scratch_fbo.fbo);
+        return EINA_TRUE;
+     }
+
+   // delete old buffer if any
+   _delete_fbo(pd);
+
+   // update the new size
+   pd->scratch_fbo.w = pd->dest_fbo.w > pd->scratch_fbo.w ? pd->dest_fbo.w : pd->scratch_fbo.w;
+   pd->scratch_fbo.h = pd->dest_fbo.h > pd->scratch_fbo.h ? pd->dest_fbo.h : pd->scratch_fbo.h;
+
+   if (pd->scratch_fbo.msaa)
+     {
+        _create_msaa_fbo_rbo(pd);
+     }
+   else if (pd->scratch_fbo.ext_msaa)
+     {
+        _create_msaa_fbo_texture_ext(pd);
+     }
+   else
+     {
+       _create_fbo_texture(pd);
+     }
    return EINA_TRUE;
 }
 
@@ -394,8 +558,8 @@ _ector_gl_surface_surface_set(Eo *obj EINA_UNUSED,
         GL.glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
         init_matrix(mvp);
         matrix_ortho(mvp,0, pd->dest_fbo.w, pd->dest_fbo.h, 0,-1000000.0, 1000000.0,0, pd->dest_fbo.w, pd->dest_fbo.h,1, 1.0);
-        GL.glUseProgram(pd->simple_program);
-        GL.glUniformMatrix4fv(pd->uniform_mvp, 1, GL_FALSE, mvp);
+        GL.glUseProgram(pd->simple_shader->program);
+        GL.glUniformMatrix4fv(pd->simple_shader->u_mvp, 1, GL_FALSE, mvp);
         GL.glEnableVertexAttribArray(SHAD_VERTEX);
      }
    else
@@ -409,6 +573,32 @@ _ector_gl_surface_surface_set(Eo *obj EINA_UNUSED,
                                  GL_COLOR_BUFFER_BIT,
                                  GL_LINEAR);
          }
+       else
+         {
+            float  mvp[16];
+            GL.glBindFramebuffer(GL_FRAMEBUFFER, pd->dest_fbo.fbo);
+            GL.glViewport(0, 0, pd->dest_fbo.w, pd->dest_fbo.h);
+            GL.glClearColor(0, 0, 0, 0);
+            GL.glDisable(GL_BLEND);
+            GL.glClear(GL_COLOR_BUFFER_BIT);
+            init_matrix(mvp);
+            matrix_ortho(mvp,0, pd->dest_fbo.w, pd->dest_fbo.h, 0,-1000000.0, 1000000.0,0, pd->dest_fbo.w, pd->dest_fbo.h,1, 1.0);
+            GL.glUseProgram(pd->texture_shader->program);
+            GL.glUniformMatrix4fv(pd->texture_shader->u_mvp, 1, GL_FALSE, mvp);
+            GL.glUniform4f(pd->texture_shader->u_pos, 0, 0, 0, 0);
+            GL.glEnableVertexAttribArray(SHAD_VERTEX);
+            GL.glEnableVertexAttribArray(SHAD_TEXUV);
+            GL.glActiveTexture(GL_TEXTURE0);
+            GL.glBindTexture(GL_TEXTURE_2D, pd->scratch_fbo.texture);
+            GL.glUniform1i(pd->texture_shader->u_texture, 0);
+            float rect_bound[10] = {0, 0 , pd->dest_fbo.w, 0, pd->dest_fbo.w, pd->dest_fbo.h, 0, pd->dest_fbo.h};
+            float w_r = (float)pd->dest_fbo.w/ pd->scratch_fbo.w;
+            float h_r = (float)pd->dest_fbo.h/ pd->scratch_fbo.h;
+            float tex_uv[10] = {0, 0 , w_r, 0, w_r, h_r, 0, h_r};
+            GL.glVertexAttribPointer(SHAD_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, rect_bound);
+            GL.glVertexAttribPointer(SHAD_TEXUV, 2, GL_FLOAT, GL_FALSE, 0, tex_uv);
+            GL.glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+         }
     }
 }
 
@@ -418,7 +608,7 @@ _ector_gl_surface_offset(Eo *obj EINA_UNUSED,
 {
    pd->offset.x = x;
    pd->offset.y = y;
-   GL.glUniform4f(pd->uniform_pos, pd->ref_point.x + pd->offset.x, pd->ref_point.y + pd->offset.y, 0, 0);
+   GL.glUniform4f(pd->simple_shader->u_pos, pd->ref_point.x + pd->offset.x, pd->ref_point.y + pd->offset.y, 0, 0);
 }
 
 void
@@ -438,11 +628,10 @@ _ector_gl_surface_eo_base_constructor(Eo *obj,
 
    obj = eo_do_super_ret(obj, ECTOR_GL_SURFACE_CLASS, obj, eo_constructor());
 
-   pd->simple_program = _init_shader();
-   pd->uniform_color = GL.glGetUniformLocation(pd->simple_program, "color");
-   pd->uniform_pos = GL.glGetUniformLocation(pd->simple_program, "pos");
-   pd->uniform_mvp = GL.glGetUniformLocation(pd->simple_program, "mvp");
+   GL.finalize();
 
+   pd->simple_shader = _create_shader_program(vertex_shader, fragment_shader);
+   pd->texture_shader = _create_shader_program(tex_vertex_shader, tex_fragment_shader);
    ector_msaa = getenv("ECTOR_MSAA");
    if (ector_msaa)
      {
@@ -453,14 +642,12 @@ _ector_gl_surface_eo_base_constructor(Eo *obj,
      {
         pd->scratch_fbo.msaa_level = 4;
      }
-   if (GL.glFuncExist(GL.glBlitFramebuffer))
-     {
-        pd->scratch_fbo.msaa = EINA_FALSE;
-     }
-   else
-     {
-        pd->scratch_fbo.msaa = EINA_FALSE;
-     }
+
+   if (GL.version == 3)
+     pd->scratch_fbo.msaa = EINA_TRUE;
+   if (GL.ext_ms_render_to_tex)
+     pd->scratch_fbo.ext_msaa = EINA_TRUE;
+
    return obj;
 }
 
@@ -468,17 +655,10 @@ static void
 _ector_gl_surface_eo_base_destructor(Eo *obj EINA_UNUSED,
                                      Ector_Gl_Surface_Data *pd EINA_UNUSED)
 {
-   if (pd->simple_program)
-     {
-        GL.glDeleteProgram(pd->simple_program);
-     }
-   if (pd->scratch_fbo.fbo)
-     {
-        GL.glDeleteRenderbuffers(1, &(pd->scratch_fbo.rbo_color));
-        GL.glDeleteRenderbuffers(1, &(pd->scratch_fbo.rbo_stencil));
-        GL.glDeleteFramebuffers(1, &(pd->scratch_fbo.fbo));
-        pd->scratch_fbo.fbo = 0;
-     }
+  _destroy_shader_program(pd->simple_shader);
+  _destroy_shader_program(pd->texture_shader);
+   _delete_fbo(pd);
+
    eo_do_super(obj, ECTOR_GL_SURFACE_CLASS, eo_destructor());
 }