VIGS: Fixed y-invert problem with texture_from_pixmap
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Fri, 19 Apr 2013 07:34:14 +0000 (11:34 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Fri, 19 Apr 2013 07:34:14 +0000 (11:34 +0400)
X.Org and OpenGL have different position of (0,0) point. X.Org's (0,0) is
at left-top corner and OpenGL's (0,0) is at left-bottom corner. texture_from_pixmap
does not specify where (0,0) is exactly, so Tizen currently treats it as X.Org.
Because of all this we used to map X.Org's (0,0) to OpenGL's (0,0) to avoid y-flipping, but it
turned out that it was wrong. Consider the case when both X.Org and OpenGL render to the pixmap
and then you try to XGetImage, what should VIGS do ? Should it just give away the contents or
should it y-flip it before ? To avoid this confusion we're forced to map X.Org's (0,0) to left-top
corener as it should be and this itself causes problems with Tizen. The only way to resolve this is
to let Tizen know that it should treat texture_from_pixmap's (0,0) as left-bottom corner.
There's an extension called EGL_NOK_texture_from_pixmap which defines EGL_Y_INVERTED_NOK config attribute,
we should implement it, patch Tizen's Evas GL to support it and then everything will work.

hw/vigs_gl_backend.c

index fcedd6c..e199e5e 100644 (file)
@@ -362,7 +362,7 @@ static void vigs_winsys_gl_surface_swap_buffers(struct winsys_gl_surface *sfc)
                                             GL_TEXTURE_2D, vigs_sfc->front_tex, 0);
 
     vigs_sfc->backend->BlitFramebuffer(0, 0, sfc->base.width, sfc->base.height,
-                                       0, sfc->base.height, sfc->base.width, 0,
+                                       0, 0, sfc->base.width, sfc->base.height,
                                        GL_COLOR_BUFFER_BIT,
                                        GL_LINEAR);
 
@@ -386,53 +386,21 @@ static void vigs_winsys_gl_surface_copy_buffers(uint32_t width,
         return;
     }
 
-    if (!vigs_gl_surface_create_framebuffer(vigs_target->parent)) {
-        return;
-    }
-
-    if (!vigs_winsys_gl_surface_create_texture(vigs_target, &vigs_target->front_tex)) {
-        return;
-    }
-
     vigs_gl_surface_wait_fence_2d(vigs_target->parent);
 
     if (is_loop) {
         /*
-         * Feedback loop is possible, need an intermediate texture to
-         * blit.
+         * Feedback loop is possible, no-op.
          */
-
-        if (!vigs_winsys_gl_surface_create_texture(vigs_target, &vigs_target->parent->tmp_tex)) {
+    } else {
+        if (!vigs_gl_surface_create_framebuffer(vigs_target->parent)) {
             return;
         }
 
-        vigs_target->backend->GetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&cur_fb);
-
-        vigs_target->backend->BindFramebuffer(GL_READ_FRAMEBUFFER,
-                                              cur_fb);
-        vigs_target->backend->BindFramebuffer(GL_DRAW_FRAMEBUFFER,
-                                              vigs_target->parent->fb);
-        vigs_target->backend->FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                                   GL_TEXTURE_2D, vigs_target->parent->tmp_tex, 0);
-
-        vigs_target->backend->BlitFramebuffer(0, 0, width, height,
-                                              0, height, width, 0,
-                                              GL_COLOR_BUFFER_BIT,
-                                              GL_LINEAR);
-
-        vigs_target->backend->BindFramebuffer(GL_DRAW_FRAMEBUFFER,
-                                              cur_fb);
-        vigs_target->backend->BindFramebuffer(GL_READ_FRAMEBUFFER,
-                                              vigs_target->parent->fb);
-
-        vigs_target->backend->BlitFramebuffer(0, 0, width, height,
-                                              0, 0, width, height,
-                                              GL_COLOR_BUFFER_BIT,
-                                              GL_LINEAR);
+        if (!vigs_winsys_gl_surface_create_texture(vigs_target, &vigs_target->front_tex)) {
+            return;
+        }
 
-        vigs_target->backend->BindFramebuffer(GL_FRAMEBUFFER,
-                                              cur_fb);
-    } else {
         vigs_target->backend->GetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&cur_fb);
 
         vigs_target->backend->BindFramebuffer(GL_READ_FRAMEBUFFER,
@@ -443,7 +411,7 @@ static void vigs_winsys_gl_surface_copy_buffers(uint32_t width,
                                                    GL_TEXTURE_2D, vigs_target->front_tex, 0);
 
         vigs_target->backend->BlitFramebuffer(0, 0, width, height,
-                                              0, height, width, 0,
+                                              0, 0, width, height,
                                               GL_COLOR_BUFFER_BIT,
                                               GL_LINEAR);
 
@@ -565,7 +533,8 @@ static void vigs_gl_surface_update(struct vigs_surface *sfc,
     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                      GL_TEXTURE_2D, ws_sfc->front_tex, 0);
 
-    gl_backend->RasterPos2f(0.0f, 0.0f);
+    gl_backend->PixelZoom(1.0f, -1.0f);
+    gl_backend->RasterPos2f(0.0f, gl_sfc->base.height);
     gl_backend->DrawPixels(gl_sfc->base.width,
                            gl_sfc->base.height,
                            ws_sfc->tex_format,
@@ -603,6 +572,9 @@ static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc,
     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend;
     struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc;
     struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc);
+    GLfloat sfc_w, sfc_h;
+    GLfloat *vert_coords;
+    GLfloat *tex_coords;
 
     VIGS_LOG_TRACE("x = %u, y = %u, width = %u, height = %u",
                    x, y, width, height);
@@ -624,16 +596,68 @@ static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc,
         goto out;
     }
 
+    if (!vigs_winsys_gl_surface_create_texture(ws_sfc, &gl_sfc->tmp_tex)) {
+        goto out;
+    }
+
     if (!vigs_gl_surface_create_framebuffer(gl_sfc)) {
         goto out;
     }
 
     vigs_gl_surface_wait_fence_3d(gl_sfc);
 
+    vigs_vector_resize(&gl_backend->v1, 0);
+    vigs_vector_resize(&gl_backend->v2, 0);
+
+    sfc_w = gl_sfc->base.width;
+    sfc_h = gl_sfc->base.height;
+
     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_sfc->fb);
 
+    vigs_gl_surface_setup_framebuffer(gl_sfc);
+
+    gl_backend->Enable(GL_TEXTURE_2D);
+
     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                     GL_TEXTURE_2D, ws_sfc->front_tex, 0);
+                                     GL_TEXTURE_2D, gl_sfc->tmp_tex, 0);
+
+    vert_coords = vigs_vector_append(&gl_backend->v1,
+                                     (8 * sizeof(GLfloat)));
+    tex_coords = vigs_vector_append(&gl_backend->v2,
+                                    (8 * sizeof(GLfloat)));
+
+    vert_coords[0] = 0;
+    vert_coords[1] = sfc_h;
+    vert_coords[2] = sfc_w;
+    vert_coords[3] = sfc_h;
+    vert_coords[4] = sfc_w;
+    vert_coords[5] = 0;
+    vert_coords[6] = 0;
+    vert_coords[7] = 0;
+
+    tex_coords[0] = 0;
+    tex_coords[1] = 0;
+    tex_coords[2] = 1;
+    tex_coords[3] = 0;
+    tex_coords[4] = 1;
+    tex_coords[5] = 1;
+    tex_coords[6] = 0;
+    tex_coords[7] = 1;
+
+    gl_backend->EnableClientState(GL_VERTEX_ARRAY);
+    gl_backend->EnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+    gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->front_tex);
+
+    gl_backend->Color4f(1.0f, 1.0f, 1.0f, 1.0f);
+
+    gl_backend->VertexPointer(2, GL_FLOAT, 0, vigs_vector_data(&gl_backend->v1));
+    gl_backend->TexCoordPointer(2, GL_FLOAT, 0, vigs_vector_data(&gl_backend->v2));
+
+    gl_backend->DrawArrays(GL_QUADS, 0, 4);
+
+    gl_backend->DisableClientState(GL_TEXTURE_COORD_ARRAY);
+    gl_backend->DisableClientState(GL_VERTEX_ARRAY);
 
     gl_backend->PixelStorei(GL_PACK_ALIGNMENT, ws_sfc->tex_bpp);
     gl_backend->ReadPixels(x, y, width, height,
@@ -658,6 +682,7 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
     struct vigs_winsys_gl_surface *ws_src = get_ws_sfc(gl_src);
     uint32_t total_entries = num_entries, i;
     GLfloat src_w, src_h;
+    GLfloat dst_h;
     GLfloat *vert_coords;
     GLfloat *tex_coords;
 
@@ -686,6 +711,7 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
 
     src_w = gl_src->base.width;
     src_h = gl_src->base.height;
+    dst_h = gl_dst->base.height;
 
     vigs_gl_surface_wait_fence_3d(gl_src);
     vigs_gl_surface_wait_fence_3d(gl_dst);
@@ -708,8 +734,6 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
         gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                          GL_TEXTURE_2D, gl_dst->tmp_tex, 0);
 
-        gl_backend->Clear(GL_COLOR_BUFFER_BIT);
-
         ++total_entries;
 
         vert_coords = vigs_vector_append(&gl_backend->v1,
@@ -718,22 +742,22 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
                                         (8 * sizeof(GLfloat)));
 
         vert_coords[0] = 0;
-        vert_coords[1] = 0;
+        vert_coords[1] = src_h;
         vert_coords[2] = src_w;
-        vert_coords[3] = 0;
+        vert_coords[3] = src_h;
         vert_coords[4] = src_w;
-        vert_coords[5] = src_h;
+        vert_coords[5] = 0;
         vert_coords[6] = 0;
-        vert_coords[7] = src_h;
+        vert_coords[7] = 0;
 
         tex_coords[0] = 0;
-        tex_coords[1] = 0;
+        tex_coords[1] = 1;
         tex_coords[2] = 1;
-        tex_coords[3] = 0;
+        tex_coords[3] = 1;
         tex_coords[4] = 1;
-        tex_coords[5] = 1;
+        tex_coords[5] = 0;
         tex_coords[6] = 0;
-        tex_coords[7] = 1;
+        tex_coords[7] = 0;
     } else {
         /*
          * No feedback loop possible, render to 'front_tex'.
@@ -751,22 +775,22 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
                                         (8 * sizeof(GLfloat)));
 
         vert_coords[0] = entries[i].to.x;
-        vert_coords[1] = entries[i].to.y;
+        vert_coords[1] = dst_h - entries[i].to.y;
         vert_coords[2] = entries[i].to.x + entries[i].size.w;
-        vert_coords[3] = entries[i].to.y;
+        vert_coords[3] = dst_h - entries[i].to.y;
         vert_coords[4] = entries[i].to.x + entries[i].size.w;
-        vert_coords[5] = (entries[i].to.y + entries[i].size.h);
+        vert_coords[5] = dst_h - (entries[i].to.y + entries[i].size.h);
         vert_coords[6] = entries[i].to.x;
-        vert_coords[7] = (entries[i].to.y + entries[i].size.h);
+        vert_coords[7] = dst_h - (entries[i].to.y + entries[i].size.h);
 
         tex_coords[0] = (GLfloat)entries[i].from.x / src_w;
-        tex_coords[1] = (GLfloat)(entries[i].from.y) / src_h;
+        tex_coords[1] = (GLfloat)(src_h - entries[i].from.y) / src_h;
         tex_coords[2] = (GLfloat)(entries[i].from.x + entries[i].size.w) / src_w;
-        tex_coords[3] = (GLfloat)(entries[i].from.y) / src_h;
+        tex_coords[3] = (GLfloat)(src_h - entries[i].from.y) / src_h;
         tex_coords[4] = (GLfloat)(entries[i].from.x + entries[i].size.w) / src_w;
-        tex_coords[5] = (GLfloat)(entries[i].from.y + entries[i].size.h) / src_h;
+        tex_coords[5] = (GLfloat)(src_h - (entries[i].from.y + entries[i].size.h)) / src_h;
         tex_coords[6] = (GLfloat)entries[i].from.x / src_w;
-        tex_coords[7] = (GLfloat)(entries[i].from.y + entries[i].size.h) / src_h;
+        tex_coords[7] = (GLfloat)(src_h - (entries[i].from.y + entries[i].size.h)) / src_h;
     }
 
     gl_backend->EnableClientState(GL_VERTEX_ARRAY);
@@ -791,22 +815,22 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
                                         (8 * sizeof(GLfloat)));
 
         vert_coords[0] = 0;
-        vert_coords[1] = 0;
+        vert_coords[1] = src_h;
         vert_coords[2] = src_w;
-        vert_coords[3] = 0;
+        vert_coords[3] = src_h;
         vert_coords[4] = src_w;
-        vert_coords[5] = src_h;
+        vert_coords[5] = 0;
         vert_coords[6] = 0;
-        vert_coords[7] = src_h;
+        vert_coords[7] = 0;
 
         tex_coords[0] = 0;
-        tex_coords[1] = 0;
+        tex_coords[1] = 1;
         tex_coords[2] = 1;
-        tex_coords[3] = 0;
+        tex_coords[3] = 1;
         tex_coords[4] = 1;
-        tex_coords[5] = 1;
+        tex_coords[5] = 0;
         tex_coords[6] = 0;
-        tex_coords[7] = 1;
+        tex_coords[7] = 0;
 
         gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                          GL_TEXTURE_2D, ws_dst->front_tex, 0);
@@ -844,6 +868,7 @@ static void vigs_gl_surface_solid_fill(struct vigs_surface *sfc,
     struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc);
     uint32_t i;
     GLubyte red, green, blue, alpha;
+    GLfloat sfc_h;
 
     if (!gl_backend->make_current(gl_backend, true)) {
         return;
@@ -857,6 +882,8 @@ static void vigs_gl_surface_solid_fill(struct vigs_surface *sfc,
         goto out;
     }
 
+    sfc_h = gl_sfc->base.height;
+
     vigs_gl_surface_wait_fence_3d(gl_sfc);
 
     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_sfc->fb);
@@ -875,13 +902,13 @@ static void vigs_gl_surface_solid_fill(struct vigs_surface *sfc,
                                                   (8 * sizeof(GLfloat)));
 
         vert_coords[0] = entries[i].pos.x;
-        vert_coords[1] = entries[i].pos.y;
+        vert_coords[1] = sfc_h - entries[i].pos.y;
         vert_coords[2] = entries[i].pos.x + entries[i].size.w;
-        vert_coords[3] = entries[i].pos.y;
+        vert_coords[3] = sfc_h - entries[i].pos.y;
         vert_coords[4] = entries[i].pos.x + entries[i].size.w;
-        vert_coords[5] = entries[i].pos.y + entries[i].size.h;
+        vert_coords[5] = sfc_h - (entries[i].pos.y + entries[i].size.h);
         vert_coords[6] = entries[i].pos.x;
-        vert_coords[7] = entries[i].pos.y + entries[i].size.h;
+        vert_coords[7] = sfc_h - (entries[i].pos.y + entries[i].size.h);
     }
 
     gl_backend->EnableClientState(GL_VERTEX_ARRAY);
@@ -948,7 +975,8 @@ static void vigs_gl_surface_put_image(struct vigs_surface *sfc,
     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                      GL_TEXTURE_2D, ws_sfc->front_tex, 0);
 
-    gl_backend->RasterPos2f(rect->pos.x, rect->pos.y);
+    gl_backend->PixelZoom(1.0f, -1.0f);
+    gl_backend->RasterPos2f(rect->pos.x, gl_sfc->base.height - rect->pos.y);
     gl_backend->DrawPixels(rect->size.w,
                            rect->size.h,
                            ws_sfc->tex_format,